diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/cryptohi/cryptohi.h verify/security/nss//lib/cryptohi/cryptohi.h --- vanilla/security/nss//lib/cryptohi/cryptohi.h 2010-02-10 01:49:43.000000000 +0100 +++ verify/security/nss//lib/cryptohi/cryptohi.h 2010-08-01 00:58:43.703787248 +0200 @@ -396,6 +396,9 @@ const SECAlgorithmID *algid, SECOidTag *hash, void *wincx); +extern SECStatus +PSSU_DecodeDERPSSParams(CK_RSA_PKCS_PSS_PARAMS *dest, SECOidTag *hashAlg, + const SECItem *in); SEC_END_PROTOS diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/cryptohi/keyi.h verify/security/nss//lib/cryptohi/keyi.h --- vanilla/security/nss//lib/cryptohi/keyi.h 2006-02-08 07:14:07.000000000 +0100 +++ verify/security/nss//lib/cryptohi/keyi.h 2010-08-01 00:21:16.340119128 +0200 @@ -50,7 +50,8 @@ * algorithm, key and parameters (parameters is the parameters field * of a algorithm ID structure (SECAlgorithmID)*/ SECStatus sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, - const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg); + const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg, + void **outparam); SEC_END_PROTOS diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/cryptohi/manifest.mn verify/security/nss//lib/cryptohi/manifest.mn --- vanilla/security/nss//lib/cryptohi/manifest.mn 2008-12-17 22:38:44.000000000 +0100 +++ verify/security/nss//lib/cryptohi/manifest.mn 2010-08-01 00:21:16.346119098 +0200 @@ -60,6 +60,7 @@ secsign.c \ secvfy.c \ dsautil.c \ + pssutil.c \ $(NULL) CSRCS = $(LIBSRCS) diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/cryptohi/pssutil.c verify/security/nss//lib/cryptohi/pssutil.c --- vanilla/security/nss//lib/cryptohi/pssutil.c 1970-01-01 01:00:00.000000000 +0100 +++ verify/security/nss//lib/cryptohi/pssutil.c 2010-08-01 00:24:29.630168560 +0200 @@ -0,0 +1,163 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Hanno Boeck + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "cryptohi.h" +#include "secasn1.h" +#include "secitem.h" +#include "secder.h" +#include "secerr.h" +#include "pkcs11t.h" +#include "pk11pub.h" + +/* +** Decode a DER encoded RSA-PSS parameter block to a PKCS #11 structure +** and get OID tag of hash algorithm. The latter can be NULL if it's +** not needed +*/ +SECStatus +PSSU_DecodeDERPSSParams(CK_RSA_PKCS_PSS_PARAMS *dest, SECOidTag *hashAlg, + const SECItem *in) +{ + SECKEYRSAPSSParams pss_params; + PRArenaPool *arena; + SECStatus rv; + SECAlgorithmID algId; + SECOidTag oid; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + PORT_Memset(&pss_params, 0, sizeof pss_params); + rv = SEC_QuickDERDecodeItem(arena, &pss_params, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), + in); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto finish; + } + + /* Hash algorithm */ + if (pss_params.hashAlg) { + oid = SECOID_FindOIDTag(&pss_params.hashAlg->algorithm); + } else { + oid = SEC_OID_SHA1; + } + if (hashAlg!=NULL) { + *hashAlg = oid; + } + + if (dest == NULL) { + rv = SECSuccess; + goto finish; + } + + dest->hashAlg = PK11_AlgtagToMechanism(oid); + + /* According to RFC 4055, only five algorithms supported */ + if ((dest->hashAlg != CKM_SHA_1) && (dest->hashAlg != CKM_SHA256) && + (dest->hashAlg != CKM_SHA384) && (dest->hashAlg != CKM_SHA512) && + (dest->hashAlg != CKM_SHA224)) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + rv = SECFailure; + goto finish; + } + + /* Mask Generation Function */ + if (pss_params.maskAlg) { + if (SECOID_FindOIDTag(&pss_params.maskAlg->algorithm) + != SEC_OID_PKCS1_MGF1) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + rv = SECFailure; + goto finish; + }; + rv = SEC_QuickDERDecodeItem(arena, &algId, + SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), + &pss_params.maskAlg->parameters); + if (rv != SECSuccess) { + PORT_FreeArena(arena, PR_FALSE); + rv = SECFailure; + goto finish; + } + switch (SECOID_FindOIDTag(&algId.algorithm)) { + case SEC_OID_SHA1: + dest->mgf = CKG_MGF1_SHA1; + break; + case SEC_OID_SHA256: + dest->mgf = CKG_MGF1_SHA256; + break; + case SEC_OID_SHA384: + dest->mgf = CKG_MGF1_SHA384; + break; + case SEC_OID_SHA512: + dest->mgf = CKG_MGF1_SHA512; + break; + case SEC_OID_SHA224: + dest->mgf = CKG_MGF1_SHA224; + break; + default: + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + rv = SECFailure; + goto finish; + } + } else { + dest->mgf = CKG_MGF1_SHA1; + } + + /* Salt length */ + if (pss_params.saltLength.len > 0) { + dest->sLen = DER_GetInteger(&pss_params.saltLength); + } else { + dest->sLen = 20; + } + + /* Trailer field (must be absent or 1) */ + if (pss_params.trailerField.len > 0) { + if (DER_GetInteger(&pss_params.trailerField) != 1) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; + goto finish; + } + } + + rv = SECSuccess; + +finish: + PORT_FreeArena(arena, PR_FALSE); + + return rv; +} diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/cryptohi/secsign.c verify/security/nss//lib/cryptohi/secsign.c --- vanilla/security/nss//lib/cryptohi/secsign.c 2010-02-10 01:49:43.000000000 +0100 +++ verify/security/nss//lib/cryptohi/secsign.c 2010-08-01 00:22:21.992795004 +0200 @@ -74,7 +74,7 @@ * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5. */ /* we have a private key, not a public key, so don't pass it in */ - rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg); + rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg, NULL); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return 0; diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/cryptohi/secvfy.c verify/security/nss//lib/cryptohi/secvfy.c --- vanilla/security/nss//lib/cryptohi/secvfy.c 2010-06-23 04:13:56.000000000 +0200 +++ verify/security/nss//lib/cryptohi/secvfy.c 2010-08-01 00:31:49.957040335 +0200 @@ -139,12 +139,15 @@ unsigned char dsasig[DSA_SIGNATURE_LEN]; /* the full ECDSA signature */ unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; + /* a RSA-PSS signature */ + unsigned char pssdigest[4096/8]; } u; unsigned int rsadigestlen; void * wincx; void *hashcx; const SECHashObject *hashobj; SECOidTag encAlg; /* enc alg */ + void *params; PRBool hasSignature; /* true if the signature was provided in the * VFY_CreateContext call. If false, the * signature must be provided with a @@ -213,12 +216,14 @@ */ SECStatus sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, - const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg) + const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg, + void **outparam) { int len; PRArenaPool *arena; SECStatus rv; SECItem oid; + CK_RSA_PKCS_PSS_PARAMS *ck_pss; PR_ASSERT(hashalg!=NULL); PR_ASSERT(encalg!=NULL); @@ -237,10 +242,29 @@ *hashalg = SEC_OID_SHA1; break; case SEC_OID_PKCS1_RSA_ENCRYPTION: + *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ + break; case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: - *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ + if (param != NULL) { + if (outparam != NULL) { + *outparam = PORT_Alloc(sizeof(CK_RSA_PKCS_PSS_PARAMS)); + if (*outparam == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + rv = PSSU_DecodeDERPSSParams(*outparam, hashalg, param); + } else if (param == NULL) { + rv = PSSU_DecodeDERPSSParams(NULL, hashalg, param); + } + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + PORT_Free(*outparam); + return SECFailure; + } + } else { + hashalg = SEC_OID_UNKNOWN; + } break; - case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: *hashalg = SEC_OID_SHA256; @@ -360,6 +384,17 @@ return SECSuccess; } +static SECStatus +sec_KeyMatchAlg(KeyType key, KeyType alg) +{ + if ((key == alg) || + ((key == rsaKey) && (alg == rsaPssKey))) { + return SECSuccess; + } + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); + return SECFailure; +} + /* * we can verify signatures that come from 2 different sources: * one in with the signature contains a signature oid, and the other @@ -373,21 +408,19 @@ * in the RSA signature block. */ static VFYContext * -vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, - SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) +vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, + SECOidTag encAlg, SECOidTag hashAlg, void *params, SECOidTag *hash, + void *wincx) { VFYContext *cx; SECStatus rv; unsigned int sigLen; - KeyType type; + KeyType algKeyType; - /* make sure the encryption algorithm matches the key type */ - /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ - type = seckey_GetKeyType(encAlg); - if ((key->keyType != type) && - ((key->keyType != rsaKey) || (type != rsaPssKey))) { - PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); - return NULL; + algKeyType = seckey_GetKeyType(encAlg); + rv = sec_KeyMatchAlg(key->keyType, algKeyType); + if (rv != SECSuccess) { + goto loser; } cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); @@ -399,10 +432,11 @@ cx->hasSignature = (sig != NULL); cx->encAlg = encAlg; cx->hashAlg = hashAlg; + cx->params = params; cx->key = SECKEY_CopyPublicKey(key); rv = SECSuccess; if (sig) { - switch (type) { + switch (algKeyType) { case rsaKey: rv = DecryptSigBlock(&cx->hashAlg, cx->u.buffer, &cx->rsadigestlen, HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); @@ -411,6 +445,9 @@ rv = SECFailure; } break; + case rsaPssKey: + PORT_Memcpy(cx->u.buffer, sig->data, sig->len); + break; case dsaKey: case ecKey: sigLen = SECKEY_SignatureLen(key); @@ -453,11 +490,13 @@ void *wincx) { SECOidTag encAlg, hashAlg; - SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg); + void *params = NULL; + SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg, + ¶ms); if (rv != SECSuccess) { return NULL; } - return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); + return vfy_CreateContext(key, sig, encAlg, hashAlg, params, NULL, wincx); } VFYContext * @@ -465,7 +504,7 @@ SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) { - return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); + return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, hash, wincx); } VFYContext * @@ -473,13 +512,14 @@ const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx) { SECOidTag encAlg, hashAlg; + void *params = NULL; SECStatus rv = sec_DecodeSigAlg(key, SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), - &sigAlgorithm->parameters, &encAlg, &hashAlg); + &sigAlgorithm->parameters, &encAlg, &hashAlg, ¶ms); if (rv != SECSuccess) { return NULL; } - return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); + return vfy_CreateContext(key, sig, encAlg, hashAlg, params, hash, wincx); } void @@ -490,6 +530,9 @@ (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); cx->hashcx = NULL; } + if (cx->params != NULL) { + PORT_Free(cx->params); + } if (cx->key) { SECKEY_DestroyPublicKey(cx->key); } @@ -535,8 +578,15 @@ { unsigned char final[HASH_LENGTH_MAX]; unsigned part; - SECItem hash,dsasig; /* dsasig is also used for ECDSA */ + SECItem hash,dsasig; /* dsasig is used for DSA, ECDSA and RSA-PSS */ SECStatus rv; + KeyType algKeyType; + + algKeyType = seckey_GetKeyType(cx->encAlg); + rv = sec_KeyMatchAlg(cx->key->keyType, algKeyType); + if (rv != SECSuccess) { + return rv; + } if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -548,7 +598,7 @@ return SECFailure; } (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); - switch (cx->key->keyType) { + switch (algKeyType) { case ecKey: case dsaKey: dsasig.data = cx->u.buffer; @@ -587,6 +637,22 @@ return SECFailure; } break; + case rsaPssKey: + if (sig) { + PORT_Memcpy(cx->u.buffer, sig->data, sig->len); + } + dsasig.data = cx->u.buffer; + dsasig.len = SECKEY_SignatureLen(cx->key); + hash.data = final; + hash.len = part; + if (PK11_VerifyWithSigAlg(cx->key, &dsasig, &hash, + SEC_OID_PKCS1_RSA_PSS_SIGNATURE, cx->params, + sizeof(CK_RSA_PKCS_PSS_PARAMS), + cx->wincx) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + break; default: PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; /* shouldn't happen */ @@ -607,17 +673,24 @@ static SECStatus vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, - void *wincx) + void *params, void *wincx) { SECStatus rv; VFYContext *cx; - SECItem dsasig; /* also used for ECDSA */ + SECItem dsasig; /* used for DSA, ECDSA and RSA-PSS */ + KeyType algKeyType; + + algKeyType = seckey_GetKeyType(encAlg); + rv = sec_KeyMatchAlg(key->keyType, algKeyType); + if (rv != SECSuccess) { + return rv; + } rv = SECFailure; - cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); + cx = vfy_CreateContext(key, sig, encAlg, hashAlg, params, NULL, wincx); if (cx != NULL) { - switch (key->keyType) { + switch (algKeyType) { case rsaKey: if ((digest->len != cx->rsadigestlen) || PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) { @@ -640,6 +713,17 @@ rv = SECSuccess; } break; + case rsaPssKey: + dsasig.data = cx->u.buffer; + dsasig.len = SECKEY_SignatureLen(cx->key); + if (PK11_VerifyWithSigAlg(cx->key, &dsasig, digest, + SEC_OID_PKCS1_RSA_PSS_SIGNATURE, cx->params, + sizeof(CK_RSA_PKCS_PSS_PARAMS), + cx->wincx) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + break; default: break; } @@ -653,7 +737,7 @@ const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, void *wincx) { - return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); + return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, NULL, wincx); } SECStatus @@ -661,11 +745,13 @@ SECOidTag algid, void *wincx) { SECOidTag encAlg, hashAlg; - SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); + void *params = NULL; + SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg, + ¶ms); if (rv != SECSuccess) { return SECFailure; } - return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); + return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, params, wincx); } /* @@ -679,9 +765,10 @@ SECOidTag hashCmp, void *wincx) { SECOidTag encAlg, hashAlg; + void *params = NULL; SECStatus rv = sec_DecodeSigAlg(key, SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), - &sigAlgorithm->parameters, &encAlg, &hashAlg); + &sigAlgorithm->parameters, &encAlg, &hashAlg, ¶ms); if (rv != SECSuccess) { return rv; } @@ -691,18 +778,18 @@ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; } - return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); + return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, params, wincx); } static SECStatus vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, - SECOidTag *hash, void *wincx) + void *params, SECOidTag *hash, void *wincx) { SECStatus rv; VFYContext *cx; - cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); + cx = vfy_CreateContext(key, sig, encAlg, hashAlg, params, hash, wincx); if (cx == NULL) return SECFailure; @@ -717,13 +804,16 @@ return rv; } +/* This public API function is not able to verify */ +/* RSA-PSS signatures */ SECStatus VFY_VerifyDataDirect(const unsigned char *buf, int len, const SECKEYPublicKey *key, const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) { - return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); + return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, hash, + wincx); } SECStatus @@ -731,11 +821,14 @@ const SECItem *sig, SECOidTag algid, void *wincx) { SECOidTag encAlg, hashAlg; - SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); + void *params = NULL; + SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg, + ¶ms); if (rv != SECSuccess) { return rv; } - return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, wincx); + return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, params, NULL, + wincx); } SECStatus @@ -746,11 +839,14 @@ SECOidTag *hash, void *wincx) { SECOidTag encAlg, hashAlg; + void *params = NULL; SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm); SECStatus rv = sec_DecodeSigAlg(key, sigAlg, - &sigAlgorithm->parameters, &encAlg, &hashAlg); + &sigAlgorithm->parameters, &encAlg, &hashAlg, + ¶ms); if (rv != SECSuccess) { return rv; } - return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); + return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, params, hash, + wincx); } diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/freebl/hasht.h verify/security/nss//lib/freebl/hasht.h --- vanilla/security/nss//lib/freebl/hasht.h 2008-12-10 23:48:03.000000000 +0100 +++ verify/security/nss//lib/freebl/hasht.h 2010-08-01 00:21:16.349119083 +0200 @@ -57,6 +57,10 @@ HASH_AlgTOTAL } HASH_HashType; +typedef enum { + MGF_AlgMGF1 = 1 +} MGFType; + /* * Number of bytes each hash algorithm produces */ diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/pk11wrap/pk11obj.c verify/security/nss//lib/pk11wrap/pk11obj.c --- vanilla/security/nss//lib/pk11wrap/pk11obj.c 2009-02-16 04:47:21.000000000 +0100 +++ verify/security/nss//lib/pk11wrap/pk11obj.c 2010-08-01 00:21:16.350119078 +0200 @@ -686,6 +686,17 @@ SECStatus PK11_Verify(SECKEYPublicKey *key, SECItem *sig, SECItem *hash, void *wincx) { + return PK11_VerifyWithSigAlg(key, sig, hash, SEC_OID_UNKNOWN, NULL, 0, wincx); +} + +/* + * verify a signature from it's hash, specify mechanism and parameters + */ +SECStatus +PK11_VerifyWithSigAlg(SECKEYPublicKey *key, SECItem *sig, const SECItem *hash, + SECOidTag sigAlg, const void *sigParams, + unsigned int sigParamsLen, void *wincx) +{ PK11SlotInfo *slot = key->pkcs11Slot; CK_OBJECT_HANDLE id = key->pkcs11ID; CK_MECHANISM mech = {0, NULL, 0 }; @@ -693,17 +704,23 @@ CK_SESSION_HANDLE session; CK_RV crv; - mech.mechanism = PK11_MapSignKeyType(key->keyType); + if (sigAlg != SEC_OID_UNKNOWN) { + mech.mechanism = PK11_AlgtagToMechanism(sigAlg); + } else { + mech.mechanism = PK11_MapSignKeyType(key->keyType); + } + mech.pParameter = sigParams; + mech.ulParameterLen = sigParamsLen; if (slot == NULL) { slot = PK11_GetBestSlot(mech.mechanism,wincx); - + if (slot == NULL) { PORT_SetError( SEC_ERROR_NO_MODULE ); return SECFailure; } id = PK11_ImportPublicKey(slot,key,PR_FALSE); - + } else { PK11_ReferenceSlot(slot); } diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/pk11wrap/pk11pub.h verify/security/nss//lib/pk11wrap/pk11pub.h --- vanilla/security/nss//lib/pk11wrap/pk11pub.h 2010-04-26 01:37:39.000000000 +0200 +++ verify/security/nss//lib/pk11wrap/pk11pub.h 2010-08-01 00:21:16.352119068 +0200 @@ -666,6 +666,10 @@ SECItem *dsig, void * wincx); SECStatus PK11_Verify(SECKEYPublicKey *key, SECItem *sig, SECItem *hash, void *wincx); +SECStatus PK11_VerifyWithSigAlg(SECKEYPublicKey *key, SECItem *sig, + const SECItem *hash, SECOidTag sigAlg, + const void *mech_parameter, + unsigned int mech_parameter_len, void *wincx); diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/softoken/pkcs11.c verify/security/nss//lib/softoken/pkcs11.c --- vanilla/security/nss//lib/softoken/pkcs11.c 2010-07-29 00:23:50.000000000 +0200 +++ verify/security/nss//lib/softoken/pkcs11.c 2010-08-01 00:21:16.354119058 +0200 @@ -296,6 +296,8 @@ CKF_GENERATE_KEY_PAIR},PR_TRUE}, {CKM_RSA_PKCS, {RSA_MIN_MODULUS_BITS,CK_MAX, CKF_DUZ_IT_ALL}, PR_TRUE}, + {CKM_RSA_PKCS_PSS, {RSA_MIN_MODULUS_BITS,CK_MAX, + CKF_DUZ_IT_ALL}, PR_TRUE}, #ifdef SFTK_RSA9796_SUPPORTED {CKM_RSA_9796, {RSA_MIN_MODULUS_BITS,CK_MAX, CKF_DUZ_IT_ALL}, PR_TRUE}, diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/softoken/pkcs11c.c verify/security/nss//lib/softoken/pkcs11c.c --- vanilla/security/nss//lib/softoken/pkcs11c.c 2010-07-20 03:26:03.000000000 +0200 +++ verify/security/nss//lib/softoken/pkcs11c.c 2010-08-01 00:21:16.358119038 +0200 @@ -2473,6 +2473,26 @@ context->destroy = sftk_Null; } break; + case CKM_RSA_PKCS_PSS: + info = PORT_New(SFTKHashVerifyInfo); + if (info == NULL) { + return CKR_HOST_MEMORY; + } + if (key_type != CKK_RSA) { + crv = CKR_KEY_TYPE_INCONSISTENT; + } + info->key = sftk_GetPubKey(key,CKK_RSA,&crv); + if (info->key == NULL) { + return crv; + } + info->meta = pMechanism->pParameter; + if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { + return CKR_MECHANISM_PARAM_INVALID; + }; + context->cipherInfo = info; + context->destroy = (SFTKDestroy) sftk_Space; + context->verify = (SFTKVerify) RSA_CheckPSSHashEM; + break; case CKM_DSA_SHA1: context->multi = PR_TRUE; crv = sftk_doSubSHA1(context); diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/softoken/pkcs11i.h verify/security/nss//lib/softoken/pkcs11i.h --- vanilla/security/nss//lib/softoken/pkcs11i.h 2010-07-20 03:26:03.000000000 +0200 +++ verify/security/nss//lib/softoken/pkcs11i.h 2010-08-01 00:21:16.361119023 +0200 @@ -386,6 +386,7 @@ struct SFTKHashVerifyInfoStr { SECOidTag hashOid; NSSLOWKEYPublicKey *key; + void *meta; }; struct SFTKHashSignInfoStr { diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/softoken/rsawrapr.c verify/security/nss//lib/softoken/rsawrapr.c --- vanilla/security/nss//lib/softoken/rsawrapr.c 2010-07-20 03:26:03.000000000 +0200 +++ verify/security/nss//lib/softoken/rsawrapr.c 2010-08-01 00:35:18.116019658 +0200 @@ -42,9 +42,11 @@ #include "blapi.h" #include "softoken.h" #include "sechash.h" +#include "hasht.h" #include "lowkeyi.h" #include "secerr.h" +#include "pkcs11i.h" #define RSA_BLOCK_MIN_PAD_LEN 8 #define RSA_BLOCK_FIRST_OCTET 0x00 @@ -58,6 +60,9 @@ #define FLAT_BUFSIZE 512 /* bytes to hold flattened SHA1Context. */ +/* This is needed for RSA-PSS functions */ +static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0}; + static SHA1Context * SHA1_CloneContext(SHA1Context *original) { @@ -940,3 +945,165 @@ failure: return SECFailure; } + +/* + * Verify a PSS signature + * Described in RFC 3447, section 9.1.2 + * We use mHash instead of M as input + * emBits from the spec is just modulus bits - 1 + */ +static SECStatus +emsa_pss_verify(const unsigned char *mHash, + const unsigned char *em, unsigned int emLen, + HASH_HashType hashAlg, MGFType maskAlg, + HASH_HashType maskHashAlg, + unsigned int sLen) +{ + const SECHashObject *hash; + void *hash_context; + unsigned char *db, *H_; + unsigned int i, dbMaskLen; + SECStatus rv; + + hash = HASH_GetRawHashObject(hashAlg); + dbMaskLen = emLen - hash->length - 1; + + if (maskAlg != MGF_AlgMGF1) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return SECFailure; + } + + /* Step 3 + 4 */ + if ((emLen < (hash->length + sLen + 2)) || + (em[emLen - 1] != 0xbc)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + + /* Step 7 */ + /* em[dbMaskLen] points to mgfSeed */ + db = PORT_Alloc(dbMaskLen); + if (db == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + 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_ is H' from the RFC */ + H_ = PORT_Alloc(hash->length); + if (H_ == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + hash_context = (*hash->create)(); + if (hash_context == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Free(db); + 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; +} + +static HASH_HashType +GetHashTypeFromMechanism(const CK_MECHANISM_TYPE hash_ckm) +{ + switch(hash_ckm) { + case CKM_SHA_1: + case CKG_MGF1_SHA1: + return HASH_AlgSHA1; + case CKM_SHA256: + case CKG_MGF1_SHA256: + return HASH_AlgSHA256; + case CKM_SHA384: + case CKG_MGF1_SHA384: + return HASH_AlgSHA384; + case CKM_SHA512: + case CKG_MGF1_SHA512: + return HASH_AlgSHA512; + default: + return HASH_AlgNULL; + } +} + +/* XXX Doesn't set error code */ +SECStatus +RSA_CheckPSSHashEM(void *vinfo, + unsigned char * sign, + unsigned int sign_len, + unsigned char * hash, + unsigned int hash_len) +{ + HASH_HashType hashAlg; + MGFType maskAlg = MGF_AlgMGF1; + HASH_HashType maskHashAlg; + CK_RSA_PKCS_PSS_PARAMS *pss_params; + SECStatus rv; + SECItem it; + SFTKHashVerifyInfo *info = vinfo; + + pss_params = info->meta; + hashAlg = GetHashTypeFromMechanism(pss_params->hashAlg); + maskHashAlg = GetHashTypeFromMechanism(pss_params->mgf); + + it.len = nsslowkey_PublicModulusLen(info->key); + if (it.len != sign_len) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + + it.data = (unsigned char *) PORT_Alloc(it.len); + rv = RSA_PublicKeyOp(&(info->key)->u.rsa, it.data, sign); + if (rv != SECSuccess) { + PORT_Free(it.data); + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + + rv = emsa_pss_verify(hash, it.data, sign_len, hashAlg, maskAlg, + maskHashAlg, pss_params->sLen); + PORT_Free(it.data); + + return rv; +} diff '--exclude=*.rej' '--exclude=dist' '--exclude=Linux2.6_x86_64_glibc_PTH_64_DBG.OBJ' '--exclude=*.orig' '--exclude=*.a' '--exclude=*.chk' '--exclude=*.so' '--exclude=*~' '--exclude=*.o' -Naur vanilla/security/nss//lib/softoken/softoken.h verify/security/nss//lib/softoken/softoken.h --- vanilla/security/nss//lib/softoken/softoken.h 2010-07-20 03:26:03.000000000 +0200 +++ verify/security/nss//lib/softoken/softoken.h 2010-08-01 00:21:16.363119013 +0200 @@ -98,6 +98,10 @@ unsigned int signLength, unsigned char *hash, unsigned int hashLength); extern +SECStatus RSA_CheckPSSHashEM(void *info, + unsigned char *sign, unsigned int sign_len, + unsigned char *hash, unsigned int hash_len); +extern SECStatus RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key, unsigned char *sig, unsigned int sigLen, unsigned char *digest,