1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright (C) 2001, 2002, 2004, 2007, 2008, 2010 by the Massachusetts Institute of Technology. 4 * All rights reserved. 5 * 6 * 7 * Export of this software from the United States of America may require 8 * a specific license from the United States Government. It is the 9 * responsibility of any person or organization contemplating export to 10 * obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include "crypto_int.h" 28 29 krb5_error_code KRB5_CALLCONV 30 krb5_c_random_seed(krb5_context context, krb5_data *data) 31 { 32 return krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_OLDAPI, data); 33 } 34 35 /* Routines to get entropy from the OS. */ 36 #if defined(_WIN32) 37 38 static krb5_boolean 39 get_os_entropy(unsigned char *buf, size_t len) 40 { 41 krb5_boolean result; 42 HCRYPTPROV provider; 43 44 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, 45 CRYPT_VERIFYCONTEXT)) 46 return FALSE; 47 result = CryptGenRandom(provider, len, buf); 48 (void)CryptReleaseContext(provider, 0); 49 return result; 50 } 51 52 #else /* not Windows */ 53 #ifdef HAVE_UNISTD_H 54 #include <unistd.h> 55 #endif 56 #ifdef HAVE_SYS_STAT_H 57 #include <sys/stat.h> 58 #endif 59 #ifdef __linux__ 60 #include <sys/syscall.h> 61 #endif /* __linux__ */ 62 63 /* Open device, ensure that it is not a regular file, and read entropy. Return 64 * true on success, false on failure. */ 65 static krb5_boolean 66 read_entropy_from_device(const char *device, unsigned char *buf, size_t len) 67 { 68 struct stat sb; 69 int fd; 70 unsigned char *bp; 71 size_t left; 72 ssize_t count; 73 krb5_boolean result = FALSE; 74 75 fd = open(device, O_RDONLY); 76 if (fd == -1) 77 return FALSE; 78 set_cloexec_fd(fd); 79 if (fstat(fd, &sb) == -1 || S_ISREG(sb.st_mode)) 80 goto cleanup; 81 82 for (bp = buf, left = len; left > 0;) { 83 count = read(fd, bp, left); 84 if (count <= 0) 85 goto cleanup; 86 left -= count; 87 bp += count; 88 } 89 result = TRUE; 90 91 cleanup: 92 close(fd); 93 return result; 94 } 95 96 static krb5_boolean 97 get_os_entropy(unsigned char *buf, size_t len) 98 { 99 #if defined(__linux__) && defined(SYS_getrandom) 100 int r; 101 102 while (len > 0) { 103 /* 104 * Pull from the /dev/urandom pool, but require it to have been seeded. 105 * This ensures strong randomness while only blocking during first 106 * system boot. 107 * 108 * glibc does not currently provide a binding for getrandom: 109 * https://sourceware.org/bugzilla/show_bug.cgi?id=17252 110 */ 111 errno = 0; 112 r = syscall(SYS_getrandom, buf, len, 0); 113 if (r <= 0) { 114 if (errno == EINTR) 115 continue; 116 117 /* ENOSYS or other unrecoverable failure */ 118 break; 119 } 120 len -= r; 121 buf += r; 122 } 123 if (len == 0) 124 return TRUE; 125 #endif /* defined(__linux__) && defined(SYS_getrandom) */ 126 127 return read_entropy_from_device("/dev/urandom", buf, len); 128 } 129 130 #endif /* not Windows */ 131 132 krb5_error_code KRB5_CALLCONV 133 krb5_c_random_make_octets(krb5_context context, krb5_data *outdata) 134 { 135 krb5_boolean res; 136 137 res = get_os_entropy((uint8_t *)outdata->data, outdata->length); 138 return res ? 0 : KRB5_CRYPTO_INTERNAL; 139 } 140 141 krb5_error_code KRB5_CALLCONV 142 krb5_c_random_add_entropy(krb5_context context, unsigned int randsource, 143 const krb5_data *indata) 144 { 145 return 0; 146 } 147 148 krb5_error_code KRB5_CALLCONV 149 krb5_c_random_os_entropy(krb5_context context, int strong, int *success) 150 { 151 *success = 0; 152 return 0; 153 } 154