1 /*
2  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <errno.h>
27 #include <ipxe/entropy.h>
28 #include <ipxe/crc32.h>
29 #include <ipxe/profile.h>
30 #include <ipxe/efi/efi.h>
31 #include <ipxe/efi/Protocol/Rng.h>
32 
33 /** @file
34  *
35  * EFI entropy source
36  *
37  */
38 
39 /** Random number generator protocol */
40 static EFI_RNG_PROTOCOL *efirng;
41 EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
42 
43 /** Minimum number of bytes to request from RNG
44  *
45  * The UEFI spec states (for no apparently good reason) that "When a
46  * Deterministic Random Bit Generator (DRBG) is used on the output of
47  * a (raw) entropy source, its security level must be at least 256
48  * bits."  The EDK2 codebase (mis)interprets this to mean that the
49  * call to GetRNG() should fail if given a buffer less than 32 bytes.
50  *
51  * Incidentally, nothing in the EFI RNG protocol provides any way to
52  * report the actual amount of entropy returned by GetRNG().
53  */
54 #define EFI_ENTROPY_RNG_LEN 32
55 
56 /** Time (in 100ns units) to delay waiting for timer tick
57  *
58  * In theory, UEFI allows us to specify a trigger time of zero to
59  * simply wait for the next timer tick.  In practice, specifying zero
60  * seems to often return immediately, which produces almost no
61  * entropy.  Specify a delay of 1000ns to try to force an existent
62  * delay.
63  */
64 #define EFI_ENTROPY_TRIGGER_TIME 10
65 
66 /** Event used to wait for timer tick */
67 static EFI_EVENT tick;
68 
69 /**
70  * Enable entropy gathering
71  *
72  * @ret rc		Return status code
73  */
efi_entropy_enable(void)74 static int efi_entropy_enable ( void ) {
75 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
76 	EFI_STATUS efirc;
77 	int rc;
78 
79 	DBGC ( &tick, "ENTROPY %s RNG protocol\n",
80 	       ( efirng ? "has" : "has no" ) );
81 
82 	/* Drop to TPL_APPLICATION to allow timer tick event to take place */
83 	bs->RestoreTPL ( TPL_APPLICATION );
84 
85 	/* Create timer tick event */
86 	if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL,
87 					 &tick ) ) != 0 ) {
88 		rc = -EEFI ( efirc );
89 		DBGC ( &tick, "ENTROPY could not create event: %s\n",
90 		       strerror ( rc ) );
91 		return rc;
92 	}
93 
94 	return 0;
95 }
96 
97 /**
98  * Disable entropy gathering
99  *
100  */
efi_entropy_disable(void)101 static void efi_entropy_disable ( void ) {
102 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
103 
104 	/* Close timer tick event */
105 	bs->CloseEvent ( tick );
106 
107 	/* Return to TPL_CALLBACK */
108 	bs->RaiseTPL ( TPL_CALLBACK );
109 }
110 
111 /**
112  * Wait for a timer tick
113  *
114  * @ret low		CPU profiling low-order bits, or negative error
115  */
efi_entropy_tick(void)116 static int efi_entropy_tick ( void ) {
117 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
118 	UINTN index;
119 	uint16_t low;
120 	EFI_STATUS efirc;
121 	int rc;
122 
123 	/* Wait for next timer tick */
124 	if ( ( efirc = bs->SetTimer ( tick, TimerRelative,
125 				      EFI_ENTROPY_TRIGGER_TIME ) ) != 0 ) {
126 		rc = -EEFI ( efirc );
127 		DBGC ( &tick, "ENTROPY could not set timer: %s\n",
128 		       strerror ( rc ) );
129 		return rc;
130 	}
131 	if ( ( efirc = bs->WaitForEvent ( 1, &tick, &index ) ) != 0 ) {
132 		rc = -EEFI ( efirc );
133 		DBGC ( &tick, "ENTROPY could not wait for timer tick: %s\n",
134 		       strerror ( rc ) );
135 		return rc;
136 	}
137 
138 	/* Get current CPU profiling timestamp low-order bits */
139 	low = profile_timestamp();
140 
141 	return low;
142 }
143 
144 /**
145  * Get noise sample from timer ticks
146  *
147  * @ret noise		Noise sample
148  * @ret rc		Return status code
149  */
efi_get_noise_ticks(noise_sample_t * noise)150 static int efi_get_noise_ticks ( noise_sample_t *noise ) {
151 	int before;
152 	int after;
153 	int rc;
154 
155 	/* Wait for a timer tick */
156 	before = efi_entropy_tick();
157 	if ( before < 0 ) {
158 		rc = before;
159 		return rc;
160 	}
161 
162 	/* Wait for another timer tick */
163 	after = efi_entropy_tick();
164 	if ( after < 0 ) {
165 		rc = after;
166 		return rc;
167 	}
168 
169 	/* Use TSC delta as noise sample */
170 	*noise = ( after - before );
171 
172 	return 0;
173 }
174 
175 /**
176  * Get noise sample from RNG protocol
177  *
178  * @ret noise		Noise sample
179  * @ret rc		Return status code
180  */
efi_get_noise_rng(noise_sample_t * noise)181 static int efi_get_noise_rng ( noise_sample_t *noise ) {
182 	static uint8_t prev[EFI_ENTROPY_RNG_LEN];
183 	uint8_t buf[EFI_ENTROPY_RNG_LEN];
184 	EFI_STATUS efirc;
185 	int rc;
186 
187 	/* Fail if we have no EFI RNG protocol */
188 	if ( ! efirng )
189 		return -ENOTSUP;
190 
191 	/* Get the minimum allowed number of random bytes */
192 	if ( ( efirc = efirng->GetRNG ( efirng, NULL, EFI_ENTROPY_RNG_LEN,
193 					buf ) ) != 0 ) {
194 		rc = -EEFI ( efirc );
195 		DBGC ( &tick, "ENTROPY could not read from RNG: %s\n",
196 		       strerror ( rc ) );
197 		return rc;
198 	}
199 
200 	/* Fail (and permanently disable the EFI RNG) if we get
201 	 * consecutive identical results.
202 	 */
203 	if ( memcmp ( buf, prev, sizeof ( buf ) ) == 0 ) {
204 		DBGC ( &tick, "ENTROPY detected broken EFI RNG:\n" );
205 		DBGC_HDA ( &tick, 0, buf, sizeof ( buf ) );
206 		efirng = NULL;
207 		return -EIO;
208 	}
209 	memcpy ( prev, buf, sizeof ( prev ) );
210 
211 	/* Reduce random bytes to a single noise sample.  This seems
212 	 * like overkill, but we have no way of knowing how much
213 	 * entropy is actually present in the bytes returned by the
214 	 * RNG protocol.
215 	 */
216 	*noise = crc32_le ( 0, buf, sizeof ( buf ) );
217 
218 	return 0;
219 }
220 
221 /**
222  * Get noise sample
223  *
224  * @ret noise		Noise sample
225  * @ret rc		Return status code
226  */
efi_get_noise(noise_sample_t * noise)227 static int efi_get_noise ( noise_sample_t *noise ) {
228 	int rc;
229 
230 	/* Try RNG first, falling back to timer ticks */
231 	if ( ( ( rc = efi_get_noise_rng ( noise ) ) != 0 ) &&
232 	     ( ( rc = efi_get_noise_ticks ( noise ) ) != 0 ) )
233 		return rc;
234 
235 	return 0;
236 }
237 
238 PROVIDE_ENTROPY_INLINE ( efi, min_entropy_per_sample );
239 PROVIDE_ENTROPY ( efi, entropy_enable, efi_entropy_enable );
240 PROVIDE_ENTROPY ( efi, entropy_disable, efi_entropy_disable );
241 PROVIDE_ENTROPY ( efi, get_noise, efi_get_noise );
242