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