| Index: crypto/third_party/nss/rsawrapr.c
|
| diff --git a/crypto/third_party/nss/rsawrapr.c b/crypto/third_party/nss/rsawrapr.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..73e498f937d1f02470a389d4075be7c2e7cc5e16
|
| --- /dev/null
|
| +++ b/crypto/third_party/nss/rsawrapr.c
|
| @@ -0,0 +1,160 @@
|
| +/*
|
| + * 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;
|
| +}
|
|
|