Chromium Code Reviews| Index: crypto/signature_verifier_nss.cc |
| =================================================================== |
| --- crypto/signature_verifier_nss.cc (revision 208575) |
| +++ crypto/signature_verifier_nss.cc (working copy) |
| @@ -6,14 +6,67 @@ |
| #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; |
| + default: |
| + 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_ResultLenContext(hash_context); |
| + 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_GetType(hash_context), 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(); |
| } |
| @@ -21,14 +74,10 @@ |
| Reset(); |
| } |
| -bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, |
| - int signature_algorithm_len, |
| - const uint8* signature, |
| - int signature_len, |
| - const uint8* public_key_info, |
| - int public_key_info_len) { |
| - signature_.assign(signature, signature + signature_len); |
| - |
| +// static |
| +SECKEYPublicKey* SignatureVerifier::DecodePublicKeyInfo( |
| + const uint8* public_key_info, |
| + int public_key_info_len) { |
| CERTSubjectPublicKeyInfo* spki = NULL; |
| SECItem spki_der; |
| spki_der.type = siBuffer; |
| @@ -36,9 +85,22 @@ |
| spki_der.len = public_key_info_len; |
| spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der); |
| if (!spki) |
| - return false; |
| + return NULL; |
| SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki); |
| SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki. |
| + return public_key; |
| +} |
| + |
| +bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, |
| + int signature_algorithm_len, |
| + const uint8* signature, |
| + int signature_len, |
| + const uint8* public_key_info, |
| + int public_key_info_len) { |
|
Ryan Sleevi
2013/06/26 19:48:28
Can you make it an error to call VerifyInit() and
wtc
2013/06/27 02:23:51
Done.
|
| + signature_.assign(signature, signature + signature_len); |
| + |
| + SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info, |
| + public_key_info_len); |
| if (!public_key) |
| return false; |
| @@ -88,14 +150,51 @@ |
| 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) { |
| + 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 |
| @@ -108,6 +207,14 @@ |
| 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(); |
|
Ryan Sleevi
2013/06/26 19:48:28
LEAK? What happens to public_key_ here. Seems like
wtc
2013/06/27 02:23:51
public_key_ is destroyed on lines 214-217 above.
|
| } |