summaryrefslogtreecommitdiffstats
path: root/crypto/signature_verifier_nss.cc
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-28 17:46:53 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-28 17:46:53 +0000
commit9b898661f246b337e278343318b7eea0c2c0ca20 (patch)
tree4243f662fd6c35aac49a2668d9723bd158ab42ed /crypto/signature_verifier_nss.cc
parent6aec09b8ad4dd6dcd11babae85322d5208a464c6 (diff)
downloadchromium_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.cc140
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();
}