0

crypto: add DecodeSignature and use SHA-256 with ECDSA.

This changes ECSignatureCreator to use the hash function that SPDY
expects (SHA-256). There are no other users of ECSignatureCreator in
the tree so I'm going to defer making these choices parameters until there's
a benefit to be had.

It also adds DecodeSignature to convert from ASN.1 signatures to the `raw'
form that SPDY needs.

BUG=none

Review URL: https://chromiumcodereview.appspot.com/10910226

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157551 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
agl@chromium.org
2012-09-19 15:11:33 +00:00
parent 7cd51e7bf5
commit 7c3090a02e
7 changed files with 64 additions and 13 deletions

@ -5,6 +5,7 @@
#ifndef CRYPTO_EC_SIGNATURE_CREATOR_H_
#define CRYPTO_EC_SIGNATURE_CREATOR_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
@ -31,7 +32,7 @@ class CRYPTO_EXPORT ECSignatureCreator {
// Create an instance. The caller must ensure that the provided PrivateKey
// instance outlives the created ECSignatureCreator.
// TODO(rch): This is currently hard coded to use SHA1. Ideally, we should
// TODO(rch): This is currently hard coded to use SHA256. Ideally, we should
// pass in the hash algorithm identifier.
static ECSignatureCreator* Create(ECPrivateKey* key);
@ -50,6 +51,14 @@ class CRYPTO_EXPORT ECSignatureCreator {
virtual bool Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) = 0;
// DecodeSignature converts from a DER encoded ECDSA-Sig-Value (as produced
// by Sign) to a `raw' ECDSA signature which consists of a pair of
// big-endian, zero-padded, 256-bit integers, r and s. On success it returns
// true and puts the raw signature into |out_raw_sig|.
// (Only P-256 signatures are supported.)
virtual bool DecodeSignature(const std::vector<uint8>& signature,
std::vector<uint8>* out_raw_sig) = 0;
};
} // namespace crypto

@ -19,8 +19,12 @@ class ECSignatureCreatorImpl : public ECSignatureCreator {
int data_len,
std::vector<uint8>* signature) OVERRIDE;
virtual bool DecodeSignature(const std::vector<uint8>& der_sig,
std::vector<uint8>* out_raw_sig) OVERRIDE;
private:
ECPrivateKey* key_;
size_t signature_len_;
DISALLOW_COPY_AND_ASSIGN(ECSignatureCreatorImpl);
};

@ -24,7 +24,8 @@ namespace {
SECStatus SignData(SECItem* result,
SECItem* input,
SECKEYPrivateKey* key,
HASH_HashType hash_type) {
HASH_HashType hash_type,
size_t* out_signature_len) {
if (key->keyType != ecKey) {
DLOG(FATAL) << "Should be using an EC key.";
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@ -49,6 +50,8 @@ SECStatus SignData(SECItem* result,
if (rv != SECSuccess)
return rv;
*out_signature_len = sig.len;
// DER encode the signature.
return DSAU_EncodeDerSigWithLen(result, &sig, sig.len);
}
@ -56,7 +59,8 @@ SECStatus SignData(SECItem* result,
} // namespace
ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key)
: key_(key) {
: key_(key),
signature_len_(0) {
EnsureNSSInit();
}
@ -79,7 +83,7 @@ bool ECSignatureCreatorImpl::Sign(const uint8* data,
// Sign the secret data and save it to |result|.
SECStatus rv =
SignData(&result, &secret, key_->key(), HASH_AlgSHA1);
SignData(&result, &secret, key_->key(), HASH_AlgSHA256, &signature_len_);
if (rv != SECSuccess) {
DLOG(ERROR) << "DerSignData: " << PORT_GetError();
return false;
@ -91,4 +95,20 @@ bool ECSignatureCreatorImpl::Sign(const uint8* data,
return true;
}
bool ECSignatureCreatorImpl::DecodeSignature(
const std::vector<uint8>& der_sig,
std::vector<uint8>* out_raw_sig) {
SECItem der_sig_item;
der_sig_item.type = siBuffer;
der_sig_item.len = der_sig.size();
der_sig_item.data = const_cast<uint8*>(&der_sig[0]);
SECItem* raw_sig = DSAU_DecodeDerSigToLen(&der_sig_item, signature_len_);
if (!raw_sig)
return false;
out_raw_sig->assign(raw_sig->data, raw_sig->data + raw_sig->len);
SECITEM_FreeItem(raw_sig, PR_TRUE /* free SECItem structure itself. */);
return true;
}
} // namespace crypto

@ -22,4 +22,10 @@ bool ECSignatureCreatorImpl::Sign(const uint8* data,
return false;
}
bool ECSignatureCreatorImpl::DecodeSignature(const std::vector<uint8>& der_sig,
std::vector<uint8>* out_raw_sig) {
NOTIMPLEMENTED();
return false;
}
} // namespace crypto

@ -53,17 +53,17 @@ TEST(ECSignatureCreatorTest, BasicTest) {
std::vector<uint8> public_key_info;
ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
// This is the algorithm ID for SHA-1 with EC encryption.
const uint8 kECDSAWithSHA1AlgorithmID[] = {
0x30, 0x0b,
0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01,
// This is the algorithm ID for SHA-256 with EC encryption.
const uint8 kECDSAWithSHA256AlgorithmID[] = {
0x30, 0x0c,
0x06, 0x08,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
0x05, 0x00
};
crypto::SignatureVerifier verifier;
ASSERT_TRUE(verifier.VerifyInit(
kECDSAWithSHA1AlgorithmID, sizeof(kECDSAWithSHA1AlgorithmID),
&signature.front(), signature.size(),
kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
&signature[0], signature.size(),
&public_key_info.front(), public_key_info.size()));
verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),

@ -55,7 +55,7 @@ int SpdyCredentialBuilder::Build(const std::string& tls_unique,
public_key = public_key.substr(2, public_key.length());
// Convert the strings into a vector<unit8>
std::vector<uint8> proof_vector;
std::vector<uint8> der_signature;
scoped_ptr<crypto::ECPrivateKey> private_key(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
ServerBoundCertService::kEPKIPassword,
@ -63,7 +63,13 @@ int SpdyCredentialBuilder::Build(const std::string& tls_unique,
scoped_ptr<crypto::ECSignatureCreator> creator(
crypto::ECSignatureCreator::Create(private_key.get()));
creator->Sign(reinterpret_cast<const unsigned char *>(secret.data()),
secret.length(), &proof_vector);
secret.length(), &der_signature);
std::vector<uint8> proof_vector;
if (!creator->DecodeSignature(der_signature, &proof_vector)) {
NOTREACHED();
return ERR_UNEXPECTED;
}
credential->slot = slot;
credential->certs.push_back(public_key.as_string());

@ -63,6 +63,12 @@ class MockECSignatureCreator : public crypto::ECSignatureCreator {
return true;
}
virtual bool DecodeSignature(const std::vector<uint8>& signature,
std::vector<uint8>* out_raw_sig) {
*out_raw_sig = signature;
return true;
}
private:
crypto::ECPrivateKey* key_;