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; |
+} |