|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright (C) 2001, 2002, 2004, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
|
|
Packit |
fd8b60 |
* All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Export of this software from the United States of America may require
|
|
Packit |
fd8b60 |
* a specific license from the United States Government. It is the
|
|
Packit |
fd8b60 |
* responsibility of any person or organization contemplating export to
|
|
Packit |
fd8b60 |
* obtain such a license before exporting.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
|
Packit |
fd8b60 |
* distribute this software and its documentation for any purpose and
|
|
Packit |
fd8b60 |
* without fee is hereby granted, provided that the above copyright
|
|
Packit |
fd8b60 |
* notice appear in all copies and that both that copyright notice and
|
|
Packit |
fd8b60 |
* this permission notice appear in supporting documentation, and that
|
|
Packit |
fd8b60 |
* the name of M.I.T. not be used in advertising or publicity pertaining
|
|
Packit |
fd8b60 |
* to distribution of the software without specific, written prior
|
|
Packit |
fd8b60 |
* permission. Furthermore if you modify this software you must label
|
|
Packit |
fd8b60 |
* your software as modified software and not distribute it in such a
|
|
Packit |
fd8b60 |
* fashion that it might be confused with the original M.I.T. software.
|
|
Packit |
fd8b60 |
* M.I.T. makes no representations about the suitability of
|
|
Packit |
fd8b60 |
* this software for any purpose. It is provided "as is" without express
|
|
Packit |
fd8b60 |
* or implied warranty.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "crypto_int.h"
|
|
Packit |
fd8b60 |
|
|
rpm-build |
3d32d0 |
#include <openssl/rand.h>
|
|
rpm-build |
3d32d0 |
|
|
Packit |
fd8b60 |
krb5_error_code KRB5_CALLCONV
|
|
Packit |
fd8b60 |
krb5_c_random_seed(krb5_context context, krb5_data *data)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_OLDAPI, data);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Routines to get entropy from the OS. */
|
|
Packit |
fd8b60 |
#if defined(_WIN32)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_boolean
|
|
Packit |
fd8b60 |
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_boolean result;
|
|
Packit |
fd8b60 |
HCRYPTPROV provider;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* CryptGenRandom is always considered strong. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
|
|
Packit |
fd8b60 |
CRYPT_VERIFYCONTEXT))
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
result = CryptGenRandom(provider, len, buf);
|
|
Packit |
fd8b60 |
(void)CryptReleaseContext(provider, 0);
|
|
Packit |
fd8b60 |
return result;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#else /* not Windows */
|
|
Packit |
fd8b60 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
fd8b60 |
#include <unistd.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef HAVE_SYS_STAT_H
|
|
Packit |
fd8b60 |
#include <sys/stat.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef __linux__
|
|
Packit |
fd8b60 |
#include <sys/syscall.h>
|
|
Packit |
fd8b60 |
#endif /* __linux__ */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Open device, ensure that it is not a regular file, and read entropy. Return
|
|
Packit |
fd8b60 |
* true on success, false on failure. */
|
|
Packit |
fd8b60 |
static krb5_boolean
|
|
Packit |
fd8b60 |
read_entropy_from_device(const char *device, unsigned char *buf, size_t len)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct stat sb;
|
|
Packit |
fd8b60 |
int fd;
|
|
Packit |
fd8b60 |
unsigned char *bp;
|
|
Packit |
fd8b60 |
size_t left;
|
|
Packit |
fd8b60 |
ssize_t count;
|
|
Packit |
fd8b60 |
krb5_boolean result = FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
fd = open(device, O_RDONLY);
|
|
Packit |
fd8b60 |
if (fd == -1)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
set_cloexec_fd(fd);
|
|
Packit |
fd8b60 |
if (fstat(fd, &sb) == -1 || S_ISREG(sb.st_mode))
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (bp = buf, left = len; left > 0;) {
|
|
Packit |
fd8b60 |
count = read(fd, bp, left);
|
|
Packit |
fd8b60 |
if (count <= 0)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
left -= count;
|
|
Packit |
fd8b60 |
bp += count;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
result = TRUE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cleanup:
|
|
Packit |
fd8b60 |
close(fd);
|
|
Packit |
fd8b60 |
return result;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_boolean
|
|
Packit |
fd8b60 |
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const char *device;
|
|
Packit |
fd8b60 |
int r;
|
|
Packit |
fd8b60 |
|
|
rpm-build |
3d32d0 |
/* A wild FIPS mode appeared! */
|
|
rpm-build |
3d32d0 |
if (FIPS_mode()) {
|
|
rpm-build |
3d32d0 |
/* The return codes on this API are not good */
|
|
rpm-build |
3d32d0 |
r = RAND_bytes(buf, len);
|
|
rpm-build |
3d32d0 |
return r == 1;
|
|
rpm-build |
3d32d0 |
}
|
|
rpm-build |
3d32d0 |
|
|
rpm-build |
3d32d0 |
#if defined(__linux__) && defined(SYS_getrandom)
|
|
Packit |
fd8b60 |
while (len > 0) {
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Pull from the /dev/urandom pool, but require it to have been seeded.
|
|
Packit |
fd8b60 |
* This ensures strong randomness while only blocking during first
|
|
Packit |
fd8b60 |
* system boot.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* glibc does not currently provide a binding for getrandom:
|
|
Packit |
fd8b60 |
* https://sourceware.org/bugzilla/show_bug.cgi?id=17252
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
errno = 0;
|
|
Packit |
fd8b60 |
r = syscall(SYS_getrandom, buf, len, 0);
|
|
Packit |
fd8b60 |
if (r <= 0) {
|
|
Packit |
fd8b60 |
if (errno == EINTR)
|
|
Packit |
fd8b60 |
continue;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* ENOSYS or other unrecoverable failure */
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
len -= r;
|
|
Packit |
fd8b60 |
buf += r;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (len == 0)
|
|
Packit |
fd8b60 |
return TRUE;
|
|
Packit |
fd8b60 |
#endif /* defined(__linux__) && defined(SYS_getrandom) */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
device = strong ? "/dev/random" : "/dev/urandom";
|
|
Packit |
fd8b60 |
return read_entropy_from_device(device, buf, len);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#endif /* not Windows */
|