67d8826e6c4a706d9db930dc2aeb86f4ebbd8b5b
[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) {\r
235     return FALSE;\r
236   }\r
237   \r
238   KeyE = BN_new ();\r
239   if (PublicExponent == NULL) {\r
240     BN_set_word (KeyE, 0x10001);\r
241   } else {\r
242     BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE);\r
243   }\r
244 \r
245   RetVal = FALSE;\r
246   if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) {\r
247    RetVal = TRUE;\r
248   }\r
249 \r
250   BN_free (KeyE);\r
251   return RetVal;\r
252 }\r
253 \r
254 /**\r
255   Validates key components of RSA context.\r
256 \r
257   This function validates key compoents of RSA context in following aspects:\r
258   - Whether p is a prime\r
259   - Whether q is a prime\r
260   - Whether n = p * q\r
261   - Whether d*e = 1  mod lcm(p-1,q-1)\r
262 \r
263   If RsaContext is NULL, then return FALSE.\r
264 \r
265   @param[in]  RsaContext  Pointer to RSA context to check.\r
266 \r
267   @retval  TRUE   RSA key components are valid.\r
268   @retval  FALSE  RSA key components are not valid.\r
269 \r
270 **/\r
271 BOOLEAN\r
272 EFIAPI\r
273 RsaCheckKey (\r
274   IN  VOID  *RsaContext\r
275   )\r
276 {\r
277   UINTN  Reason;\r
278 \r
279   //\r
280   // Check input parameters.\r
281   //\r
282   if (RsaContext == NULL) {\r
283     return FALSE;\r
284   }\r
285   \r
286   if  (RSA_check_key ((RSA *) RsaContext) != 1) {\r
287     Reason = ERR_GET_REASON (ERR_peek_last_error ());\r
288     if (Reason == RSA_R_P_NOT_PRIME ||\r
289         Reason == RSA_R_Q_NOT_PRIME ||\r
290         Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q ||\r
291         Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) {\r
292       return FALSE;\r
293     }\r
294   }\r
295 \r
296   return TRUE;\r
297 }\r
298 \r
299 /**\r
300   Performs the PKCS1-v1_5 encoding methods defined in RSA PKCS #1.\r
301 \r
302   @param  Message      Message buffer to be encoded.\r
303   @param  MessageSize  Size of message buffer in bytes.\r
304   @param  DigestInfo   Pointer to buffer of digest info for output.\r
305 \r
306   @return  Size of DigestInfo in bytes.\r
307 \r
308 **/  \r
309 UINTN\r
310 DigestInfoEncoding (\r
311   IN   CONST UINT8  *Message,\r
312   IN   UINTN        MessageSize,\r
313   OUT  UINT8        *DigestInfo\r
314   )\r
315 {\r
316   CONST UINT8  *HashDer;\r
317   UINTN        DerSize;\r
318 \r
319   //\r
320   // Check input parameters.\r
321   //\r
322   if (Message == NULL || DigestInfo == NULL) {\r
323     return FALSE;\r
324   }\r
325 \r
326   //\r
327   // The original message length is used to determine the hash algorithm since\r
328   // message is digest value hashed by the specified algorithm.\r
329   //\r
330   switch (MessageSize) {\r
331   case MD5_DIGEST_SIZE:\r
332     HashDer = Asn1IdMd5;\r
333     DerSize = sizeof (Asn1IdMd5);\r
334     break;\r
335   \r
336   case SHA1_DIGEST_SIZE:\r
337     HashDer = Asn1IdSha1;\r
338     DerSize = sizeof (Asn1IdSha1);\r
339     break;\r
340    \r
341   case SHA256_DIGEST_SIZE:\r
342     HashDer = Asn1IdSha256;\r
343     DerSize = sizeof (Asn1IdSha256);\r
344     break;\r
345   \r
346   default:\r
347     return FALSE;\r
348   }\r
349 \r
350   CopyMem (DigestInfo, HashDer, DerSize);\r
351   CopyMem (DigestInfo + DerSize, Message, MessageSize);\r
352 \r
353   return (DerSize + MessageSize);\r
354 }\r
355 \r
356 /**\r
357   Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.\r
358 \r
359   This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in\r
360   RSA PKCS#1.\r
361   If the Signature buffer is too small to hold the contents of signature, FALSE\r
362   is returned and SigSize is set to the required buffer size to obtain the signature.\r
363 \r
364   If RsaContext is NULL, then return FALSE.\r
365   If MessageHash is NULL, then return FALSE.\r
366   If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.\r
367   If SigSize is large enough but Signature is NULL, then return FALSE.\r
368 \r
369   @param[in]       RsaContext   Pointer to RSA context for signature generation.\r
370   @param[in]       MessageHash  Pointer to octet message hash to be signed.\r
371   @param[in]       HashSize     Size of the message hash in bytes.\r
372   @param[out]      Signature    Pointer to buffer to receive RSA PKCS1-v1_5 signature.\r
373   @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.\r
374                                 On output, the size of data returned in Signature buffer in bytes.\r
375 \r
376   @retval  TRUE   Signature successfully generated in PKCS1-v1_5.\r
377   @retval  FALSE  Signature generation failed.\r
378   @retval  FALSE  SigSize is too small.\r
379 \r
380 **/\r
381 BOOLEAN\r
382 EFIAPI\r
383 RsaPkcs1Sign (\r
384   IN      VOID         *RsaContext,\r
385   IN      CONST UINT8  *MessageHash,\r
386   IN      UINTN        HashSize,\r
387   OUT     UINT8        *Signature,\r
388   IN OUT  UINTN        *SigSize\r
389   )\r
390 {\r
391   RSA      *Rsa;\r
392   UINTN    Size;\r
393   INTN     ReturnVal;\r
394 \r
395   //\r
396   // Check input parameters.\r
397   //\r
398   if (RsaContext == NULL || MessageHash == NULL ||\r
399     (HashSize != MD5_DIGEST_SIZE && HashSize != SHA1_DIGEST_SIZE && HashSize != SHA256_DIGEST_SIZE)) {\r
400     return FALSE;\r
401   }\r
402 \r
403   Rsa = (RSA *) RsaContext;\r
404   Size = BN_num_bytes (Rsa->n);\r
405 \r
406   if (*SigSize < Size) {\r
407     *SigSize = Size;\r
408     return FALSE;\r
409   }\r
410 \r
411   if (Signature == NULL) {\r
412     return FALSE;\r
413   }\r
414 \r
415   Size = DigestInfoEncoding (MessageHash, HashSize, Signature);\r
416 \r
417   ReturnVal = RSA_private_encrypt (\r
418                 (UINT32) Size,\r
419                 Signature,\r
420                 Signature,\r
421                 Rsa,\r
422                 RSA_PKCS1_PADDING\r
423                 );\r
424 \r
425   if (ReturnVal < (INTN) Size) {\r
426     return FALSE;\r
427   }\r
428 \r
429   *SigSize = (UINTN)ReturnVal;\r
430   return TRUE;\r
431 }\r
432 \r