/* * PKCS#1 encoding and decoding functions. * This file is believed to contain no code licensed from other parties. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "seccomon.h" #include "secerr.h" #include "sechash.h" /* Needed for RSA-PSS functions */ static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447. */ static SECStatus MGF1(HASH_HashType hashAlg, unsigned char *mask, unsigned int maskLen, const unsigned char *mgfSeed, unsigned int mgfSeedLen) { unsigned int digestLen; PRUint32 counter, rounds; unsigned char *tempHash, *temp; const SECHashObject *hash; void *hashContext; unsigned char C[4]; hash = HASH_GetHashObject(hashAlg); if (hash == NULL) return SECFailure; hashContext = (*hash->create)(); rounds = (maskLen + hash->length - 1) / hash->length; for (counter = 0; counter < rounds; counter++) { C[0] = (unsigned char)((counter >> 24) & 0xff); C[1] = (unsigned char)((counter >> 16) & 0xff); C[2] = (unsigned char)((counter >> 8) & 0xff); C[3] = (unsigned char)(counter & 0xff); /* This could be optimized when the clone functions in * rawhash.c are implemented. */ (*hash->begin)(hashContext); (*hash->update)(hashContext, mgfSeed, mgfSeedLen); (*hash->update)(hashContext, C, sizeof C); tempHash = mask + counter * hash->length; if (counter != (rounds-1)) { (*hash->end)(hashContext, tempHash, &digestLen, hash->length); } else { /* we're in the last round and need to cut the hash */ temp = (unsigned char *)PORT_Alloc(hash->length); (*hash->end)(hashContext, temp, &digestLen, hash->length); PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length); PORT_Free(temp); } } (*hash->destroy)(hashContext, PR_TRUE); return SECSuccess; } /* * Verify a RSA-PSS signature. * Described in RFC 3447, section 9.1.2. * We use mHash instead of M as input. * emBits from the RFC is just modBits - 1, see section 8.1.2. * We only support MGF1 as the MGF. * * NOTE: this code assumes modBits is a multiple of 8. */ SECStatus emsa_pss_verify(const unsigned char *mHash, const unsigned char *em, unsigned int emLen, HASH_HashType hashAlg, HASH_HashType maskHashAlg, unsigned int sLen) { const SECHashObject *hash; void *hash_context; unsigned char *db; unsigned char *H_; /* H' from the RFC */ unsigned int i, dbMaskLen; SECStatus rv; hash = HASH_GetHashObject(hashAlg); dbMaskLen = emLen - hash->length - 1; /* Step 3 + 4 + 6 */ if ((emLen < (hash->length + sLen + 2)) || (em[emLen - 1] != 0xbc) || ((em[0] & 0x80) != 0)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; } /* Step 7 */ db = (unsigned char *)PORT_Alloc(dbMaskLen); if (db == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } /* &em[dbMaskLen] points to H, used as mgfSeed */ MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length); /* Step 8 */ for (i = 0; i < dbMaskLen; i++) { db[i] ^= em[i]; } /* Step 9 */ db[0] &= 0x7f; /* Step 10 */ for (i = 0; i < (dbMaskLen - sLen - 1); i++) { if (db[i] != 0) { PORT_Free(db); PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; } } if (db[dbMaskLen - sLen - 1] != 0x01) { PORT_Free(db); PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; } /* Step 12 + 13 */ H_ = (unsigned char *)PORT_Alloc(hash->length); if (H_ == NULL) { PORT_Free(db); PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } hash_context = (*hash->create)(); if (hash_context == NULL) { PORT_Free(db); PORT_Free(H_); PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } (*hash->begin)(hash_context); (*hash->update)(hash_context, eightZeros, 8); (*hash->update)(hash_context, mHash, hash->length); (*hash->update)(hash_context, &db[dbMaskLen - sLen], sLen); (*hash->end)(hash_context, H_, &i, hash->length); (*hash->destroy)(hash_context, PR_TRUE); PORT_Free(db); /* Step 14 */ if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); rv = SECFailure; } else { rv = SECSuccess; } PORT_Free(H_); return rv; }