Fix several issues in BaseCryptLib:
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptRsaExt.c
1 /** @file\r
2   RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.\r
3 \r
4   This file implements following APIs which provide more capabilities for RSA:\r
5   1) RsaGetKey\r
6   2) RsaGenerateKey\r
7   3) RsaCheckKey\r
8   4) RsaPkcs1Sign\r
9 \r
10 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
11 This program and the accompanying materials\r
12 are licensed and made available under the terms and conditions of the BSD License\r
13 which accompanies this distribution.  The full text of the license may be found at\r
14 http://opensource.org/licenses/bsd-license.php\r
15 \r
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
18 \r
19 **/\r
20 \r
21 #include "InternalCryptLib.h"\r
22 \r
23 #include <openssl/rsa.h>\r
24 #include <openssl/err.h>\r
25 \r
26 //\r
27 // ASN.1 value for Hash Algorithm ID with the Distringuished Encoding Rules (DER)\r
28 // Refer to Section 9.2 of PKCS#1 v2.1\r
29 //                           \r
30 CONST UINT8  Asn1IdMd5[] = {\r
31   0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,\r
32   0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10\r
33   };\r
34 \r
35 CONST UINT8  Asn1IdSha1[] = {\r
36   0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,\r
37   0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14\r
38   };\r
39 \r
40 CONST UINT8  Asn1IdSha256[] = {\r
41   0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,\r
42   0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,\r
43   0x00, 0x04, 0x20\r
44   };\r
45 \r
46 /**\r
47   Gets the tag-designated RSA key component from the established RSA context.\r
48 \r
49   This function retrieves the tag-designated RSA key component from the\r
50   established RSA context as a non-negative integer (octet string format\r
51   represented in RSA PKCS#1).\r
52   If specified key component has not been set or has been cleared, then returned\r
53   BnSize is set to 0.\r
54   If the BigNumber buffer is too small to hold the contents of the key, FALSE\r
55   is returned and BnSize is set to the required buffer size to obtain the key.\r
56 \r
57   If RsaContext is NULL, then return FALSE.\r
58   If BnSize is NULL, then return FALSE.\r
59   If BnSize is large enough but BigNumber is NULL, then return FALSE.\r
60 \r
61   @param[in, out]  RsaContext  Pointer to RSA context being set.\r
62   @param[in]       KeyTag      Tag of RSA key component being set.\r
63   @param[out]      BigNumber   Pointer to octet integer buffer.\r
64   @param[in, out]  BnSize      On input, the size of big number buffer in bytes.\r
65                                On output, the size of data returned in big number buffer in bytes.\r
66 \r
67   @retval  TRUE   RSA key component was retrieved successfully.\r
68   @retval  FALSE  Invalid RSA key component tag.\r
69   @retval  FALSE  BnSize is too small.\r
70 \r
71 **/\r
72 BOOLEAN\r
73 EFIAPI\r
74 RsaGetKey (\r
75   IN OUT  VOID         *RsaContext,\r
76   IN      RSA_KEY_TAG  KeyTag,\r
77   OUT     UINT8        *BigNumber,\r
78   IN OUT  UINTN        *BnSize\r
79   )\r
80 {\r
81   RSA    *RsaKey;\r
82   BIGNUM *BnKey;\r
83   UINTN  Size;\r
84 \r
85   //\r
86   // Check input parameters.\r
87   //\r
88   if (RsaContext == NULL || BnSize == NULL) {\r
89     return FALSE;\r
90   }\r
91 \r
92   RsaKey  = (RSA *) RsaContext;\r
93   Size    = *BnSize;\r
94   *BnSize = 0;\r
95 \r
96   switch (KeyTag) {\r
97 \r
98   //\r
99   // RSA Public Modulus (N)\r
100   //\r
101   case RsaKeyN:\r
102     if (RsaKey->n == NULL) {\r
103       return TRUE;\r
104     }\r
105     BnKey = RsaKey->n;\r
106     break;\r
107 \r
108   //\r
109   // RSA Public Exponent (e)\r
110   //\r
111   case RsaKeyE:\r
112     if (RsaKey->e == NULL) {\r
113       return TRUE;\r
114     }\r
115     BnKey = RsaKey->e;\r
116     break;\r
117 \r
118   //\r
119   // RSA Private Exponent (d)\r
120   //\r
121   case RsaKeyD:\r
122     if (RsaKey->d == NULL) {\r
123       return TRUE;\r
124     }\r
125     BnKey = RsaKey->d;\r
126     break;\r
127 \r
128   //\r
129   // RSA Secret Prime Factor of Modulus (p)\r
130   //\r
131   case RsaKeyP:\r
132     if (RsaKey->p == NULL) {\r
133       return TRUE;\r
134     }\r
135     BnKey = RsaKey->p;\r
136     break;\r
137 \r
138   //\r
139   // RSA Secret Prime Factor of Modules (q)\r
140   //\r
141   case RsaKeyQ:\r
142     if (RsaKey->q == NULL) {\r
143       return TRUE;\r
144     }\r
145     BnKey = RsaKey->q;\r
146     break;\r
147 \r
148   //\r
149   // p's CRT Exponent (== d mod (p - 1))\r
150   //\r
151   case RsaKeyDp:\r
152     if (RsaKey->dmp1 == NULL) {\r
153       return TRUE;\r
154     }\r
155     BnKey = RsaKey->dmp1;\r
156     break;\r
157 \r
158   //\r
159   // q's CRT Exponent (== d mod (q - 1))\r
160   //\r
161   case RsaKeyDq:\r
162     if (RsaKey->dmq1 == NULL) {\r
163       return TRUE;\r
164     }\r
165     BnKey = RsaKey->dmq1;\r
166     break;\r
167 \r
168   //\r
169   // The CRT Coefficient (== 1/q mod p)\r
170   //\r
171   case RsaKeyQInv:\r
172     if (RsaKey->iqmp == NULL) {\r
173       return TRUE;\r
174     }\r
175     BnKey = RsaKey->iqmp;\r
176     break;\r
177 \r
178   default:\r
179     return FALSE;\r
180   }\r
181 \r
182   *BnSize = Size;\r
183   Size    = BN_num_bytes (BnKey);\r
184 \r
185   if (*BnSize < Size) {\r
186     *BnSize = Size;\r
187     return FALSE;\r
188   }\r
189 \r
190   if (BigNumber == NULL) {\r
191     return FALSE;\r
192   }\r
193   *BnSize = BN_bn2bin (BnKey, BigNumber) ;\r
194   \r
195   return TRUE;\r
196 }\r
197 \r
198 /**\r
199   Generates RSA key components.\r
200 \r
201   This function generates RSA key components. It takes RSA public exponent E and\r
202   length in bits of RSA modulus N as input, and generates all key components.\r
203   If PublicExponent is NULL, the default RSA public exponent (0x10001) will be used.\r
204 \r
205   Before this function can be invoked, pseudorandom number generator must be correctly\r
206   initialized by RandomSeed().\r
207 \r
208   If RsaContext is NULL, then return FALSE.\r
209 \r
210   @param[in, out]  RsaContext           Pointer to RSA context being set.\r
211   @param[in]       ModulusLength        Length of RSA modulus N in bits.\r
212   @param[in]       PublicExponent       Pointer to RSA public exponent.\r
213   @param[in]       PublicExponentSize   Size of RSA public exponent buffer in bytes. \r
214 \r
215   @retval  TRUE   RSA key component was generated successfully.\r
216   @retval  FALSE  Invalid RSA key component tag.\r
217 \r
218 **/\r
219 BOOLEAN\r
220 EFIAPI\r
221 RsaGenerateKey (\r
222   IN OUT  VOID         *RsaContext,\r
223   IN      UINTN        ModulusLength,\r
224   IN      CONST UINT8  *PublicExponent,\r
225   IN      UINTN        PublicExponentSize\r
226   )\r
227 {\r
228   BIGNUM   *KeyE;\r
229   BOOLEAN  RetVal;\r
230 \r
231   //\r
232   // Check input parameters.\r
233   //\r
234   if (RsaContext == NULL || ModulusLength > INT_MAX || PublicExponentSize > INT_MAX) {\r
235     return FALSE;\r
236   }\r
237   \r
238   KeyE = BN_new ();\r
239   if (KeyE == NULL) {\r
240     return FALSE;\r
241   }\r
242 \r
243   RetVal = FALSE;\r
244   \r
245   if (PublicExponent == NULL) {\r
246     if (BN_set_word (KeyE, 0x10001) == 0) {\r
247       goto _Exit;\r
248     }\r
249   } else {\r
250     if (BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE) == NULL) {\r
251       goto _Exit;\r
252     }\r
253   }\r
254 \r
255   if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) {\r
256    RetVal = TRUE;\r
257   }\r
258 \r
259 _Exit:\r
260   BN_free (KeyE);\r
261   return RetVal;\r
262 }\r
263 \r
264 /**\r
265   Validates key components of RSA context.\r
266 \r
267   This function validates key compoents of RSA context in following aspects:\r
268   - Whether p is a prime\r
269   - Whether q is a prime\r
270   - Whether n = p * q\r
271   - Whether d*e = 1  mod lcm(p-1,q-1)\r
272 \r
273   If RsaContext is NULL, then return FALSE.\r
274 \r
275   @param[in]  RsaContext  Pointer to RSA context to check.\r
276 \r
277   @retval  TRUE   RSA key components are valid.\r
278   @retval  FALSE  RSA key components are not valid.\r
279 \r
280 **/\r
281 BOOLEAN\r
282 EFIAPI\r
283 RsaCheckKey (\r
284   IN  VOID  *RsaContext\r
285   )\r
286 {\r
287   UINTN  Reason;\r
288 \r
289   //\r
290   // Check input parameters.\r
291   //\r
292   if (RsaContext == NULL) {\r
293     return FALSE;\r
294   }\r
295   \r
296   if  (RSA_check_key ((RSA *) RsaContext) != 1) {\r
297     Reason = ERR_GET_REASON (ERR_peek_last_error ());\r
298     if (Reason == RSA_R_P_NOT_PRIME ||\r
299         Reason == RSA_R_Q_NOT_PRIME ||\r
300         Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q ||\r
301         Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) {\r
302       return FALSE;\r
303     }\r
304   }\r
305 \r
306   return TRUE;\r
307 }\r
308 \r
309 /**\r
310   Performs the PKCS1-v1_5 encoding methods defined in RSA PKCS #1.\r
311 \r
312   @param[in]     Message        Message buffer to be encoded.\r
313   @param[in]     MessageSize    Size of message buffer in bytes.\r
314   @param[out]    DigestInfo     Pointer to buffer of digest info for output.\r
315   @param[in,out] DigestInfoSize On input, the size of DigestInfo buffer in bytes.\r
316                                 On output, the size of data returned in DigestInfo\r
317                                 buffer in bytes.\r
318 \r
319   @retval TRUE   PKCS1-v1_5 encoding finished successfully.\r
320   @retval FALSE  Any input parameter is invalid.\r
321   @retval FALSE  DigestInfo buffer is not large enough.\r
322 \r
323 **/  \r
324 BOOLEAN\r
325 DigestInfoEncoding (\r
326   IN CONST UINT8  *Message,\r
327   IN       UINTN  MessageSize,\r
328   OUT      UINT8  *DigestInfo,\r
329   IN OUT   UINTN  *DigestInfoSize\r
330   )\r
331 {\r
332   CONST UINT8  *HashDer;\r
333   UINTN        DerSize;\r
334 \r
335   //\r
336   // Check input parameters.\r
337   //\r
338   if (Message == NULL || DigestInfo == NULL || DigestInfoSize == NULL) {\r
339     return FALSE;\r
340   }\r
341 \r
342   //\r
343   // The original message length is used to determine the hash algorithm since\r
344   // message is digest value hashed by the specified algorithm.\r
345   //\r
346   switch (MessageSize) {\r
347   case MD5_DIGEST_SIZE:\r
348     HashDer = Asn1IdMd5;\r
349     DerSize = sizeof (Asn1IdMd5);\r
350     break;\r
351   \r
352   case SHA1_DIGEST_SIZE:\r
353     HashDer = Asn1IdSha1;\r
354     DerSize = sizeof (Asn1IdSha1);\r
355     break;\r
356    \r
357   case SHA256_DIGEST_SIZE:\r
358     HashDer = Asn1IdSha256;\r
359     DerSize = sizeof (Asn1IdSha256);\r
360     break;\r
361   \r
362   default:\r
363     return FALSE;\r
364   }\r
365 \r
366   if (*DigestInfoSize < DerSize + MessageSize) {\r
367     *DigestInfoSize = DerSize + MessageSize;\r
368     return FALSE;\r
369   }\r
370 \r
371   CopyMem (DigestInfo, HashDer, DerSize);\r
372   CopyMem (DigestInfo + DerSize, Message, MessageSize);\r
373 \r
374   *DigestInfoSize = DerSize + MessageSize;\r
375   return TRUE;\r
376 }\r
377 \r
378 /**\r
379   Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.\r
380 \r
381   This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in\r
382   RSA PKCS#1.\r
383   If the Signature buffer is too small to hold the contents of signature, FALSE\r
384   is returned and SigSize is set to the required buffer size to obtain the signature.\r
385 \r
386   If RsaContext is NULL, then return FALSE.\r
387   If MessageHash is NULL, then return FALSE.\r
388   If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.\r
389   If SigSize is large enough but Signature is NULL, then return FALSE.\r
390 \r
391   @param[in]       RsaContext   Pointer to RSA context for signature generation.\r
392   @param[in]       MessageHash  Pointer to octet message hash to be signed.\r
393   @param[in]       HashSize     Size of the message hash in bytes.\r
394   @param[out]      Signature    Pointer to buffer to receive RSA PKCS1-v1_5 signature.\r
395   @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.\r
396                                 On output, the size of data returned in Signature buffer in bytes.\r
397 \r
398   @retval  TRUE   Signature successfully generated in PKCS1-v1_5.\r
399   @retval  FALSE  Signature generation failed.\r
400   @retval  FALSE  SigSize is too small.\r
401 \r
402 **/\r
403 BOOLEAN\r
404 EFIAPI\r
405 RsaPkcs1Sign (\r
406   IN      VOID         *RsaContext,\r
407   IN      CONST UINT8  *MessageHash,\r
408   IN      UINTN        HashSize,\r
409   OUT     UINT8        *Signature,\r
410   IN OUT  UINTN        *SigSize\r
411   )\r
412 {\r
413   RSA      *Rsa;\r
414   UINTN    Size;\r
415   INTN     ReturnVal;\r
416 \r
417   //\r
418   // Check input parameters.\r
419   //\r
420   if (RsaContext == NULL || MessageHash == NULL ||\r
421     (HashSize != MD5_DIGEST_SIZE && HashSize != SHA1_DIGEST_SIZE && HashSize != SHA256_DIGEST_SIZE)) {\r
422     return FALSE;\r
423   }\r
424 \r
425   Rsa = (RSA *) RsaContext;\r
426   Size = BN_num_bytes (Rsa->n);\r
427 \r
428   if (*SigSize < Size) {\r
429     *SigSize = Size;\r
430     return FALSE;\r
431   }\r
432 \r
433   if (Signature == NULL) {\r
434     return FALSE;\r
435   }\r
436 \r
437   if (!DigestInfoEncoding (MessageHash, HashSize, Signature, SigSize)) {\r
438     return FALSE;\r
439   }\r
440 \r
441   ReturnVal = RSA_private_encrypt (\r
442                 (UINT32) *SigSize,\r
443                 Signature,\r
444                 Signature,\r
445                 Rsa,\r
446                 RSA_PKCS1_PADDING\r
447                 );\r
448 \r
449   if (ReturnVal < (INTN) *SigSize) {\r
450     return FALSE;\r
451   }\r
452 \r
453   *SigSize = (UINTN) ReturnVal;\r
454   return TRUE;\r
455 }\r
456 \r