OLD | NEW |
1 /* | 1 /* |
2 * PKCS#1 encoding and decoding functions. | 2 * PKCS#1 encoding and decoding functions. |
3 * This file is believed to contain no code licensed from other parties. | 3 * This file is believed to contain no code licensed from other parties. |
4 * | 4 * |
5 * This Source Code Form is subject to the terms of the Mozilla Public | 5 * This Source Code Form is subject to the terms of the Mozilla Public |
6 * License, v. 2.0. If a copy of the MPL was not distributed with this | 6 * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
8 /* $Id: rsawrapr.c,v 1.21 2012/06/26 22:27:31 rrelyea%redhat.com Exp $ */ | 8 /* $Id: rsawrapr.c,v 1.22 2013/02/05 02:19:52 ryan.sleevi%gmail.com Exp $ */ |
9 | 9 |
10 #include "blapi.h" | 10 #include "blapi.h" |
11 #include "softoken.h" | 11 #include "softoken.h" |
12 | 12 |
13 #include "lowkeyi.h" | 13 #include "lowkeyi.h" |
14 #include "secerr.h" | 14 #include "secerr.h" |
15 | 15 |
16 #define RSA_BLOCK_MIN_PAD_LEN 8 | 16 #define RSA_BLOCK_MIN_PAD_LEN 8 |
17 #define RSA_BLOCK_FIRST_OCTET 0x00 | 17 #define RSA_BLOCK_FIRST_OCTET 0x00 |
18 #define RSA_BLOCK_PRIVATE0_PAD_OCTET 0x00 | 18 #define RSA_BLOCK_PRIVATE0_PAD_OCTET 0x00 |
19 #define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff | 19 #define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff |
20 #define RSA_BLOCK_AFTER_PAD_OCTET 0x00 | 20 #define RSA_BLOCK_AFTER_PAD_OCTET 0x00 |
21 | 21 |
22 #define OAEP_SALT_LEN 8 | |
23 #define OAEP_PAD_LEN 8 | |
24 #define OAEP_PAD_OCTET 0x00 | |
25 | |
26 #define FLAT_BUFSIZE 512 /* bytes to hold flattened SHA1Context. */ | |
27 | |
28 /* Needed for RSA-PSS functions */ | 22 /* Needed for RSA-PSS functions */ |
29 static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 23 static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
30 | 24 |
31 static SHA1Context * | 25 /* Constant time comparison of a single byte. |
32 SHA1_CloneContext(SHA1Context *original) | 26 * Returns 1 iff a == b, otherwise returns 0. |
| 27 * Note: For ranges of bytes, use constantTimeCompare. |
| 28 */ |
| 29 static unsigned char constantTimeEQ8(unsigned char a, unsigned char b) { |
| 30 unsigned char c = ~(a - b | b - a); |
| 31 c >>= 7; |
| 32 return c; |
| 33 } |
| 34 |
| 35 /* Constant time comparison of a range of bytes. |
| 36 * Returns 1 iff len bytes of a are identical to len bytes of b, otherwise |
| 37 * returns 0. |
| 38 */ |
| 39 static unsigned char constantTimeCompare(const unsigned char *a, |
| 40 const unsigned char *b, |
| 41 unsigned int len) { |
| 42 unsigned char tmp = 0; |
| 43 unsigned int i; |
| 44 for (i = 0; i < len; ++i, ++a, ++b) |
| 45 tmp |= *a ^ *b; |
| 46 return constantTimeEQ8(0x00, tmp); |
| 47 } |
| 48 |
| 49 /* Constant time conditional. |
| 50 * Returns a if c is 1, or b if c is 0. The result is undefined if c is |
| 51 * not 0 or 1. |
| 52 */ |
| 53 static unsigned int constantTimeCondition(unsigned int c, |
| 54 unsigned int a, |
| 55 unsigned int b) |
33 { | 56 { |
34 SHA1Context * clone» = NULL; | 57 return (~(c - 1) & a) | ((c - 1) & b); |
35 unsigned char *pBuf; | |
36 int sha1ContextSize = SHA1_FlattenSize(original); | |
37 SECStatus frv; | |
38 unsigned char buf[FLAT_BUFSIZE]; | |
39 | |
40 PORT_Assert(sizeof buf >= sha1ContextSize); | |
41 if (sizeof buf >= sha1ContextSize) { | |
42 » pBuf = buf; | |
43 } else { | |
44 pBuf = PORT_Alloc(sha1ContextSize); | |
45 » if (!pBuf) | |
46 » goto done; | |
47 } | |
48 | |
49 frv = SHA1_Flatten(original, pBuf); | |
50 if (frv == SECSuccess) { | |
51 » clone = SHA1_Resurrect(pBuf, NULL); | |
52 » memset(pBuf, 0, sha1ContextSize); | |
53 } | |
54 done: | |
55 if (pBuf != buf) | |
56 » PORT_Free(pBuf); | |
57 return clone; | |
58 } | 58 } |
59 | 59 |
60 /* | 60 /* |
61 * Modify data by XORing it with a special hash of salt. | |
62 */ | |
63 static SECStatus | |
64 oaep_xor_with_h1(unsigned char *data, unsigned int datalen, | |
65 unsigned char *salt, unsigned int saltlen) | |
66 { | |
67 SHA1Context *sha1cx; | |
68 unsigned char *dp, *dataend; | |
69 unsigned char end_octet; | |
70 | |
71 sha1cx = SHA1_NewContext(); | |
72 if (sha1cx == NULL) { | |
73 return SECFailure; | |
74 } | |
75 | |
76 /* | |
77 * Get a hash of salt started; we will use it several times, | |
78 * adding in a different end octet (x00, x01, x02, ...). | |
79 */ | |
80 SHA1_Begin (sha1cx); | |
81 SHA1_Update (sha1cx, salt, saltlen); | |
82 end_octet = 0; | |
83 | |
84 dp = data; | |
85 dataend = data + datalen; | |
86 | |
87 while (dp < dataend) { | |
88 SHA1Context *sha1cx_h1; | |
89 unsigned int sha1len, sha1off; | |
90 unsigned char sha1[SHA1_LENGTH]; | |
91 | |
92 /* | |
93 * Create hash of (salt || end_octet) | |
94 */ | |
95 sha1cx_h1 = SHA1_CloneContext (sha1cx); | |
96 SHA1_Update (sha1cx_h1, &end_octet, 1); | |
97 SHA1_End (sha1cx_h1, sha1, &sha1len, sizeof(sha1)); | |
98 SHA1_DestroyContext (sha1cx_h1, PR_TRUE); | |
99 PORT_Assert (sha1len == SHA1_LENGTH); | |
100 | |
101 /* | |
102 * XOR that hash with the data. | |
103 * When we have fewer than SHA1_LENGTH octets of data | |
104 * left to xor, use just the low-order ones of the hash. | |
105 */ | |
106 sha1off = 0; | |
107 if ((dataend - dp) < SHA1_LENGTH) | |
108 sha1off = SHA1_LENGTH - (dataend - dp); | |
109 while (sha1off < SHA1_LENGTH) | |
110 *dp++ ^= sha1[sha1off++]; | |
111 | |
112 /* | |
113 * Bump for next hash chunk. | |
114 */ | |
115 end_octet++; | |
116 } | |
117 | |
118 SHA1_DestroyContext (sha1cx, PR_TRUE); | |
119 return SECSuccess; | |
120 } | |
121 | |
122 /* | |
123 * Modify salt by XORing it with a special hash of data. | |
124 */ | |
125 static SECStatus | |
126 oaep_xor_with_h2(unsigned char *salt, unsigned int saltlen, | |
127 unsigned char *data, unsigned int datalen) | |
128 { | |
129 unsigned char sha1[SHA1_LENGTH]; | |
130 unsigned char *psalt, *psha1, *saltend; | |
131 SECStatus rv; | |
132 | |
133 /* | |
134 * Create a hash of data. | |
135 */ | |
136 rv = SHA1_HashBuf (sha1, data, datalen); | |
137 if (rv != SECSuccess) { | |
138 return rv; | |
139 } | |
140 | |
141 /* | |
142 * XOR the low-order octets of that hash with salt. | |
143 */ | |
144 PORT_Assert (saltlen <= SHA1_LENGTH); | |
145 saltend = salt + saltlen; | |
146 psalt = salt; | |
147 psha1 = sha1 + SHA1_LENGTH - saltlen; | |
148 while (psalt < saltend) { | |
149 *psalt++ ^= *psha1++; | |
150 } | |
151 | |
152 return SECSuccess; | |
153 } | |
154 | |
155 /* | |
156 * Format one block of data for public/private key encryption using | 61 * Format one block of data for public/private key encryption using |
157 * the rules defined in PKCS #1. | 62 * the rules defined in PKCS #1. |
158 */ | 63 */ |
159 static unsigned char * | 64 static unsigned char * |
160 rsa_FormatOneBlock(unsigned modulusLen, RSA_BlockType blockType, | 65 rsa_FormatOneBlock(unsigned modulusLen, RSA_BlockType blockType, |
161 SECItem *data) | 66 SECItem *data) |
162 { | 67 { |
163 unsigned char *block; | 68 unsigned char *block; |
164 unsigned char *bp; | 69 unsigned char *bp; |
165 int padLen; | 70 int padLen; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 if (rv != SECSuccess) { | 163 if (rv != SECSuccess) { |
259 sftk_fatalError = PR_TRUE; | 164 sftk_fatalError = PR_TRUE; |
260 PORT_Free (block); | 165 PORT_Free (block); |
261 return NULL; | 166 return NULL; |
262 } | 167 } |
263 bp += padLen; | 168 bp += padLen; |
264 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET; | 169 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET; |
265 PORT_Memcpy (bp, data->data, data->len); | 170 PORT_Memcpy (bp, data->data, data->len); |
266 break; | 171 break; |
267 | 172 |
268 /* | |
269 * Blocks intended for public-key operation, using | |
270 * Optimal Asymmetric Encryption Padding (OAEP). | |
271 */ | |
272 case RSA_BlockOAEP: | |
273 /* | |
274 * 0x00 || BT || Modified2(Salt) || Modified1(PaddedData) | |
275 * 1 1 OAEP_SALT_LEN OAEP_PAD_LEN + data->len [+ N] | |
276 * | |
277 * where: | |
278 * PaddedData is "Pad1 || ActualData [|| Pad2]" | |
279 * Salt is random data. | |
280 * Pad1 is all zeros. | |
281 * Pad2, if present, is random data. | |
282 * (The "modified" fields are all the same length as the original | |
283 * unmodified values; they are just xor'd with other values.) | |
284 * | |
285 * Modified1 is an XOR of PaddedData with a special octet | |
286 * string constructed of iterated hashing of Salt (see below). | |
287 * Modified2 is an XOR of Salt with the low-order octets of | |
288 * the hash of Modified1 (see farther below ;-). | |
289 * | |
290 * Whew! | |
291 */ | |
292 | |
293 | |
294 /* | |
295 * Salt | |
296 */ | |
297 rv = RNG_GenerateGlobalRandomBytes(bp, OAEP_SALT_LEN); | |
298 if (rv != SECSuccess) { | |
299 sftk_fatalError = PR_TRUE; | |
300 PORT_Free (block); | |
301 return NULL; | |
302 } | |
303 bp += OAEP_SALT_LEN; | |
304 | |
305 /* | |
306 * Pad1 | |
307 */ | |
308 PORT_Memset (bp, OAEP_PAD_OCTET, OAEP_PAD_LEN); | |
309 bp += OAEP_PAD_LEN; | |
310 | |
311 /* | |
312 * Data | |
313 */ | |
314 PORT_Memcpy (bp, data->data, data->len); | |
315 bp += data->len; | |
316 | |
317 /* | |
318 * Pad2 | |
319 */ | |
320 if (bp < (block + modulusLen)) { | |
321 rv = RNG_GenerateGlobalRandomBytes(bp, block - bp + modulusLen); | |
322 if (rv != SECSuccess) { | |
323 sftk_fatalError = PR_TRUE; | |
324 PORT_Free (block); | |
325 return NULL; | |
326 } | |
327 } | |
328 | |
329 /* | |
330 * Now we have the following: | |
331 * 0x00 || BT || Salt || PaddedData | |
332 * (From this point on, "Pad1 || Data [|| Pad2]" is treated | |
333 * as the one entity PaddedData.) | |
334 * | |
335 * We need to turn PaddedData into Modified1. | |
336 */ | |
337 if (oaep_xor_with_h1(block + 2 + OAEP_SALT_LEN, | |
338 modulusLen - 2 - OAEP_SALT_LEN, | |
339 block + 2, OAEP_SALT_LEN) != SECSuccess) { | |
340 PORT_Free (block); | |
341 return NULL; | |
342 } | |
343 | |
344 /* | |
345 * Now we have: | |
346 * 0x00 || BT || Salt || Modified1(PaddedData) | |
347 * | |
348 * The remaining task is to turn Salt into Modified2. | |
349 */ | |
350 if (oaep_xor_with_h2(block + 2, OAEP_SALT_LEN, | |
351 block + 2 + OAEP_SALT_LEN, | |
352 modulusLen - 2 - OAEP_SALT_LEN) != SECSuccess) { | |
353 PORT_Free (block); | |
354 return NULL; | |
355 } | |
356 | |
357 break; | |
358 | |
359 default: | 173 default: |
360 PORT_Assert (0); | 174 PORT_Assert (0); |
361 PORT_Free (block); | 175 PORT_Free (block); |
362 return NULL; | 176 return NULL; |
363 } | 177 } |
364 | 178 |
365 return block; | 179 return block; |
366 } | 180 } |
367 | 181 |
368 static SECStatus | 182 static SECStatus |
(...skipping 27 matching lines...) Expand all Loading... |
396 | 210 |
397 result->data = rsa_FormatOneBlock(modulusLen, blockType, data); | 211 result->data = rsa_FormatOneBlock(modulusLen, blockType, data); |
398 if (result->data == NULL) { | 212 if (result->data == NULL) { |
399 result->len = 0; | 213 result->len = 0; |
400 return SECFailure; | 214 return SECFailure; |
401 } | 215 } |
402 result->len = modulusLen; | 216 result->len = modulusLen; |
403 | 217 |
404 break; | 218 break; |
405 | 219 |
406 case RSA_BlockOAEP: | |
407 /* | |
408 * 0x00 || BT || M1(Salt) || M2(Pad1||ActualData[||Pad2]) | |
409 * | |
410 * The "2" below is the first octet + the second octet. | |
411 * (The other fields do not contain the clear values, but are | |
412 * the same length as the clear values.) | |
413 */ | |
414 PORT_Assert (data->len <= (modulusLen - (2 + OAEP_SALT_LEN | |
415 + OAEP_PAD_LEN))); | |
416 | |
417 result->data = rsa_FormatOneBlock(modulusLen, blockType, data); | |
418 if (result->data == NULL) { | |
419 result->len = 0; | |
420 return SECFailure; | |
421 } | |
422 result->len = modulusLen; | |
423 | |
424 break; | |
425 | |
426 case RSA_BlockRaw: | 220 case RSA_BlockRaw: |
427 /* | 221 /* |
428 * Pad || ActualData | 222 * Pad || ActualData |
429 * Pad is zeros. The application is responsible for recovering | 223 * Pad is zeros. The application is responsible for recovering |
430 * the actual data. | 224 * the actual data. |
431 */ | 225 */ |
432 if (data->len > modulusLen ) { | 226 if (data->len > modulusLen ) { |
433 return SECFailure; | 227 return SECFailure; |
434 } | 228 } |
435 result->data = (unsigned char*)PORT_ZAlloc(modulusLen); | 229 result->data = (unsigned char*)PORT_ZAlloc(modulusLen); |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length); | 746 PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length); |
953 PORT_Free(temp); | 747 PORT_Free(temp); |
954 } | 748 } |
955 } | 749 } |
956 (*hash->destroy)(hashContext, PR_TRUE); | 750 (*hash->destroy)(hashContext, PR_TRUE); |
957 | 751 |
958 return SECSuccess; | 752 return SECSuccess; |
959 } | 753 } |
960 | 754 |
961 /* | 755 /* |
| 756 * Decodes an EME-OAEP encoded block, validating the encoding in constant |
| 757 * time. |
| 758 * Described in RFC 3447, section 7.1.2. |
| 759 * input contains the encoded block, after decryption. |
| 760 * label is the optional value L that was associated with the message. |
| 761 * On success, the original message and message length will be stored in |
| 762 * output and outputLen. |
| 763 */ |
| 764 static SECStatus |
| 765 eme_oaep_decode(unsigned char *output, unsigned int *outputLen, |
| 766 unsigned int maxOutputLen, |
| 767 const unsigned char *input, unsigned int inputLen, |
| 768 HASH_HashType hashAlg, HASH_HashType maskHashAlg, |
| 769 const unsigned char *label, unsigned int labelLen) |
| 770 { |
| 771 const SECHashObject *hash; |
| 772 void *hashContext; |
| 773 SECStatus rv = SECFailure; |
| 774 unsigned char labelHash[HASH_LENGTH_MAX]; |
| 775 unsigned int i, maskLen, paddingOffset; |
| 776 unsigned char *mask = NULL, *tmpOutput = NULL; |
| 777 unsigned char isGood, foundPaddingEnd; |
| 778 |
| 779 hash = HASH_GetRawHashObject(hashAlg); |
| 780 |
| 781 /* 1.c */ |
| 782 if (inputLen < (hash->length * 2) + 2) { |
| 783 PORT_SetError(SEC_ERROR_INPUT_LEN); |
| 784 return SECFailure; |
| 785 } |
| 786 |
| 787 /* Step 3.a - Generate lHash */ |
| 788 hashContext = (*hash->create)(); |
| 789 if (hashContext == NULL) { |
| 790 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 791 return SECFailure; |
| 792 } |
| 793 (*hash->begin)(hashContext); |
| 794 if (labelLen > 0) |
| 795 (*hash->update)(hashContext, label, labelLen); |
| 796 (*hash->end)(hashContext, labelHash, &i, sizeof(labelHash)); |
| 797 (*hash->destroy)(hashContext, PR_TRUE); |
| 798 |
| 799 tmpOutput = (unsigned char*)PORT_Alloc(inputLen); |
| 800 if (tmpOutput == NULL) { |
| 801 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 802 goto done; |
| 803 } |
| 804 |
| 805 maskLen = inputLen - hash->length - 1; |
| 806 mask = (unsigned char*)PORT_Alloc(maskLen); |
| 807 if (mask == NULL) { |
| 808 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 809 goto done; |
| 810 } |
| 811 |
| 812 PORT_Memcpy(tmpOutput, input, inputLen); |
| 813 |
| 814 /* 3.c - Generate seedMask */ |
| 815 MGF1(maskHashAlg, mask, hash->length, &tmpOutput[1 + hash->length], |
| 816 inputLen - hash->length - 1); |
| 817 /* 3.d - Unmask seed */ |
| 818 for (i = 0; i < hash->length; ++i) |
| 819 tmpOutput[1 + i] ^= mask[i]; |
| 820 |
| 821 /* 3.e - Generate dbMask */ |
| 822 MGF1(maskHashAlg, mask, maskLen, &tmpOutput[1], hash->length); |
| 823 /* 3.f - Unmask DB */ |
| 824 for (i = 0; i < maskLen; ++i) |
| 825 tmpOutput[1 + hash->length + i] ^= mask[i]; |
| 826 |
| 827 /* 3.g - Compare Y, lHash, and PS in constant time |
| 828 * Warning: This code is timing dependent and must not disclose which of |
| 829 * these were invalid. |
| 830 */ |
| 831 paddingOffset = 0; |
| 832 isGood = 1; |
| 833 foundPaddingEnd = 0; |
| 834 |
| 835 /* Compare Y */ |
| 836 isGood &= constantTimeEQ8(0x00, tmpOutput[0]); |
| 837 |
| 838 /* Compare lHash and lHash' */ |
| 839 isGood &= constantTimeCompare(&labelHash[0], |
| 840 &tmpOutput[1 + hash->length], |
| 841 hash->length); |
| 842 |
| 843 /* Compare that the padding is zero or more zero octets, followed by a |
| 844 * 0x01 octet */ |
| 845 for (i = 1 + (hash->length * 2); i < inputLen; ++i) { |
| 846 unsigned char isZero = constantTimeEQ8(0x00, tmpOutput[i]); |
| 847 unsigned char isOne = constantTimeEQ8(0x01, tmpOutput[i]); |
| 848 /* non-constant time equivalent: |
| 849 * if (tmpOutput[i] == 0x01 && !foundPaddingEnd) |
| 850 * paddingOffset = i; |
| 851 */ |
| 852 paddingOffset = constantTimeCondition(isOne & ~foundPaddingEnd, i, |
| 853 paddingOffset); |
| 854 /* non-constant time equivalent: |
| 855 * if (tmpOutput[i] == 0x01) |
| 856 * foundPaddingEnd = true; |
| 857 * |
| 858 * Note: This may yield false positives, as it will be set whenever |
| 859 * a 0x01 byte is encountered. If there was bad padding (eg: |
| 860 * 0x03 0x02 0x01), foundPaddingEnd will still be set to true, and |
| 861 * paddingOffset will still be set to 2. |
| 862 */ |
| 863 foundPaddingEnd = constantTimeCondition(isOne, 1, foundPaddingEnd); |
| 864 /* non-constant time equivalent: |
| 865 * if (tmpOutput[i] != 0x00 && tmpOutput[i] != 0x01 && |
| 866 * !foundPaddingEnd) { |
| 867 * isGood = false; |
| 868 * } |
| 869 * |
| 870 * Note: This may yield false positives, as a message (and padding) |
| 871 * that is entirely zeros will result in isGood still being true. Thus |
| 872 * it's necessary to check foundPaddingEnd is positive below. |
| 873 */ |
| 874 isGood = constantTimeCondition(~foundPaddingEnd & ~isZero, 0, isGood); |
| 875 } |
| 876 |
| 877 /* While both isGood and foundPaddingEnd may have false positives, they |
| 878 * cannot BOTH have false positives. If both are not true, then an invalid |
| 879 * message was received. Note, this comparison must still be done in constan
t |
| 880 * time so as not to leak either condition. |
| 881 */ |
| 882 if (!(isGood & foundPaddingEnd)) { |
| 883 PORT_SetError(SEC_ERROR_BAD_DATA); |
| 884 goto done; |
| 885 } |
| 886 |
| 887 /* End timing dependent code */ |
| 888 |
| 889 ++paddingOffset; /* Skip the 0x01 following the end of PS */ |
| 890 |
| 891 *outputLen = inputLen - paddingOffset; |
| 892 if (*outputLen > maxOutputLen) { |
| 893 PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
| 894 goto done; |
| 895 } |
| 896 |
| 897 if (*outputLen) |
| 898 PORT_Memcpy(output, &tmpOutput[paddingOffset], *outputLen); |
| 899 rv = SECSuccess; |
| 900 |
| 901 done: |
| 902 if (mask) |
| 903 PORT_ZFree(mask, maskLen); |
| 904 if (tmpOutput) |
| 905 PORT_ZFree(tmpOutput, inputLen); |
| 906 return rv; |
| 907 } |
| 908 |
| 909 /* |
| 910 * Generate an EME-OAEP encoded block for encryption |
| 911 * Described in RFC 3447, section 7.1.1 |
| 912 * We use input instead of M for the message to be encrypted |
| 913 * label is the optional value L to be associated with the message. |
| 914 */ |
| 915 static SECStatus |
| 916 eme_oaep_encode(unsigned char *em, unsigned int emLen, |
| 917 const unsigned char *input, unsigned int inputLen, |
| 918 HASH_HashType hashAlg, HASH_HashType maskHashAlg, |
| 919 const unsigned char *label, unsigned int labelLen) |
| 920 { |
| 921 const SECHashObject *hash; |
| 922 void *hashContext; |
| 923 SECStatus rv; |
| 924 unsigned char *mask; |
| 925 unsigned int reservedLen, dbMaskLen, i; |
| 926 |
| 927 hash = HASH_GetRawHashObject(hashAlg); |
| 928 |
| 929 /* Step 1.b */ |
| 930 reservedLen = (2 * hash->length) + 2; |
| 931 if (emLen < reservedLen || inputLen > (emLen - reservedLen)) { |
| 932 PORT_SetError(SEC_ERROR_INPUT_LEN); |
| 933 return SECFailure; |
| 934 } |
| 935 |
| 936 /* |
| 937 * From RFC 3447, Section 7.1 |
| 938 * +----------+---------+-------+ |
| 939 * DB = | lHash | PS | M | |
| 940 * +----------+---------+-------+ |
| 941 * | |
| 942 * +----------+ V |
| 943 * | seed |--> MGF ---> xor |
| 944 * +----------+ | |
| 945 * | | |
| 946 * +--+ V | |
| 947 * |00| xor <----- MGF <-----| |
| 948 * +--+ | | |
| 949 * | | | |
| 950 * V V V |
| 951 * +--+----------+----------------------------+ |
| 952 * EM = |00|maskedSeed| maskedDB | |
| 953 * +--+----------+----------------------------+ |
| 954 * |
| 955 * We use mask to hold the result of the MGF functions, and all other |
| 956 * values are generated in their final resting place. |
| 957 */ |
| 958 *em = 0x00; |
| 959 |
| 960 /* Step 2.a - Generate lHash */ |
| 961 hashContext = (*hash->create)(); |
| 962 if (hashContext == NULL) { |
| 963 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 964 return SECFailure; |
| 965 } |
| 966 (*hash->begin)(hashContext); |
| 967 if (labelLen > 0) |
| 968 (*hash->update)(hashContext, label, labelLen); |
| 969 (*hash->end)(hashContext, &em[1 + hash->length], &i, hash->length); |
| 970 (*hash->destroy)(hashContext, PR_TRUE); |
| 971 |
| 972 /* Step 2.b - Generate PS */ |
| 973 if (emLen - reservedLen - inputLen > 0) { |
| 974 PORT_Memset(em + 1 + (hash->length * 2), 0x00, |
| 975 emLen - reservedLen - inputLen); |
| 976 } |
| 977 |
| 978 /* Step 2.c. - Generate DB |
| 979 * DB = lHash || PS || 0x01 || M |
| 980 * Note that PS and lHash have already been placed into em at their |
| 981 * appropriate offsets. This just copies M into place |
| 982 */ |
| 983 em[emLen - inputLen - 1] = 0x01; |
| 984 if (inputLen) |
| 985 PORT_Memcpy(em + emLen - inputLen, input, inputLen); |
| 986 |
| 987 /* Step 2.d - Generate seed */ |
| 988 rv = RNG_GenerateGlobalRandomBytes(em + 1, hash->length); |
| 989 if (rv != SECSuccess) { |
| 990 return rv; |
| 991 } |
| 992 |
| 993 /* Step 2.e - Generate dbMask*/ |
| 994 dbMaskLen = emLen - hash->length - 1; |
| 995 mask = (unsigned char*)PORT_Alloc(dbMaskLen); |
| 996 if (mask == NULL) { |
| 997 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 998 return SECFailure; |
| 999 } |
| 1000 MGF1(maskHashAlg, mask, dbMaskLen, em + 1, hash->length); |
| 1001 /* Step 2.f - Compute maskedDB*/ |
| 1002 for (i = 0; i < dbMaskLen; ++i) |
| 1003 em[1 + hash->length + i] ^= mask[i]; |
| 1004 |
| 1005 /* Step 2.g - Generate seedMask */ |
| 1006 MGF1(maskHashAlg, mask, hash->length, &em[1 + hash->length], dbMaskLen); |
| 1007 /* Step 2.h - Compute maskedSeed */ |
| 1008 for (i = 0; i < hash->length; ++i) |
| 1009 em[1 + i] ^= mask[i]; |
| 1010 |
| 1011 PORT_ZFree(mask, dbMaskLen); |
| 1012 return SECSuccess; |
| 1013 } |
| 1014 |
| 1015 /* |
962 * Encode a RSA-PSS signature. | 1016 * Encode a RSA-PSS signature. |
963 * Described in RFC 3447, section 9.1.1. | 1017 * Described in RFC 3447, section 9.1.1. |
964 * We use mHash instead of M as input. | 1018 * We use mHash instead of M as input. |
965 * emBits from the RFC is just modBits - 1, see section 8.1.1. | 1019 * emBits from the RFC is just modBits - 1, see section 8.1.1. |
966 * We only support MGF1 as the MGF. | 1020 * We only support MGF1 as the MGF. |
967 * | 1021 * |
968 * NOTE: this code assumes modBits is a multiple of 8. | 1022 * NOTE: this code assumes modBits is a multiple of 8. |
969 */ | 1023 */ |
970 static SECStatus | 1024 static SECStatus |
971 emsa_pss_encode(unsigned char *em, unsigned int emLen, | 1025 emsa_pss_encode(unsigned char *em, unsigned int emLen, |
(...skipping 29 matching lines...) Expand all Loading... |
1001 return SECFailure; | 1055 return SECFailure; |
1002 } | 1056 } |
1003 (*hash->begin)(hash_context); | 1057 (*hash->begin)(hash_context); |
1004 (*hash->update)(hash_context, eightZeros, 8); | 1058 (*hash->update)(hash_context, eightZeros, 8); |
1005 (*hash->update)(hash_context, mHash, hash->length); | 1059 (*hash->update)(hash_context, mHash, hash->length); |
1006 (*hash->update)(hash_context, &em[dbMaskLen - sLen], sLen); | 1060 (*hash->update)(hash_context, &em[dbMaskLen - sLen], sLen); |
1007 (*hash->end)(hash_context, &em[dbMaskLen], &i, hash->length); | 1061 (*hash->end)(hash_context, &em[dbMaskLen], &i, hash->length); |
1008 (*hash->destroy)(hash_context, PR_TRUE); | 1062 (*hash->destroy)(hash_context, PR_TRUE); |
1009 | 1063 |
1010 /* Step 7 + 8 */ | 1064 /* Step 7 + 8 */ |
1011 memset(em, 0, dbMaskLen - sLen - 1); | 1065 PORT_Memset(em, 0, dbMaskLen - sLen - 1); |
1012 em[dbMaskLen - sLen - 1] = 0x01; | 1066 em[dbMaskLen - sLen - 1] = 0x01; |
1013 | 1067 |
1014 /* Step 9 */ | 1068 /* Step 9 */ |
1015 dbMask = (unsigned char *)PORT_Alloc(dbMaskLen); | 1069 dbMask = (unsigned char *)PORT_Alloc(dbMaskLen); |
1016 if (dbMask == NULL) { | 1070 if (dbMask == NULL) { |
1017 PORT_SetError(SEC_ERROR_NO_MEMORY); | 1071 PORT_SetError(SEC_ERROR_NO_MEMORY); |
1018 return SECFailure; | 1072 return SECFailure; |
1019 } | 1073 } |
1020 MGF1(maskHashAlg, dbMask, dbMaskLen, &em[dbMaskLen], hash->length); | 1074 MGF1(maskHashAlg, dbMask, dbMaskLen, &em[dbMaskLen], hash->length); |
1021 | 1075 |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1244 rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output, pss_encoded); | 1298 rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, output, pss_encoded); |
1245 if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { | 1299 if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
1246 sftk_fatalError = PR_TRUE; | 1300 sftk_fatalError = PR_TRUE; |
1247 } | 1301 } |
1248 *output_len = modulus_len; | 1302 *output_len = modulus_len; |
1249 | 1303 |
1250 done: | 1304 done: |
1251 PORT_Free(pss_encoded); | 1305 PORT_Free(pss_encoded); |
1252 return rv; | 1306 return rv; |
1253 } | 1307 } |
| 1308 |
| 1309 /* MGF1 is the only supported MGF. */ |
| 1310 SECStatus |
| 1311 RSA_EncryptOAEP(CK_RSA_PKCS_OAEP_PARAMS *oaepParams, |
| 1312 NSSLOWKEYPublicKey *key, |
| 1313 unsigned char *output, unsigned int *outputLen, |
| 1314 unsigned int maxOutputLen, |
| 1315 const unsigned char *input, unsigned int inputLen) |
| 1316 { |
| 1317 SECStatus rv = SECFailure; |
| 1318 unsigned int modulusLen = nsslowkey_PublicModulusLen(key); |
| 1319 unsigned char *oaepEncoded = NULL; |
| 1320 unsigned char *sourceData = NULL; |
| 1321 unsigned int sourceDataLen = 0; |
| 1322 |
| 1323 HASH_HashType hashAlg; |
| 1324 HASH_HashType maskHashAlg; |
| 1325 |
| 1326 if (maxOutputLen < modulusLen) { |
| 1327 PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
| 1328 return SECFailure; |
| 1329 } |
| 1330 PORT_Assert(key->keyType == NSSLOWKEYRSAKey); |
| 1331 if (key->keyType != NSSLOWKEYRSAKey) { |
| 1332 PORT_SetError(SEC_ERROR_INVALID_KEY); |
| 1333 return SECFailure; |
| 1334 } |
| 1335 |
| 1336 hashAlg = GetHashTypeFromMechanism(oaepParams->hashAlg); |
| 1337 maskHashAlg = GetHashTypeFromMechanism(oaepParams->mgf); |
| 1338 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) { |
| 1339 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| 1340 return SECFailure; |
| 1341 } |
| 1342 |
| 1343 /* The PKCS#11 source parameter is the "source" of the label parameter. |
| 1344 * The only defined source is explicitly specified, in which case, the |
| 1345 * label is an optional byte string in pSourceData. If ulSourceDataLen is |
| 1346 * zero, then pSourceData MUST be NULL - otherwise, it must be non-NULL. |
| 1347 */ |
| 1348 if (oaepParams->source != CKZ_DATA_SPECIFIED) { |
| 1349 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| 1350 return SECFailure; |
| 1351 } |
| 1352 sourceData = (unsigned char*)oaepParams->pSourceData; |
| 1353 sourceDataLen = oaepParams->ulSourceDataLen; |
| 1354 if ((sourceDataLen == 0 && sourceData != NULL) || |
| 1355 (sourceDataLen > 0 && sourceData == NULL)) { |
| 1356 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| 1357 return SECFailure; |
| 1358 } |
| 1359 |
| 1360 oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen); |
| 1361 if (oaepEncoded == NULL) { |
| 1362 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1363 return SECFailure; |
| 1364 } |
| 1365 rv = eme_oaep_encode(oaepEncoded, modulusLen, input, inputLen, |
| 1366 hashAlg, maskHashAlg, sourceData, sourceDataLen); |
| 1367 if (rv != SECSuccess) |
| 1368 goto done; |
| 1369 |
| 1370 rv = RSA_PublicKeyOp(&key->u.rsa, output, oaepEncoded); |
| 1371 if (rv != SECSuccess) |
| 1372 goto done; |
| 1373 *outputLen = modulusLen; |
| 1374 |
| 1375 done: |
| 1376 PORT_Free(oaepEncoded); |
| 1377 return rv; |
| 1378 } |
| 1379 |
| 1380 /* MGF1 is the only supported MGF. */ |
| 1381 SECStatus |
| 1382 RSA_DecryptOAEP(CK_RSA_PKCS_OAEP_PARAMS *oaepParams, |
| 1383 NSSLOWKEYPrivateKey *key, |
| 1384 unsigned char *output, unsigned int *outputLen, |
| 1385 unsigned int maxOutputLen, |
| 1386 const unsigned char *input, unsigned int inputLen) |
| 1387 { |
| 1388 SECStatus rv = SECFailure; |
| 1389 unsigned int modulusLen = nsslowkey_PrivateModulusLen(key); |
| 1390 unsigned char *oaepEncoded = NULL; |
| 1391 unsigned char *sourceData = NULL; |
| 1392 unsigned int sourceDataLen = 0; |
| 1393 |
| 1394 HASH_HashType hashAlg = GetHashTypeFromMechanism(oaepParams->hashAlg); |
| 1395 HASH_HashType maskHashAlg = GetHashTypeFromMechanism(oaepParams->mgf); |
| 1396 |
| 1397 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) { |
| 1398 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| 1399 return SECFailure; |
| 1400 } |
| 1401 |
| 1402 if (inputLen != modulusLen) { |
| 1403 PORT_SetError(SEC_ERROR_INPUT_LEN); |
| 1404 return SECFailure; |
| 1405 } |
| 1406 PORT_Assert(key->keyType == NSSLOWKEYRSAKey); |
| 1407 if (key->keyType != NSSLOWKEYRSAKey) { |
| 1408 PORT_SetError(SEC_ERROR_INVALID_KEY); |
| 1409 return SECFailure; |
| 1410 } |
| 1411 |
| 1412 /* The PKCS#11 source parameter is the "source" of the label parameter. |
| 1413 * The only defined source is explicitly specified, in which case, the |
| 1414 * label is an optional byte string in pSourceData. If ulSourceDataLen is |
| 1415 * zero, then pSourceData MUST be NULL - otherwise, it must be non-NULL. |
| 1416 */ |
| 1417 if (oaepParams->source != CKZ_DATA_SPECIFIED) { |
| 1418 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| 1419 return SECFailure; |
| 1420 } |
| 1421 sourceData = (unsigned char*)oaepParams->pSourceData; |
| 1422 sourceDataLen = oaepParams->ulSourceDataLen; |
| 1423 if ((sourceDataLen == 0 && sourceData != NULL) || |
| 1424 (sourceDataLen > 0 && sourceData == NULL)) { |
| 1425 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| 1426 return SECFailure; |
| 1427 } |
| 1428 |
| 1429 oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen); |
| 1430 if (oaepEncoded == NULL) { |
| 1431 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1432 return SECFailure; |
| 1433 } |
| 1434 |
| 1435 rv = RSA_PrivateKeyOpDoubleChecked(&key->u.rsa, oaepEncoded, input); |
| 1436 if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
| 1437 sftk_fatalError = PR_TRUE; |
| 1438 goto done; |
| 1439 } |
| 1440 |
| 1441 rv = eme_oaep_decode(output, outputLen, maxOutputLen, oaepEncoded, |
| 1442 modulusLen, hashAlg, maskHashAlg, sourceData, |
| 1443 sourceDataLen); |
| 1444 |
| 1445 done: |
| 1446 if (oaepEncoded) |
| 1447 PORT_ZFree(oaepEncoded, modulusLen); |
| 1448 return rv; |
| 1449 } |
OLD | NEW |