1 /** @file
2 Diffie-Hellman Wrapper Implementation over OpenSSL.
3
4 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "InternalCryptLib.h"
16 #include <openssl/bn.h>
17 #include <openssl/dh.h>
18
19
20 /**
21 Allocates and Initializes one Diffie-Hellman Context for subsequent use.
22
23 @return Pointer to the Diffie-Hellman Context that has been initialized.
24 If the allocations fails, DhNew() returns NULL.
25
26 **/
27 VOID *
28 EFIAPI
DhNew(VOID)29 DhNew (
30 VOID
31 )
32 {
33 //
34 // Allocates & Initializes DH Context by OpenSSL DH_new()
35 //
36 return (VOID *) DH_new ();
37 }
38
39 /**
40 Release the specified DH context.
41
42 If DhContext is NULL, then return FALSE.
43
44 @param[in] DhContext Pointer to the DH context to be released.
45
46 **/
47 VOID
48 EFIAPI
DhFree(IN VOID * DhContext)49 DhFree (
50 IN VOID *DhContext
51 )
52 {
53 //
54 // Free OpenSSL DH Context
55 //
56 DH_free ((DH *) DhContext);
57 }
58
59 /**
60 Generates DH parameter.
61
62 Given generator g, and length of prime number p in bits, this function generates p,
63 and sets DH context according to value of g and p.
64
65 Before this function can be invoked, pseudorandom number generator must be correctly
66 initialized by RandomSeed().
67
68 If DhContext is NULL, then return FALSE.
69 If Prime is NULL, then return FALSE.
70
71 @param[in, out] DhContext Pointer to the DH context.
72 @param[in] Generator Value of generator.
73 @param[in] PrimeLength Length in bits of prime to be generated.
74 @param[out] Prime Pointer to the buffer to receive the generated prime number.
75
76 @retval TRUE DH parameter generation succeeded.
77 @retval FALSE Value of Generator is not supported.
78 @retval FALSE PRNG fails to generate random prime number with PrimeLength.
79
80 **/
81 BOOLEAN
82 EFIAPI
DhGenerateParameter(IN OUT VOID * DhContext,IN UINTN Generator,IN UINTN PrimeLength,OUT UINT8 * Prime)83 DhGenerateParameter (
84 IN OUT VOID *DhContext,
85 IN UINTN Generator,
86 IN UINTN PrimeLength,
87 OUT UINT8 *Prime
88 )
89 {
90 BOOLEAN RetVal;
91
92 //
93 // Check input parameters.
94 //
95 if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
96 return FALSE;
97 }
98
99 if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) {
100 return FALSE;
101 }
102
103 RetVal = (BOOLEAN) DH_generate_parameters_ex (DhContext, (UINT32) PrimeLength, (UINT32) Generator, NULL);
104 if (!RetVal) {
105 return FALSE;
106 }
107
108 BN_bn2bin (((DH *) DhContext)->p, Prime);
109
110 return TRUE;
111 }
112
113 /**
114 Sets generator and prime parameters for DH.
115
116 Given generator g, and prime number p, this function and sets DH
117 context accordingly.
118
119 If DhContext is NULL, then return FALSE.
120 If Prime is NULL, then return FALSE.
121
122 @param[in, out] DhContext Pointer to the DH context.
123 @param[in] Generator Value of generator.
124 @param[in] PrimeLength Length in bits of prime to be generated.
125 @param[in] Prime Pointer to the prime number.
126
127 @retval TRUE DH parameter setting succeeded.
128 @retval FALSE Value of Generator is not supported.
129 @retval FALSE Value of Generator is not suitable for the Prime.
130 @retval FALSE Value of Prime is not a prime number.
131 @retval FALSE Value of Prime is not a safe prime number.
132
133 **/
134 BOOLEAN
135 EFIAPI
DhSetParameter(IN OUT VOID * DhContext,IN UINTN Generator,IN UINTN PrimeLength,IN CONST UINT8 * Prime)136 DhSetParameter (
137 IN OUT VOID *DhContext,
138 IN UINTN Generator,
139 IN UINTN PrimeLength,
140 IN CONST UINT8 *Prime
141 )
142 {
143 DH *Dh;
144 BIGNUM *Bn;
145
146 //
147 // Check input parameters.
148 //
149 if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
150 return FALSE;
151 }
152
153 if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) {
154 return FALSE;
155 }
156
157 Bn = NULL;
158
159 Dh = (DH *) DhContext;
160 Dh->g = NULL;
161 Dh->p = BN_new ();
162 if (Dh->p == NULL) {
163 goto Error;
164 }
165
166 Dh->g = BN_new ();
167 if (Dh->g == NULL) {
168 goto Error;
169 }
170
171 Bn = BN_bin2bn (Prime, (UINT32) (PrimeLength / 8), Dh->p);
172 if (Bn == NULL) {
173 goto Error;
174 }
175
176 if (BN_set_word (Dh->g, (UINT32) Generator) == 0) {
177 goto Error;
178 }
179
180 return TRUE;
181
182 Error:
183
184 if (Dh->p != NULL) {
185 BN_free (Dh->p);
186 }
187
188 if (Dh->g != NULL) {
189 BN_free (Dh->g);
190 }
191
192 if (Bn != NULL) {
193 BN_free (Bn);
194 }
195
196 return FALSE;
197 }
198
199 /**
200 Generates DH public key.
201
202 This function generates random secret exponent, and computes the public key, which is
203 returned via parameter PublicKey and PublicKeySize. DH context is updated accordingly.
204 If the PublicKey buffer is too small to hold the public key, FALSE is returned and
205 PublicKeySize is set to the required buffer size to obtain the public key.
206
207 If DhContext is NULL, then return FALSE.
208 If PublicKeySize is NULL, then return FALSE.
209 If PublicKeySize is large enough but PublicKey is NULL, then return FALSE.
210
211 @param[in, out] DhContext Pointer to the DH context.
212 @param[out] PublicKey Pointer to the buffer to receive generated public key.
213 @param[in, out] PublicKeySize On input, the size of PublicKey buffer in bytes.
214 On output, the size of data returned in PublicKey buffer in bytes.
215
216 @retval TRUE DH public key generation succeeded.
217 @retval FALSE DH public key generation failed.
218 @retval FALSE PublicKeySize is not large enough.
219
220 **/
221 BOOLEAN
222 EFIAPI
DhGenerateKey(IN OUT VOID * DhContext,OUT UINT8 * PublicKey,IN OUT UINTN * PublicKeySize)223 DhGenerateKey (
224 IN OUT VOID *DhContext,
225 OUT UINT8 *PublicKey,
226 IN OUT UINTN *PublicKeySize
227 )
228 {
229 BOOLEAN RetVal;
230 DH *Dh;
231 INTN Size;
232
233 //
234 // Check input parameters.
235 //
236 if (DhContext == NULL || PublicKeySize == NULL) {
237 return FALSE;
238 }
239
240 if (PublicKey == NULL && *PublicKeySize != 0) {
241 return FALSE;
242 }
243
244 Dh = (DH *) DhContext;
245
246 RetVal = (BOOLEAN) DH_generate_key (DhContext);
247 if (RetVal) {
248 Size = BN_num_bytes (Dh->pub_key);
249 if (Size <= 0) {
250 *PublicKeySize = 0;
251 return FALSE;
252 }
253 if (*PublicKeySize < (UINTN) Size) {
254 *PublicKeySize = Size;
255 return FALSE;
256 }
257
258 BN_bn2bin (Dh->pub_key, PublicKey);
259 *PublicKeySize = Size;
260 }
261
262 return RetVal;
263 }
264
265 /**
266 Computes exchanged common key.
267
268 Given peer's public key, this function computes the exchanged common key, based on its own
269 context including value of prime modulus and random secret exponent.
270
271 If DhContext is NULL, then return FALSE.
272 If PeerPublicKey is NULL, then return FALSE.
273 If KeySize is NULL, then return FALSE.
274 If Key is NULL, then return FALSE.
275 If KeySize is not large enough, then return FALSE.
276
277 @param[in, out] DhContext Pointer to the DH context.
278 @param[in] PeerPublicKey Pointer to the peer's public key.
279 @param[in] PeerPublicKeySize Size of peer's public key in bytes.
280 @param[out] Key Pointer to the buffer to receive generated key.
281 @param[in, out] KeySize On input, the size of Key buffer in bytes.
282 On output, the size of data returned in Key buffer in bytes.
283
284 @retval TRUE DH exchanged key generation succeeded.
285 @retval FALSE DH exchanged key generation failed.
286 @retval FALSE KeySize is not large enough.
287
288 **/
289 BOOLEAN
290 EFIAPI
DhComputeKey(IN OUT VOID * DhContext,IN CONST UINT8 * PeerPublicKey,IN UINTN PeerPublicKeySize,OUT UINT8 * Key,IN OUT UINTN * KeySize)291 DhComputeKey (
292 IN OUT VOID *DhContext,
293 IN CONST UINT8 *PeerPublicKey,
294 IN UINTN PeerPublicKeySize,
295 OUT UINT8 *Key,
296 IN OUT UINTN *KeySize
297 )
298 {
299 BIGNUM *Bn;
300 INTN Size;
301
302 //
303 // Check input parameters.
304 //
305 if (DhContext == NULL || PeerPublicKey == NULL || KeySize == NULL || Key == NULL) {
306 return FALSE;
307 }
308
309 if (PeerPublicKeySize > INT_MAX) {
310 return FALSE;
311 }
312
313 Bn = BN_bin2bn (PeerPublicKey, (UINT32) PeerPublicKeySize, NULL);
314 if (Bn == NULL) {
315 return FALSE;
316 }
317
318 Size = DH_compute_key (Key, Bn, DhContext);
319 if (Size < 0) {
320 BN_free (Bn);
321 return FALSE;
322 }
323
324 if (*KeySize < (UINTN) Size) {
325 *KeySize = Size;
326 BN_free (Bn);
327 return FALSE;
328 }
329
330 *KeySize = Size;
331 BN_free (Bn);
332 return TRUE;
333 }
334