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