diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 01:21:12 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 01:21:12 +0000 |
commit | 71a9f84a47ed556ecaa23b26a0b0adfee0ae51ce (patch) | |
tree | ea44ee948ea6239dd5a92367e24136acca41c51e /base/crypto | |
parent | be5ad89174eeff113654a42f775fbbe8d3402e50 (diff) | |
download | chromium_src-71a9f84a47ed556ecaa23b26a0b0adfee0ae51ce.zip chromium_src-71a9f84a47ed556ecaa23b26a0b0adfee0ae51ce.tar.gz chromium_src-71a9f84a47ed556ecaa23b26a0b0adfee0ae51ce.tar.bz2 |
Reland: Linux (nss) implementations of RSAPrivateKey and SignatureCreator.
This relands: http://codereview.chromium.org/208032.
Additionally, it fixes a memleak unconvered by valgrind, and adds a valgrind supression for a memleak discovered in the nss library. https://bugzilla.mozilla.org/show_bug.cgi?id=518443
BUG=20669
Review URL: http://codereview.chromium.org/218010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27033 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/crypto')
-rw-r--r-- | base/crypto/rsa_private_key.h | 18 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_nss.cc | 225 | ||||
-rw-r--r-- | base/crypto/signature_creator.h | 18 | ||||
-rw-r--r-- | base/crypto/signature_creator_nss.cc | 74 | ||||
-rw-r--r-- | base/crypto/signature_creator_win.cc | 2 |
5 files changed, 327 insertions, 10 deletions
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h index 21aa601..3d85ebb 100644 --- a/base/crypto/rsa_private_key.h +++ b/base/crypto/rsa_private_key.h @@ -7,11 +7,14 @@ #include "build/build_config.h" -#if defined(OS_WIN) +#if defined(USE_NSS) +#include <cryptoht.h> +#include <keythi.h> +#elif defined(OS_MACOSX) +// TODO(port); +#elif defined(OS_WIN) #include <windows.h> #include <wincrypt.h> -#else -// TODO(port) #endif #include <vector> @@ -35,7 +38,9 @@ class RSAPrivateKey { ~RSAPrivateKey(); -#if defined(OS_WIN) +#if defined(USE_NSS) + SECKEYPrivateKey* key() { return key_; } +#elif defined(OS_WIN) HCRYPTPROV provider() { return provider_; } HCRYPTKEY key() { return key_; } #endif @@ -51,7 +56,10 @@ private: // instead. RSAPrivateKey(); -#if defined(OS_WIN) +#if defined(USE_NSS) + SECKEYPrivateKey* key_; + SECKEYPublicKey* public_key_; +#elif defined(OS_WIN) bool InitProvider(); HCRYPTPROV provider_; diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc new file mode 100644 index 0000000..f9f9a73 --- /dev/null +++ b/base/crypto/rsa_private_key_nss.cc @@ -0,0 +1,225 @@ +// Copyright (c) 2009 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 "base/crypto/rsa_private_key.h" + +#include <cryptohi.h> +#include <keyhi.h> +#include <pk11pub.h> + +#include <iostream> +#include <list> + +#include "base/logging.h" +#include "base/nss_init.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" + +// TODO(rafaelw): Consider refactoring common functions and definitions from +// rsa_private_key_win.cc or using NSS's ASN.1 encoder. +namespace { + +// ASN.1 encoding of the AlgorithmIdentifier from PKCS #8. +const uint8 kRsaAlgorithmIdentifier[] = { + 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, + 0x05, 0x00 +}; + +// ASN.1 tags for some types we use. +const uint8 kSequenceTag = 0x30; +const uint8 kIntegerTag = 0x02; +const uint8 kNullTag = 0x05; +const uint8 kOctetStringTag = 0x04; + +static void PrependBytesInOrder(uint8* val, int start, int num_bytes, + std::list<uint8>* data) { + while(num_bytes > start) { + --num_bytes; + data->push_front(val[num_bytes]); + } +} + +// Helper to prepend an ASN.1 length field. +static void PrependLength(size_t size, std::list<uint8>* data) { + // The high bit is used to indicate whether additional octets are needed to + // represent the length. + if (size < 0x80) { + data->push_front(static_cast<uint8>(size)); + } else { + uint8 num_bytes = 0; + while (size > 0) { + data->push_front(static_cast<uint8>(size & 0xFF)); + size >>= 8; + num_bytes++; + } + CHECK(num_bytes <= 4); + data->push_front(0x80 | num_bytes); + } +} + +// Helper to prepend an ASN.1 type header. +static void PrependTypeHeaderAndLength(uint8 type, uint32 length, + std::list<uint8>* output) { + PrependLength(length, output); + output->push_front(type); +} + +// Helper to prepend an ASN.1 integer. +static void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data) { + // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes + // from the most-significant end of the integer. + int start = 0; + while (start < (num_bytes - 1) && val[start] == 0x00) + start++; + + PrependBytesInOrder(val, start, num_bytes, data); + + // ASN.1 integers are signed. To encode a positive integer whose sign bit + // (the most significant bit) would otherwise be set and make the number + // negative, ASN.1 requires a leading null byte to force the integer to be + // positive. + if ((val[start] & 0x80) != 0) { + data->push_front(0x00); + num_bytes++; + } + + PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); +} + +static bool ReadAttributeAndPrependInteger(SECKEYPrivateKey* key, + CK_ATTRIBUTE_TYPE type, + std::list<uint8>* output) { + SECItem item; + SECStatus rv; + rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); + if (rv != SECSuccess) { + NOTREACHED(); + return false; + } + + PrependInteger(item.data, item.len, output); + SECITEM_FreeItem(&item, PR_FALSE); + return true; +} + +} // namespace + + +namespace base { + +// static +RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { + scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); + + PK11SlotInfo *slot = PK11_GetInternalSlot(); + if (!slot) + return NULL; + + PK11RSAGenParams param; + param.keySizeInBits = num_bits; + param.pe = 65537L; + result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶m, + &result->public_key_, PR_FALSE, PR_FALSE, NULL); + PK11_FreeSlot(slot); + if (!result->key_) + return NULL; + + return result.release(); +} + +// static +RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( + const std::vector<uint8>& input) { + scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); + + PK11SlotInfo *slot = PK11_GetInternalSlot(); + if (!slot) + return NULL; + + SECItem der_private_key_info; + der_private_key_info.data = const_cast<unsigned char*>(&input.front()); + der_private_key_info.len = input.size(); + SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, + &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE, + KU_DIGITAL_SIGNATURE, &result->key_, NULL); + PK11_FreeSlot(slot); + if (rv != SECSuccess) { + NOTREACHED(); + return NULL; + } + + result->public_key_ = SECKEY_ConvertToPublicKey(result->key_); + if (!result->public_key_) { + NOTREACHED(); + return NULL; + } + + return result.release(); +} + +RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { + EnsureNSSInit(); +} + +RSAPrivateKey::~RSAPrivateKey() { + if (key_) + SECKEY_DestroyPrivateKey(key_); + if (public_key_) + SECKEY_DestroyPublicKey(public_key_); +} + +bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) { + std::list<uint8> content; + + // Version (always zero) + uint8 version = 0; + + // Manually read the component attributes of the private key and build up the + // output in reverse order to prevent having to do copies to figure out the + // length. + if (!ReadAttributeAndPrependInteger(key_, CKA_COEFFICIENT, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_EXPONENT_2, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_EXPONENT_1, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_PRIME_2, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_PRIME_1, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_PRIVATE_EXPONENT, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_PUBLIC_EXPONENT, &content) || + !ReadAttributeAndPrependInteger(key_, CKA_MODULUS, &content)) { + NOTREACHED(); + return false; + } + PrependInteger(&version, 1, &content); + PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); + PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content); + + // RSA algorithm OID + for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) + content.push_front(kRsaAlgorithmIdentifier[i - 1]); + + PrependInteger(&version, 1, &content); + PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); + + // Copy everying into the output. + output->reserve(content.size()); + for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) + output->push_back(*i); + + return true; +} + +bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { + SECItem* der_pubkey = SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_); + if (!der_pubkey) { + NOTREACHED(); + return false; + } + + for (size_t i = 0; i < der_pubkey->len; ++i) + output->push_back(der_pubkey->data[i]); + + SECITEM_FreeItem(der_pubkey, PR_TRUE); + return true; +} + +} // namespace base diff --git a/base/crypto/signature_creator.h b/base/crypto/signature_creator.h index 0b66baa..6c7ddbc 100644 --- a/base/crypto/signature_creator.h +++ b/base/crypto/signature_creator.h @@ -5,11 +5,15 @@ #ifndef BASE_CRYPTO_SIGNATURE_CREATOR_H_ #define BASE_CRYPTO_SIGNATURE_CREATOR_H_ -#if defined(OS_WIN) +#include "build/build_config.h" + +#if defined(USE_NSS) +#include <cryptoht.h> +#elif defined(OS_MACOSX) +// TODO(port) +#elif defined(OS_WIN) #include <windows.h> #include <wincrypt.h> -#else -// TODO(PORT) #endif #include <vector> @@ -37,11 +41,15 @@ class SignatureCreator { private: // Private constructor. Use the Create() method instead. - SignatureCreator() {} + SignatureCreator(); RSAPrivateKey* key_; -#if defined(OS_WIN) +#if defined(USE_NSS) + SGNContext* sign_context_; +#elif defined(OS_MACOSX) + // TODO(port) +#elif defined(OS_WIN) HCRYPTHASH hash_object_; #endif diff --git a/base/crypto/signature_creator_nss.cc b/base/crypto/signature_creator_nss.cc new file mode 100644 index 0000000..7108975 --- /dev/null +++ b/base/crypto/signature_creator_nss.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2009 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 "base/crypto/signature_creator.h" + +#include <cryptohi.h> +#include <keyhi.h> +#include <stdlib.h> + +#include "base/logging.h" +#include "base/nss_init.h" +#include "base/scoped_ptr.h" + +namespace base { + +// static +SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { + scoped_ptr<SignatureCreator> result(new SignatureCreator); + result->key_ = key; + + result->sign_context_ = SGN_NewContext(SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, + key->key()); + if (!result->sign_context_) { + NOTREACHED(); + return NULL; + } + + SECStatus rv = SGN_Begin(result->sign_context_); + if (rv != SECSuccess) { + NOTREACHED(); + return NULL; + } + + return result.release(); +} + +SignatureCreator::SignatureCreator() : sign_context_(NULL) { + EnsureNSSInit(); +} + +SignatureCreator::~SignatureCreator() { + if (sign_context_) { + SGN_DestroyContext(sign_context_, PR_TRUE); + sign_context_ = NULL; + } +} + +bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { + SECStatus rv = SGN_Update(sign_context_, + const_cast<unsigned char*>(data_part), + data_part_len); + if (rv != SECSuccess) { + NOTREACHED(); + return false; + } + + return true; +} + +bool SignatureCreator::Final(std::vector<uint8>* signature) { + SECItem signature_item; + SECStatus rv = SGN_End(sign_context_, &signature_item); + if (rv != SECSuccess) { + NOTREACHED(); + return false; + } + signature->assign(signature_item.data, + signature_item.data + signature_item.len); + SECITEM_FreeItem(&signature_item, PR_FALSE); + return true; +} + +} // namespace base diff --git a/base/crypto/signature_creator_win.cc b/base/crypto/signature_creator_win.cc index 78e4964..700a309 100644 --- a/base/crypto/signature_creator_win.cc +++ b/base/crypto/signature_creator_win.cc @@ -23,6 +23,8 @@ SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { return result.release(); } +SignatureCreator::SignatureCreator() : hash_object_(0) {} + SignatureCreator::~SignatureCreator() { if (hash_object_) { if (!CryptDestroyHash(hash_object_)) |