diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-28 17:46:53 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-28 17:46:53 +0000 |
commit | 9b898661f246b337e278343318b7eea0c2c0ca20 (patch) | |
tree | 4243f662fd6c35aac49a2668d9723bd158ab42ed /crypto/signature_verifier_nss.cc | |
parent | 6aec09b8ad4dd6dcd11babae85322d5208a464c6 (diff) | |
download | chromium_src-9b898661f246b337e278343318b7eea0c2c0ca20.zip chromium_src-9b898661f246b337e278343318b7eea0c2c0ca20.tar.gz chromium_src-9b898661f246b337e278343318b7eea0c2c0ca20.tar.bz2 |
Add SignatureVerifier::VerifyInitRSAPSS for verifying RSA-PSS signatures.
Change the OpenSSL-based SignatureVerifier to use EVP_DigestVerifyInit
instead of EVP_VerifyInit_ex.
Copy the PSS padding verification code from NSS to the NSS-based
SignatureVerifier because the RSA-PSS code in the NSS softoken isn't
exposed via the NSS PK11_ or VFY_ functions yet.
R=agl@chromium.org,rsleevi@chromium.org
BUG=none
TEST=to be added to net_unittests via testing net::quic::ProofVerifier.
Review URL: https://chromiumcodereview.appspot.com/17776003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209178 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'crypto/signature_verifier_nss.cc')
-rw-r--r-- | crypto/signature_verifier_nss.cc | 140 |
1 files changed, 126 insertions, 14 deletions
diff --git a/crypto/signature_verifier_nss.cc b/crypto/signature_verifier_nss.cc index 662e8f2..69b0f82 100644 --- a/crypto/signature_verifier_nss.cc +++ b/crypto/signature_verifier_nss.cc @@ -6,14 +6,66 @@ #include <cryptohi.h> #include <keyhi.h> +#include <pk11pub.h> +#include <secerr.h> +#include <sechash.h> #include <stdlib.h> #include "base/logging.h" #include "crypto/nss_util.h" +#include "crypto/third_party/nss/chromium-nss.h" namespace crypto { -SignatureVerifier::SignatureVerifier() : vfy_context_(NULL) { +namespace { + +HASH_HashType ToNSSHashType(SignatureVerifier::HashAlgorithm hash_alg) { + switch (hash_alg) { + case SignatureVerifier::SHA1: + return HASH_AlgSHA1; + case SignatureVerifier::SHA256: + return HASH_AlgSHA256; + } + return HASH_AlgNULL; +} + +SECStatus VerifyRSAPSS_End(SECKEYPublicKey* public_key, + HASHContext* hash_context, + HASH_HashType mask_hash_alg, + unsigned int salt_len, + const unsigned char* signature, + unsigned int signature_len) { + unsigned int hash_len = hash_context->hashobj->length; + std::vector<unsigned char> hash(hash_len); + HASH_End(hash_context, &hash[0], &hash_len, hash.size()); + + unsigned int modulus_len = SECKEY_PublicKeyStrength(public_key); + if (signature_len != modulus_len) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + std::vector<unsigned char> enc(signature_len); + SECStatus rv = PK11_PubEncryptRaw(public_key, &enc[0], + const_cast<unsigned char*>(signature), + signature_len, NULL); + if (rv != SECSuccess) { + LOG(WARNING) << "PK11_PubEncryptRaw failed"; + return rv; + } + return emsa_pss_verify(&hash[0], &enc[0], enc.size(), + hash_context->hashobj->type, mask_hash_alg, + salt_len); +} + +} // namespace + +SignatureVerifier::SignatureVerifier() + : vfy_context_(NULL), + hash_alg_(SHA1), + mask_hash_alg_(SHA1), + salt_len_(0), + public_key_(NULL), + hash_context_(NULL) { EnsureNSSInit(); } @@ -27,18 +79,13 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, int signature_len, const uint8* public_key_info, int public_key_info_len) { + if (vfy_context_ || hash_context_) + return false; + signature_.assign(signature, signature + signature_len); - CERTSubjectPublicKeyInfo* spki = NULL; - SECItem spki_der; - spki_der.type = siBuffer; - spki_der.data = const_cast<uint8*>(public_key_info); - spki_der.len = public_key_info_len; - spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der); - if (!spki) - return false; - SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki); - SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki. + SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info, + public_key_info_len); if (!public_key) return false; @@ -88,14 +135,54 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, return true; } +bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg, + HashAlgorithm mask_hash_alg, + int salt_len, + const uint8* signature, + int signature_len, + const uint8* public_key_info, + int public_key_info_len) { + if (vfy_context_ || hash_context_) + return false; + + signature_.assign(signature, signature + signature_len); + + SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info, + public_key_info_len); + if (!public_key) + return false; + + public_key_ = public_key; + hash_alg_ = hash_alg; + mask_hash_alg_ = mask_hash_alg; + salt_len_ = salt_len; + hash_context_ = HASH_Create(ToNSSHashType(hash_alg_)); + if (!hash_context_) + return false; + HASH_Begin(hash_context_); + return true; +} + void SignatureVerifier::VerifyUpdate(const uint8* data_part, int data_part_len) { - SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len); - DCHECK_EQ(SECSuccess, rv); + if (vfy_context_) { + SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len); + DCHECK_EQ(SECSuccess, rv); + } else { + HASH_Update(hash_context_, data_part, data_part_len); + } } bool SignatureVerifier::VerifyFinal() { - SECStatus rv = VFY_End(vfy_context_); + SECStatus rv; + if (vfy_context_) { + rv = VFY_End(vfy_context_); + } else { + rv = VerifyRSAPSS_End(public_key_, hash_context_, + ToNSSHashType(mask_hash_alg_), salt_len_, + signature_.data(), + signature_.size()); + } Reset(); // If signature verification fails, the error code is @@ -103,11 +190,36 @@ bool SignatureVerifier::VerifyFinal() { return (rv == SECSuccess); } +// static +SECKEYPublicKey* SignatureVerifier::DecodePublicKeyInfo( + const uint8* public_key_info, + int public_key_info_len) { + CERTSubjectPublicKeyInfo* spki = NULL; + SECItem spki_der; + spki_der.type = siBuffer; + spki_der.data = const_cast<uint8*>(public_key_info); + spki_der.len = public_key_info_len; + spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der); + if (!spki) + return NULL; + SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki); + SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki. + return public_key; +} + void SignatureVerifier::Reset() { if (vfy_context_) { VFY_DestroyContext(vfy_context_, PR_TRUE); vfy_context_ = NULL; } + if (hash_context_) { + HASH_Destroy(hash_context_); + hash_context_ = NULL; + } + if (public_key_) { + SECKEY_DestroyPublicKey(public_key_); + public_key_ = NULL; + } signature_.clear(); } |