Skip to content

Commit

Permalink
Create a new ECSignatureCreator class for signing content using EC cr…
Browse files Browse the repository at this point in the history
…ypto.

Review URL: http://codereview.chromium.org/9240029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118964 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rch@chromium.org committed Jan 25, 2012
1 parent 40f96f2 commit e4c1847
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 25 deletions.
14 changes: 11 additions & 3 deletions crypto/crypto.gyp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

Expand Down Expand Up @@ -39,6 +39,8 @@
'sources/': [
['exclude', '_nss\.cc$'],
['include', 'ec_private_key_nss\.cc$'],
['include', 'ec_signature_creator_nss\.cc$'],
['include', 'signature_verifier_nss\.cc$'],
],
'sources!': [
'openpgp_symmetric_encryption.cc',
Expand All @@ -50,6 +52,8 @@
],
'sources/': [
['exclude', 'ec_private_key_nss\.cc$'],
['exclude', 'ec_signature_creator_nss\.cc$'],
['exclude', 'signature_verifier_nss\.cc$'],
],
}],
[ 'os_bsd==1', {
Expand Down Expand Up @@ -91,6 +95,7 @@
# OpenSSL file set is complete.
'sources!': [
'ec_private_key_nss.cc',
'ec_signature_creator_nss.cc',
'encryptor_nss.cc',
'hmac_nss.cc',
'nss_util.cc',
Expand All @@ -112,6 +117,7 @@
}, {
'sources!': [
'ec_private_key_openssl.cc',
'ec_signature_creator_openssl.cc',
'encryptor_openssl.cc',
'hmac_openssl.cc',
'openssl_util.cc',
Expand All @@ -134,6 +140,9 @@
'ec_private_key.h',
'ec_private_key_nss.cc',
'ec_private_key_openssl.cc',
'ec_signature_creator.h',
'ec_signature_creator_nss.cc',
'ec_signature_creator_openssl.cc',
'encryptor.cc',
'encryptor.h',
'encryptor_mac.cc',
Expand Down Expand Up @@ -180,10 +189,8 @@
'signature_creator_openssl.cc',
'signature_creator_win.cc',
'signature_verifier.h',
'signature_verifier_mac.cc',
'signature_verifier_nss.cc',
'signature_verifier_openssl.cc',
'signature_verifier_win.cc',
'symmetric_key.h',
'symmetric_key_mac.cc',
'symmetric_key_nss.cc',
Expand All @@ -207,6 +214,7 @@

# Tests.
'ec_private_key_unittest.cc',
'ec_signature_creator_unittest.cc',
'encryptor_unittest.cc',
'hmac_unittest.cc',
'nss_util_unittest.cc',
Expand Down
52 changes: 52 additions & 0 deletions crypto/ec_signature_creator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CRYPTO_EC_SIGNATURE_CREATOR_H_
#define CRYPTO_EC_SIGNATURE_CREATOR_H_
#pragma once

#include <vector>

#include "base/basictypes.h"
#include "crypto/crypto_export.h"

namespace crypto {

class ECPrivateKey;

// Signs data using a bare private key (as opposed to a full certificate).
// We need this class because SignatureCreator is hardcoded to use
// RSAPrivateKey.
class CRYPTO_EXPORT ECSignatureCreator {
public:
~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
// pass in the hash algorithm identifier.
static ECSignatureCreator* Create(ECPrivateKey* key);

// Signs |data_len| bytes from |data| and writes the results into
// |signature| as a DER encoded ECDSA-Sig-Value from RFC 3279.
//
// ECDSA-Sig-Value ::= SEQUENCE {
// r INTEGER,
// s INTEGER }
bool Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature);

private:
// Private constructor. Use the Create() method instead.
explicit ECSignatureCreator(ECPrivateKey* key);

ECPrivateKey* key_;

DISALLOW_COPY_AND_ASSIGN(ECSignatureCreator);
};

} // namespace crypto

#endif // CRYPTO_EC_SIGNATURE_CREATOR_H_
99 changes: 99 additions & 0 deletions crypto/ec_signature_creator_nss.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "crypto/ec_signature_creator.h"

#include <cryptohi.h>
#include <pk11pub.h>
#include <secerr.h>
#include <sechash.h>

#include "base/logging.h"
#include "crypto/ec_private_key.h"
#include "crypto/nss_util.h"
#include "crypto/scoped_nss_types.h"

namespace crypto {

namespace {

SECStatus SignData(PLArenaPool* arena,
SECItem* result,
SECItem* input,
SECKEYPrivateKey* key,
HASH_HashType hash_type) {
if (key->keyType != ecKey) {
DLOG(FATAL) << "Should be using an EC key.";
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}

// Hash the input.
std::vector<uint8> hash_data(HASH_ResultLen(hash_type));
SECStatus rv = HASH_HashBuf(
hash_type, &hash_data[0], input->data, input->len);
if (rv != SECSuccess)
return rv;
SECItem hash = {siBuffer, &hash_data[0], hash_data.size()};

// Compute signature of hash.
int signature_len = PK11_SignatureLen(key);
std::vector<uint8> signature_data(signature_len);
SECItem sig = {siBuffer, &signature_data[0], signature_len};
rv = PK11_Sign(key, &sig, &hash);
if (rv != SECSuccess)
return rv;

// DER encode the signature.
return DSAU_EncodeDerSigWithLen(result, &sig, sig.len);
}

} // namespace

// static
ECSignatureCreator* ECSignatureCreator::Create(ECPrivateKey* key) {
return new ECSignatureCreator(key);
}

ECSignatureCreator::ECSignatureCreator(ECPrivateKey* key)
: key_(key) {
EnsureNSSInit();
}

ECSignatureCreator::~ECSignatureCreator() { }

bool ECSignatureCreator::Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) {
// Data to be signed
SECItem secret;
secret.type = siBuffer;
secret.len = data_len;
secret.data = const_cast<unsigned char*>(data);

// |arena| is used to encode the cert.
crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
CHECK(arena.get() != NULL);

// Allocate space to contain the signed data.
SECItem* result = SECITEM_AllocItem(arena.get(), NULL, 0);
if (!result) {
DLOG(ERROR) << "Unable to allocate space for signed data.";
return false;
}

// Sign the secret data and save it to |result|.
SECStatus rv =
SignData(arena.get(), result, &secret, key_->key(), HASH_AlgSHA1);
if (rv != SECSuccess) {
DLOG(ERROR) << "DerSignData: " << PORT_GetError();
return false;
}

// Copy the signed data into the output vector.
signature->assign(result->data, result->data + result->len);
return true;
}

} // namespace crypto
33 changes: 33 additions & 0 deletions crypto/ec_signature_creator_openssl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "crypto/ec_signature_creator.h"

#include "base/logging.h"

namespace crypto {

// static
ECSignatureCreator* ECSignatureCreator::Create(ECPrivateKey* key) {
NOTIMPLEMENTED();
return NULL;
}

ECSignatureCreator::ECSignatureCreator(ECPrivateKey* key,
HASH_HashType hash_type)
: key_(key),
hash_type_(hash_type) {
NOTIMPLEMENTED();
}

ECSignatureCreator::~ECSignatureCreator() { }

bool ECSignatureCreator::Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) {
NOTIMPLEMENTED();
return false;
}

} // namespace crypto
72 changes: 72 additions & 0 deletions crypto/ec_signature_creator_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "crypto/ec_signature_creator.h"

#include <string>
#include <vector>

#include "base/memory/scoped_ptr.h"
#include "crypto/ec_private_key.h"
#include "crypto/signature_verifier.h"
#include "testing/gtest/include/gtest/gtest.h"

#if defined(USE_OPENSSL)
// Once ECSignatureCreator is implemented for OpenSSL, remove this #if block.
// TODO(rch): When that happens, also add some exported keys from each to
// test interop between NSS and OpenSSL.
TEST(ECSignatureCreatorTest, OpenSSLStub) {
scoped_ptr<crypto::ECSignatureCreator> signer(
crypto::ECSignatureCreator::Create(NULL));
ASSERT_FALSE(signer.get());
}
#else
TEST(ECSignatureCreatorTest, BasicTest) {
// Do a verify round trip.
scoped_ptr<crypto::ECPrivateKey> key_original(
crypto::ECPrivateKey::Create());
ASSERT_TRUE(key_original.get());

std::vector<uint8> key_info;
ASSERT_TRUE(key_original->ExportEncryptedPrivateKey("", 1000, &key_info));
std::vector<uint8> pubkey_info;
ASSERT_TRUE(key_original->ExportPublicKey(&pubkey_info));

scoped_ptr<crypto::ECPrivateKey> key(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo("", key_info,
pubkey_info));
ASSERT_TRUE(key.get());
ASSERT_TRUE(key->key() != NULL);

scoped_ptr<crypto::ECSignatureCreator> signer(
crypto::ECSignatureCreator::Create(key.get()));
ASSERT_TRUE(signer.get());

std::string data("Hello, World!");
std::vector<uint8> signature;
ASSERT_TRUE(signer->Sign(reinterpret_cast<const uint8*>(data.c_str()),
data.size(),
&signature));

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,
0x05, 0x00
};
crypto::SignatureVerifier verifier;
ASSERT_TRUE(verifier.VerifyInit(
kECDSAWithSHA1AlgorithmID, sizeof(kECDSAWithSHA1AlgorithmID),
&signature.front(), signature.size(),
&public_key_info.front(), public_key_info.size()));

verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
data.size());
ASSERT_TRUE(verifier.VerifyFinal());
}
#endif // !defined(USE_OPENSSL)
26 changes: 4 additions & 22 deletions crypto/signature_verifier.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Expand All @@ -8,19 +8,13 @@

#include "build/build_config.h"

#if defined(USE_NSS)
#include <cryptoht.h>
#elif defined(OS_MACOSX)
#include <Security/cssm.h>
#endif

#include <vector>

#include "base/basictypes.h"
#include "crypto/crypto_export.h"

#if defined(OS_WIN)
#include "crypto/scoped_capi_types.h"
#if !defined(USE_OPENSSL)
typedef struct VFYContextStr VFYContext;
#endif

namespace crypto {
Expand Down Expand Up @@ -87,20 +81,8 @@ class CRYPTO_EXPORT SignatureVerifier {
#if defined(USE_OPENSSL)
struct VerifyContext;
VerifyContext* verify_context_;
#elif defined(USE_NSS)
#else
VFYContext* vfy_context_;
#elif defined(OS_MACOSX)
std::vector<uint8> public_key_info_;

CSSM_CC_HANDLE sig_handle_;

CSSM_KEY public_key_;
#elif defined(OS_WIN)
ScopedHCRYPTPROV provider_;

ScopedHCRYPTHASH hash_object_;

ScopedHCRYPTKEY public_key_;
#endif
};

Expand Down

0 comments on commit e4c1847

Please sign in to comment.