OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * PKCS#1 encoding and decoding functions. |
| 3 * This file is believed to contain no code licensed from other parties. |
| 4 * |
| 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 |
| 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 8 |
| 9 #include "seccomon.h" |
| 10 #include "secerr.h" |
| 11 #include "sechash.h" |
| 12 |
| 13 /* Needed for RSA-PSS functions */ |
| 14 static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 15 |
| 16 /* |
| 17 * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447. |
| 18 */ |
| 19 static SECStatus |
| 20 MGF1(HASH_HashType hashAlg, unsigned char *mask, unsigned int maskLen, |
| 21 const unsigned char *mgfSeed, unsigned int mgfSeedLen) |
| 22 { |
| 23 unsigned int digestLen; |
| 24 PRUint32 counter, rounds; |
| 25 unsigned char *tempHash, *temp; |
| 26 const SECHashObject *hash; |
| 27 void *hashContext; |
| 28 unsigned char C[4]; |
| 29 |
| 30 hash = HASH_GetHashObject(hashAlg); |
| 31 if (hash == NULL) |
| 32 return SECFailure; |
| 33 |
| 34 hashContext = (*hash->create)(); |
| 35 rounds = (maskLen + hash->length - 1) / hash->length; |
| 36 for (counter = 0; counter < rounds; counter++) { |
| 37 C[0] = (unsigned char)((counter >> 24) & 0xff); |
| 38 C[1] = (unsigned char)((counter >> 16) & 0xff); |
| 39 C[2] = (unsigned char)((counter >> 8) & 0xff); |
| 40 C[3] = (unsigned char)(counter & 0xff); |
| 41 |
| 42 /* This could be optimized when the clone functions in |
| 43 * rawhash.c are implemented. */ |
| 44 (*hash->begin)(hashContext); |
| 45 (*hash->update)(hashContext, mgfSeed, mgfSeedLen); |
| 46 (*hash->update)(hashContext, C, sizeof C); |
| 47 |
| 48 tempHash = mask + counter * hash->length; |
| 49 if (counter != (rounds-1)) { |
| 50 (*hash->end)(hashContext, tempHash, &digestLen, hash->length); |
| 51 } else { /* we're in the last round and need to cut the hash */ |
| 52 temp = (unsigned char *)PORT_Alloc(hash->length); |
| 53 (*hash->end)(hashContext, temp, &digestLen, hash->length); |
| 54 PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length); |
| 55 PORT_Free(temp); |
| 56 } |
| 57 } |
| 58 (*hash->destroy)(hashContext, PR_TRUE); |
| 59 |
| 60 return SECSuccess; |
| 61 } |
| 62 |
| 63 /* |
| 64 * Verify a RSA-PSS signature. |
| 65 * Described in RFC 3447, section 9.1.2. |
| 66 * We use mHash instead of M as input. |
| 67 * emBits from the RFC is just modBits - 1, see section 8.1.2. |
| 68 * We only support MGF1 as the MGF. |
| 69 * |
| 70 * NOTE: this code assumes modBits is a multiple of 8. |
| 71 */ |
| 72 SECStatus |
| 73 emsa_pss_verify(const unsigned char *mHash, |
| 74 const unsigned char *em, unsigned int emLen, |
| 75 HASH_HashType hashAlg, HASH_HashType maskHashAlg, |
| 76 unsigned int sLen) |
| 77 { |
| 78 const SECHashObject *hash; |
| 79 void *hash_context; |
| 80 unsigned char *db; |
| 81 unsigned char *H_; /* H' from the RFC */ |
| 82 unsigned int i, dbMaskLen; |
| 83 SECStatus rv; |
| 84 |
| 85 hash = HASH_GetHashObject(hashAlg); |
| 86 dbMaskLen = emLen - hash->length - 1; |
| 87 |
| 88 /* Step 3 + 4 + 6 */ |
| 89 if ((emLen < (hash->length + sLen + 2)) || |
| 90 (em[emLen - 1] != 0xbc) || |
| 91 ((em[0] & 0x80) != 0)) { |
| 92 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
| 93 return SECFailure; |
| 94 } |
| 95 |
| 96 /* Step 7 */ |
| 97 db = (unsigned char *)PORT_Alloc(dbMaskLen); |
| 98 if (db == NULL) { |
| 99 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 100 return SECFailure; |
| 101 } |
| 102 /* &em[dbMaskLen] points to H, used as mgfSeed */ |
| 103 MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length); |
| 104 |
| 105 /* Step 8 */ |
| 106 for (i = 0; i < dbMaskLen; i++) { |
| 107 db[i] ^= em[i]; |
| 108 } |
| 109 |
| 110 /* Step 9 */ |
| 111 db[0] &= 0x7f; |
| 112 |
| 113 /* Step 10 */ |
| 114 for (i = 0; i < (dbMaskLen - sLen - 1); i++) { |
| 115 if (db[i] != 0) { |
| 116 PORT_Free(db); |
| 117 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
| 118 return SECFailure; |
| 119 } |
| 120 } |
| 121 if (db[dbMaskLen - sLen - 1] != 0x01) { |
| 122 PORT_Free(db); |
| 123 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
| 124 return SECFailure; |
| 125 } |
| 126 |
| 127 /* Step 12 + 13 */ |
| 128 H_ = (unsigned char *)PORT_Alloc(hash->length); |
| 129 if (H_ == NULL) { |
| 130 PORT_Free(db); |
| 131 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 132 return SECFailure; |
| 133 } |
| 134 hash_context = (*hash->create)(); |
| 135 if (hash_context == NULL) { |
| 136 PORT_Free(db); |
| 137 PORT_Free(H_); |
| 138 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 139 return SECFailure; |
| 140 } |
| 141 (*hash->begin)(hash_context); |
| 142 (*hash->update)(hash_context, eightZeros, 8); |
| 143 (*hash->update)(hash_context, mHash, hash->length); |
| 144 (*hash->update)(hash_context, &db[dbMaskLen - sLen], sLen); |
| 145 (*hash->end)(hash_context, H_, &i, hash->length); |
| 146 (*hash->destroy)(hash_context, PR_TRUE); |
| 147 |
| 148 PORT_Free(db); |
| 149 |
| 150 /* Step 14 */ |
| 151 if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) { |
| 152 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
| 153 rv = SECFailure; |
| 154 } else { |
| 155 rv = SECSuccess; |
| 156 } |
| 157 |
| 158 PORT_Free(H_); |
| 159 return rv; |
| 160 } |
OLD | NEW |