/src/libgcrypt/random/rndgetentropy.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* rndgetentropy.c - raw random number for OSes by getentropy function. |
2 | | * Copyright (C) 1998, 2001, 2002, 2003, 2007, |
3 | | * 2009 Free Software Foundation, Inc. |
4 | | * |
5 | | * This file is part of Libgcrypt. |
6 | | * |
7 | | * Libgcrypt is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation; either version 2.1 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * Libgcrypt is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | |
22 | | #include <config.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <errno.h> |
26 | | #include <sys/types.h> |
27 | | #include <string.h> |
28 | | #include <unistd.h> |
29 | | #ifdef HAVE_SYS_RANDOM_H |
30 | | #include <sys/random.h> |
31 | | #endif |
32 | | |
33 | | #include "types.h" |
34 | | #include "g10lib.h" |
35 | | #include "rand-internal.h" |
36 | | |
37 | | /* The function returns 0 on success or true on failure (in which case |
38 | | * the caller will signal a fatal error). */ |
39 | | int |
40 | | _gcry_rndgetentropy_gather_random (void (*add)(const void*, size_t, |
41 | | enum random_origins), |
42 | | enum random_origins origin, |
43 | | size_t length, int level) |
44 | 75 | { |
45 | 75 | byte buffer[256]; |
46 | | |
47 | 75 | if (!add) |
48 | 0 | { |
49 | | /* Special mode to release resouces. */ |
50 | 0 | _gcry_rndjent_fini (); |
51 | 0 | return 0; |
52 | 0 | } |
53 | | |
54 | | /* When using a blocking random generator try to get some entropy |
55 | | * from the jitter based RNG. In this case we take up to 50% of the |
56 | | * remaining requested bytes. */ |
57 | 75 | if (level >= GCRY_VERY_STRONG_RANDOM) |
58 | 0 | { |
59 | 0 | size_t n; |
60 | |
|
61 | 0 | n = _gcry_rndjent_poll (add, origin, length/2); |
62 | 0 | if (n > length/2) |
63 | 0 | n = length/2; |
64 | 0 | if (length > 1) |
65 | 0 | length -= n; |
66 | 0 | } |
67 | | |
68 | | /* Enter the loop. */ |
69 | 150 | while (length) |
70 | 75 | { |
71 | 75 | int ret; |
72 | 75 | size_t nbytes; |
73 | | |
74 | | /* For a modern operating system, we use the new getentropy |
75 | | * function. That call guarantees that the kernel's RNG has |
76 | | * been properly seeded before returning any data. This is |
77 | | * different from /dev/urandom which may, due to its |
78 | | * non-blocking semantics, return data even if the kernel has |
79 | | * not been properly seeded. And it differs from /dev/random by |
80 | | * never blocking once the kernel is seeded. */ |
81 | 75 | do |
82 | 75 | { |
83 | 75 | _gcry_pre_syscall (); |
84 | 75 | if (fips_mode ()) |
85 | 0 | { |
86 | | /* DRBG chaining defined in SP 800-90A (rev 1) specify |
87 | | * the upstream (kernel) DRBG needs to be reseeded for |
88 | | * initialization of downstream (libgcrypt) DRBG. For this |
89 | | * in RHEL, we repurposed the GRND_RANDOM flag of getrandom API. |
90 | | * The libgcrypt DRBG is initialized with 48B of entropy, but |
91 | | * the kernel can provide only 32B at a time after reseeding |
92 | | * so we need to limit our requests to 32B here. |
93 | | * This is clarified in IG 7.19 / IG D.K. for FIPS 140-2 / 3 |
94 | | * and might not be applicable on other FIPS modules not running |
95 | | * RHEL kernel. |
96 | | */ |
97 | 0 | nbytes = length < 32 ? length : 32; |
98 | 0 | ret = getrandom (buffer, nbytes, GRND_RANDOM); |
99 | 0 | } |
100 | 75 | else |
101 | 75 | { |
102 | 75 | nbytes = length < sizeof (buffer) ? length : sizeof (buffer); |
103 | 75 | ret = getentropy (buffer, nbytes); |
104 | 75 | } |
105 | 75 | _gcry_post_syscall (); |
106 | 75 | } |
107 | 75 | while (ret == -1 && errno == EINTR); |
108 | | |
109 | 75 | if (ret == -1 && errno == ENOSYS) |
110 | 0 | log_fatal ("getentropy is not supported: %s\n", strerror (errno)); |
111 | 75 | else |
112 | 75 | { /* getentropy is supported. Some sanity checks. */ |
113 | 75 | if (ret == -1) |
114 | 0 | log_fatal ("unexpected error from getentropy: %s\n", |
115 | 0 | strerror (errno)); |
116 | | |
117 | 75 | (*add) (buffer, nbytes, origin); |
118 | 75 | length -= nbytes; |
119 | 75 | } |
120 | 75 | } |
121 | 75 | wipememory (buffer, sizeof buffer); |
122 | | |
123 | 75 | return 0; /* success */ |
124 | 75 | } |