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