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:
@ -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_;
|
||||
|
||||
|
Reference in New Issue
Block a user