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