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 } 161