391efd5c14550f16bd9466ad076d2313a3b3bb83
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptDh.c
1 /** @file
2 Diffie-Hellman Wrapper Implementation over OpenSSL.
3
4 Copyright (c) 2010 - 2017, 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 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 parameter 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 BIGNUM *BnP;
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 DH_get0_pqg (DhContext, (const BIGNUM **)&BnP, NULL, NULL);
109 BN_bn2bin (BnP, Prime);
110
111 return TRUE;
112 }
113
114 /**
115 Sets generator and prime parameters for DH.
116
117 Given generator g, and prime number p, this function and sets DH
118 context accordingly.
119
120 If DhContext is NULL, then return FALSE.
121 If Prime is NULL, then return FALSE.
122
123 @param[in, out] DhContext Pointer to the DH context.
124 @param[in] Generator Value of generator.
125 @param[in] PrimeLength Length in bits of prime to be generated.
126 @param[in] Prime Pointer to the prime number.
127
128 @retval TRUE DH parameter setting succeeded.
129 @retval FALSE Value of Generator is not supported.
130 @retval FALSE Value of Generator is not suitable for the Prime.
131 @retval FALSE Value of Prime is not a prime number.
132 @retval FALSE Value of Prime is not a safe prime number.
133
134 **/
135 BOOLEAN
136 EFIAPI
137 DhSetParameter (
138 IN OUT VOID *DhContext,
139 IN UINTN Generator,
140 IN UINTN PrimeLength,
141 IN CONST UINT8 *Prime
142 )
143 {
144 DH *Dh;
145 BIGNUM *BnP;
146 BIGNUM *BnG;
147
148 //
149 // Check input parameters.
150 //
151 if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
152 return FALSE;
153 }
154
155 if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) {
156 return FALSE;
157 }
158
159 //
160 // Set the generator and prime parameters for DH object.
161 //
162 Dh = (DH *)DhContext;
163 BnP = BN_bin2bn ((const unsigned char *)Prime, (int)(PrimeLength / 8), NULL);
164 BnG = BN_bin2bn ((const unsigned char *)&Generator, 1, NULL);
165 if ((BnP == NULL) || (BnG == NULL) || !DH_set0_pqg (Dh, BnP, NULL, BnG)) {
166 goto Error;
167 }
168
169 return TRUE;
170
171 Error:
172 BN_free (BnP);
173 BN_free (BnG);
174
175 return FALSE;
176 }
177
178 /**
179 Generates DH public key.
180
181 This function generates random secret exponent, and computes the public key, which is
182 returned via parameter PublicKey and PublicKeySize. DH context is updated accordingly.
183 If the PublicKey buffer is too small to hold the public key, FALSE is returned and
184 PublicKeySize is set to the required buffer size to obtain the public key.
185
186 If DhContext is NULL, then return FALSE.
187 If PublicKeySize is NULL, then return FALSE.
188 If PublicKeySize is large enough but PublicKey is NULL, then return FALSE.
189
190 @param[in, out] DhContext Pointer to the DH context.
191 @param[out] PublicKey Pointer to the buffer to receive generated public key.
192 @param[in, out] PublicKeySize On input, the size of PublicKey buffer in bytes.
193 On output, the size of data returned in PublicKey buffer in bytes.
194
195 @retval TRUE DH public key generation succeeded.
196 @retval FALSE DH public key generation failed.
197 @retval FALSE PublicKeySize is not large enough.
198
199 **/
200 BOOLEAN
201 EFIAPI
202 DhGenerateKey (
203 IN OUT VOID *DhContext,
204 OUT UINT8 *PublicKey,
205 IN OUT UINTN *PublicKeySize
206 )
207 {
208 BOOLEAN RetVal;
209 DH *Dh;
210 BIGNUM *DhPubKey;
211 INTN Size;
212
213 //
214 // Check input parameters.
215 //
216 if (DhContext == NULL || PublicKeySize == NULL) {
217 return FALSE;
218 }
219
220 if (PublicKey == NULL && *PublicKeySize != 0) {
221 return FALSE;
222 }
223
224 Dh = (DH *) DhContext;
225
226 RetVal = (BOOLEAN) DH_generate_key (DhContext);
227 if (RetVal) {
228 DH_get0_key (Dh, (const BIGNUM **)&DhPubKey, NULL);
229 Size = BN_num_bytes (DhPubKey);
230 if ((Size > 0) && (*PublicKeySize < (UINTN) Size)) {
231 *PublicKeySize = Size;
232 return FALSE;
233 }
234
235 if (PublicKey != NULL) {
236 BN_bn2bin (DhPubKey, PublicKey);
237 }
238 *PublicKeySize = Size;
239 }
240
241 return RetVal;
242 }
243
244 /**
245 Computes exchanged common key.
246
247 Given peer's public key, this function computes the exchanged common key, based on its own
248 context including value of prime modulus and random secret exponent.
249
250 If DhContext is NULL, then return FALSE.
251 If PeerPublicKey is NULL, then return FALSE.
252 If KeySize is NULL, then return FALSE.
253 If Key is NULL, then return FALSE.
254 If KeySize is not large enough, then return FALSE.
255
256 @param[in, out] DhContext Pointer to the DH context.
257 @param[in] PeerPublicKey Pointer to the peer's public key.
258 @param[in] PeerPublicKeySize Size of peer's public key in bytes.
259 @param[out] Key Pointer to the buffer to receive generated key.
260 @param[in, out] KeySize On input, the size of Key buffer in bytes.
261 On output, the size of data returned in Key buffer in bytes.
262
263 @retval TRUE DH exchanged key generation succeeded.
264 @retval FALSE DH exchanged key generation failed.
265 @retval FALSE KeySize is not large enough.
266
267 **/
268 BOOLEAN
269 EFIAPI
270 DhComputeKey (
271 IN OUT VOID *DhContext,
272 IN CONST UINT8 *PeerPublicKey,
273 IN UINTN PeerPublicKeySize,
274 OUT UINT8 *Key,
275 IN OUT UINTN *KeySize
276 )
277 {
278 BIGNUM *Bn;
279 INTN Size;
280
281 //
282 // Check input parameters.
283 //
284 if (DhContext == NULL || PeerPublicKey == NULL || KeySize == NULL || Key == NULL) {
285 return FALSE;
286 }
287
288 if (PeerPublicKeySize > INT_MAX) {
289 return FALSE;
290 }
291
292 Bn = BN_bin2bn (PeerPublicKey, (UINT32) PeerPublicKeySize, NULL);
293 if (Bn == NULL) {
294 return FALSE;
295 }
296
297 Size = DH_compute_key (Key, Bn, DhContext);
298 if (Size < 0) {
299 BN_free (Bn);
300 return FALSE;
301 }
302
303 if (*KeySize < (UINTN) Size) {
304 *KeySize = Size;
305 BN_free (Bn);
306 return FALSE;
307 }
308
309 *KeySize = Size;
310 BN_free (Bn);
311 return TRUE;
312 }