diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-07 02:46:31 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-07 02:46:31 +0000 |
commit | 308379a5ec38a9cf25a91aeaa3f11f9f7af33e95 (patch) | |
tree | 373af2c8453787823641585af0d3a5a07f8c2eb1 /base/crypto | |
parent | 4fd4de79c980066d6cfd37d1fc177f0d00bfd9b5 (diff) | |
download | chromium_src-308379a5ec38a9cf25a91aeaa3f11f9f7af33e95.zip chromium_src-308379a5ec38a9cf25a91aeaa3f11f9f7af33e95.tar.gz chromium_src-308379a5ec38a9cf25a91aeaa3f11f9f7af33e95.tar.bz2 |
Refactor ASN1 parsing/serialization
Review URL: http://codereview.chromium.org/242136
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28223 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/crypto')
-rw-r--r-- | base/crypto/rsa_private_key.cc | 375 | ||||
-rw-r--r-- | base/crypto/rsa_private_key.h | 127 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_mac.cc | 236 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_nss.cc | 123 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_win.cc | 344 | ||||
-rw-r--r-- | base/crypto/signature_creator_unittest.cc | 1 |
6 files changed, 573 insertions, 633 deletions
diff --git a/base/crypto/rsa_private_key.cc b/base/crypto/rsa_private_key.cc new file mode 100644 index 0000000..e6faa3e --- /dev/null +++ b/base/crypto/rsa_private_key.cc @@ -0,0 +1,375 @@ +// 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 <iostream> +#include <list> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" + +// This file manually encodes and decodes RSA private keys using PrivateKeyInfo +// from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are: +// +// PrivateKeyInfo ::= SEQUENCE { +// version Version, +// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, +// privateKey PrivateKey, +// attributes [0] IMPLICIT Attributes OPTIONAL +// } +// +// RSAPrivateKey ::= SEQUENCE { +// version Version, +// modulus INTEGER, +// publicExponent INTEGER, +// privateExponent INTEGER, +// prime1 INTEGER, +// prime2 INTEGER, +// exponent1 INTEGER, +// exponent2 INTEGER, +// coefficient INTEGER +// } + +namespace { +// Helper for error handling during key import. +#define READ_ASSERT(truth) \ + if (!(truth)) { \ + NOTREACHED(); \ + return false; \ + } +} // namespace + +namespace base { + +const uint8 PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = { + 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, + 0x05, 0x00 +}; + +void PrivateKeyInfoCodec::PrependBytes(uint8* val, + int start, + int num_bytes, + std::list<uint8>* data) { + while(num_bytes > 0) { + --num_bytes; + data->push_front(val[start + num_bytes]); + } +} + +void PrivateKeyInfoCodec::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); + } +} + +void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(uint8 type, + uint32 length, + std::list<uint8>* output) { + PrependLength(length, output); + output->push_front(type); +} + +void PrivateKeyInfoCodec::PrependBitString(uint8* val, + int num_bytes, + std::list<uint8>* output) { + // Start with the data. + PrependBytes(val, 0, num_bytes, output); + // Zero unused bits. + output->push_front(0); + // Add the length. + PrependLength(num_bytes + 1, output); + // Finally, add the bit string tag. + output->push_front((uint8) kBitStringTag); +} + +bool PrivateKeyInfoCodec::ReadLength(uint8** pos, uint8* end, uint32* result) { + READ_ASSERT(*pos < end); + int length = 0; + + // If the MSB is not set, the length is just the byte itself. + if (!(**pos & 0x80)) { + length = **pos; + (*pos)++; + } else { + // Otherwise, the lower 7 indicate the length of the length. + int length_of_length = **pos & 0x7F; + READ_ASSERT(length_of_length <= 4); + (*pos)++; + READ_ASSERT(*pos + length_of_length < end); + + length = 0; + for (int i = 0; i < length_of_length; ++i) { + length <<= 8; + length |= **pos; + (*pos)++; + } + } + + READ_ASSERT(*pos + length <= end); + if (result) *result = length; + return true; +} + +bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8** pos, + uint8* end, + uint8 expected_tag, + uint32* length) { + READ_ASSERT(*pos < end); + READ_ASSERT(**pos == expected_tag); + (*pos)++; + + return ReadLength(pos, end, length); +} + +bool PrivateKeyInfoCodec::ReadSequence(uint8** pos, uint8* end) { + return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); +} + +bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8** pos, uint8* end) { + READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); + READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, + sizeof(kRsaAlgorithmIdentifier)) == 0); + (*pos) += sizeof(kRsaAlgorithmIdentifier); + return true; +} + +bool PrivateKeyInfoCodec::ReadVersion(uint8** pos, uint8* end) { + uint32 length = 0; + if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) + return false; + + // The version should be zero. + for (uint32 i = 0; i < length; ++i) { + READ_ASSERT(**pos == 0x00); + (*pos)++; + } + + return true; +} + +bool PrivateKeyInfoCodec::Export(std::vector<uint8>* output) { + std::list<uint8> content; + + // Version (always zero) + uint8 version = 0; + + PrependInteger(coefficient_, &content); + PrependInteger(exponent2_, &content); + PrependInteger(exponent1_, &content); + PrependInteger(prime2_, &content); + PrependInteger(prime1_, &content); + PrependInteger(private_exponent_, &content); + PrependInteger(public_exponent_, &content); + PrependInteger(modulus_, &content); + 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 PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) { + // Create a sequence with the modulus (n) and public exponent (e). + std::list<uint8> content; + PrependInteger(&public_exponent_[0], + static_cast<int>(public_exponent_.size()), + &content); + PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content); + PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); + + // Copy the sequence with n and e into a buffer. + std::vector<uint8> bit_string; + for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) + bit_string.push_back(*i); + content.clear(); + // Add the sequence as the contents of a bit string. + PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()), + &content); + + // Add the RSA algorithm OID. + for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) + content.push_front(kRsaAlgorithmIdentifier[i - 1]); + + // Finally, wrap everything in a sequence. + PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); + + // Copy everything 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 PrivateKeyInfoCodec::Import(const std::vector<uint8>& input) { + if (input.empty()) { + return false; + } + + // Parse the private key info up to the public key values, ignoring + // the subsequent private key values. + uint8* src = const_cast<uint8*>(&input.front()); + uint8* end = src + input.size(); + if (!ReadSequence(&src, end) || + !ReadVersion(&src, end) || + !ReadAlgorithmIdentifier(&src, end) || + !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) || + !ReadSequence(&src, end) || + !ReadVersion(&src, end) || + !ReadInteger(&src, end, &modulus_)) + return false; + + int mod_size = modulus_.size(); + READ_ASSERT(mod_size % 2 == 0); + int primes_size = mod_size / 2; + + if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent_) || + !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent_) || + !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1_) || + !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2_) || + !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1_) || + !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2_) || + !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient_)) + return false; + + READ_ASSERT(src == end); + + + return true; +} + +void PrivateKeyInfoCodec::PrependInteger(const std::vector<uint8>& in, + std::list<uint8>* out) { + uint8* ptr = const_cast<uint8*>(&in.front()); + PrependIntegerImpl(ptr, in.size(), out, big_endian_); +} + +// Helper to prepend an ASN.1 integer. +void PrivateKeyInfoCodec::PrependInteger(uint8* val, + int num_bytes, + std::list<uint8>* data) { + PrependIntegerImpl(val, num_bytes, data, big_endian_); +} + +void PrivateKeyInfoCodec::PrependIntegerImpl(uint8* val, + int num_bytes, + std::list<uint8>* data, + bool big_endian) { + // Reverse input if little-endian. + std::vector<uint8> tmp; + if (!big_endian) { + tmp.assign(val, val + num_bytes); + reverse(tmp.begin(), tmp.end()); + val = &tmp.front(); + } + + // 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++; + num_bytes--; + } + PrependBytes(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. + uint8 front = data->front(); + if ((front & 0x80) != 0) { + data->push_front(0x00); + num_bytes++; + } + + PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); +} + +bool PrivateKeyInfoCodec::ReadInteger(uint8** pos, + uint8* end, + std::vector<uint8>* out) { + return ReadIntegerImpl(pos, end, out, big_endian_); +} + +bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8** pos, + uint8* end, + std::vector<uint8>* out, + bool big_endian) { + uint32 length = 0; + if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length) + return false; + + // The first byte can be zero to force positiveness. We can ignore this. + if (**pos == 0x00) { + ++(*pos); + --length; + } + + if (length) + out->insert(out->end(), *pos, (*pos) + length); + + (*pos) += length; + + // Reverse output if little-endian. + if (!big_endian) + reverse(out->begin(), out->end()); + return true; +} + +bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(uint8** pos, + uint8* end, + size_t expected_size, + std::vector<uint8>* out) { + std::vector<uint8> temp; + if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian + return false; + + int pad = expected_size - temp.size(); + int index = 0; + if (out->size() == expected_size + 1) { + READ_ASSERT(out->front() == 0x00); + pad++; + index++; + } else { + READ_ASSERT(out->size() <= expected_size); + } + + while(pad) { + out->push_back(0x00); + pad--; + } + out->insert(out->end(), temp.begin(), temp.end()); + + // Reverse output if little-endian. + if (!big_endian_) + reverse(out->begin(), out->end()); + return true; +} + +} // namespace base diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h index a6b0e20..3f07188 100644 --- a/base/crypto/rsa_private_key.h +++ b/base/crypto/rsa_private_key.h @@ -17,12 +17,139 @@ #include <wincrypt.h> #endif +#include <list> #include <vector> #include "base/basictypes.h" namespace base { +// Used internally by RSAPrivateKey for serializing and deserializing +// PKCS #8 PrivateKeyInfo and PublicKeyInfo. +class PrivateKeyInfoCodec { + public: + + // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8. + static const uint8 kRsaAlgorithmIdentifier[]; + + // ASN.1 tags for some types we use. + static const uint8 kBitStringTag = 0x03; + static const uint8 kIntegerTag = 0x02; + static const uint8 kNullTag = 0x05; + static const uint8 kOctetStringTag = 0x04; + static const uint8 kSequenceTag = 0x30; + + // |big_endian| here specifies the byte-significance of the integer components + // that will be parsed & serialized (modulus(), etc...) during Import(), + // Export() and ExportPublicKeyInfo() -- not the ASN.1 DER encoding of the + // PrivateKeyInfo/PublicKeyInfo (which is always big-endian). + explicit PrivateKeyInfoCodec(bool big_endian) : big_endian_(big_endian) {} + + // Exports the contents of the integer components to the ASN.1 DER encoding + // of the PrivateKeyInfo structure to |output|. + bool Export(std::vector<uint8>* output); + + // Exports the contents of the integer components to the ASN.1 DER encoding + // of the PublicKeyInfo structure to |output|. + bool ExportPublicKeyInfo(std::vector<uint8>* output); + + // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input| + // and populates the integer components with |big_endian_| byte-significance. + bool Import(const std::vector<uint8>& input); + + // Accessors to the contents of the integer components of the PrivateKeyInfo + // structure. + std::vector<uint8>* modulus() { return &modulus_; }; + std::vector<uint8>* public_exponent() { return &public_exponent_; }; + std::vector<uint8>* private_exponent() { return &private_exponent_; }; + std::vector<uint8>* prime1() { return &prime1_; }; + std::vector<uint8>* prime2() { return &prime2_; }; + std::vector<uint8>* exponent1() { return &exponent1_; }; + std::vector<uint8>* exponent2() { return &exponent2_; }; + std::vector<uint8>* coefficient() { return &coefficient_; }; + + private: + // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_| + // value. + void PrependInteger(const std::vector<uint8>& in, std::list<uint8>* out); + void PrependInteger(uint8* val, int num_bytes, std::list<uint8>* data); + + // Prepends the integer stored in |val| - |val + num_bytes| with |big_endian| + // byte-significance into |data| as an ASN.1 integer. + void PrependIntegerImpl(uint8* val, + int num_bytes, + std::list<uint8>* data, + bool big_endian); + + // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_| + // value. + bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out); + bool ReadIntegerWithExpectedSize(uint8** pos, + uint8* end, + size_t expected_size, + std::vector<uint8>* out); + + // Reads an ASN.1 integer from |pos|, and stores the result into |out| with + // |big_endian| byte-significance. + bool ReadIntegerImpl(uint8** pos, + uint8* end, + std::vector<uint8>* out, + bool big_endian); + + // Prepends the integer stored in |val|, starting a index |start|, for + // |num_bytes| bytes onto |data|. + void PrependBytes(uint8* val, + int start, + int num_bytes, + std::list<uint8>* data); + + // Helper to prepend an ASN.1 length field. + void PrependLength(size_t size, std::list<uint8>* data); + + // Helper to prepend an ASN.1 type header. + void PrependTypeHeaderAndLength(uint8 type, + uint32 length, + std::list<uint8>* output); + + // Helper to prepend an ASN.1 bit string + void PrependBitString(uint8* val, int num_bytes, std::list<uint8>* output); + + // Read an ASN.1 length field. This also checks that the length does not + // extend beyond |end|. + bool ReadLength(uint8** pos, uint8* end, uint32* result); + + // Read an ASN.1 type header and its length. + bool ReadTypeHeaderAndLength(uint8** pos, + uint8* end, + uint8 expected_tag, + uint32* length); + + // Read an ASN.1 sequence declaration. This consumes the type header and + // length field, but not the contents of the sequence. + bool ReadSequence(uint8** pos, uint8* end); + + // Read the RSA AlgorithmIdentifier. + bool ReadAlgorithmIdentifier(uint8** pos, uint8* end); + + // Read one of the two version fields in PrivateKeyInfo. + bool ReadVersion(uint8** pos, uint8* end); + + // The byte-significance of the stored components (modulus, etc..). + bool big_endian_; + + // Component integers of the PrivateKeyInfo + std::vector<uint8> modulus_; + std::vector<uint8> public_exponent_; + std::vector<uint8> private_exponent_; + std::vector<uint8> prime1_; + std::vector<uint8> prime2_; + std::vector<uint8> exponent1_; + std::vector<uint8> exponent2_; + std::vector<uint8> coefficient_; + + DISALLOW_COPY_AND_ASSIGN(PrivateKeyInfoCodec); +}; + // Encapsulates an RSA private key. Can be used to generate new keys, export // keys to other formats, or to extract a public key. class RSAPrivateKey { diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc index f44115c..61845e3 100644 --- a/base/crypto/rsa_private_key_mac.cc +++ b/base/crypto/rsa_private_key_mac.cc @@ -10,187 +10,6 @@ #include "base/logging.h" #include "base/scoped_ptr.h" -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; -const uint8 kBitStringTag = 0x03; - -// Helper for error handling during key import. -#define READ_ASSERT(truth) \ - if (!(truth)) { \ - NOTREACHED(); \ - return false; \ - } - -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 bit string -static void PrependBitString(uint8* val, int num_bytes, - std::list<uint8>* output) { - // Start with the data. - PrependBytesInOrder(val, 0, num_bytes, output); - // Zero unused bits. - output->push_front(0); - // Add the length. - PrependLength(num_bytes + 1, output); - // Finally, add the bit string tag. - output->push_front(kBitStringTag); -} - -// 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); -} - -// Read an ASN.1 length field. This also checks that the length does not extend -// beyond |end|. -static bool ReadLength(uint8** pos, uint8* end, uint32* result) { - READ_ASSERT(*pos < end); - int length = 0; - - // If the MSB is not set, the length is just the byte itself. - if (!(**pos & 0x80)) { - length = **pos; - (*pos)++; - } else { - // Otherwise, the lower 7 indicate the length of the length. - int length_of_length = **pos & 0x7F; - READ_ASSERT(length_of_length <= 4); - (*pos)++; - READ_ASSERT(*pos + length_of_length < end); - - length = 0; - for (int i = 0; i < length_of_length; ++i) { - length <<= 8; - length |= **pos; - (*pos)++; - } - } - - READ_ASSERT(*pos + length <= end); - if (result) *result = length; - return true; -} - -// Read an ASN.1 type header and its length. -static bool ReadTypeHeaderAndLength(uint8** pos, uint8* end, - uint8 expected_tag, uint32* length) { - READ_ASSERT(*pos < end); - READ_ASSERT(**pos == expected_tag); - (*pos)++; - - return ReadLength(pos, end, length); -} - -// Read an ASN.1 sequence declaration. This consumes the type header and length -// field, but not the contents of the sequence. -static bool ReadSequence(uint8** pos, uint8* end) { - return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); -} - -// Read the RSA AlgorithmIdentifier. -static bool ReadAlgorithmIdentifier(uint8** pos, uint8* end) { - READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); - READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, - sizeof(kRsaAlgorithmIdentifier)) == 0); - (*pos) += sizeof(kRsaAlgorithmIdentifier); - return true; -} - -// Read one of the two version fields in PrivateKeyInfo. -static bool ReadVersion(uint8** pos, uint8* end) { - uint32 length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) - return false; - - // The version should be zero. - for (uint32 i = 0; i < length; ++i) { - READ_ASSERT(**pos == 0x00); - (*pos)++; - } - - return true; -} - -// Read an ASN.1 integer. -static bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out) { - uint32 length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length) - return false; - - // The first byte can be zero to force positiveness. We can ignore this. - if (**pos == 0x00) { - ++(*pos); - --length; - } - - if (length) - out->insert(out->end(), *pos, (*pos) + length); - - (*pos) += length; - return true; -} - -} // namespace - namespace base { // static @@ -318,55 +137,12 @@ bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) { } bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { - if (!key_.KeyData.Data || !key_.KeyData.Length) { - return false; - } - - // Parse the private key info up to the public key values, ignoring - // the subsequent private key values. - uint8* src = key_.KeyData.Data; - uint8* end = src + key_.KeyData.Length; - std::vector<uint8> modulus; - std::vector<uint8> public_exponent; - if (!ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadAlgorithmIdentifier(&src, end) || - !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) || - !ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadInteger(&src, end, &modulus) || - !ReadInteger(&src, end, &public_exponent)) - return false; - - // Create a sequence with the modulus (n) and public exponent (e). - std::list<uint8> content; - PrependInteger(&public_exponent[0], static_cast<int>(public_exponent.size()), - &content); - PrependInteger(&modulus[0], static_cast<int>(modulus.size()), &content); - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy the sequence with n and e into a buffer. - std::vector<uint8> bit_string; - for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i) - bit_string.push_back(*i); - content.clear(); - // Add the sequence as the contents of a bit string. - PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()), - &content); - - // Add the RSA algorithm OID. - for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i) - content.push_front(kRsaAlgorithmIdentifier[i - 1]); - - // Finally, wrap everything in a sequence. - PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content); - - // Copy everything 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; + PrivateKeyInfoCodec private_key_info(true); + std::vector<uint8> private_key_data; + private_key_data.assign(key_.KeyData.Data, + key_.KeyData.Data + key_.KeyData.Length); + return (private_key_info.Import(private_key_data) && + private_key_info.ExportPublicKeyInfo(output)); } } // namespace base diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc index f9f9a73..7e10b36 100644 --- a/base/crypto/rsa_private_key_nss.cc +++ b/base/crypto/rsa_private_key_nss.cc @@ -20,76 +20,9 @@ // 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) { +static bool ReadAttribute(SECKEYPrivateKey* key, + CK_ATTRIBUTE_TYPE type, + std::vector<uint8>* output) { SECItem item; SECStatus rv; rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); @@ -98,14 +31,13 @@ static bool ReadAttributeAndPrependInteger(SECKEYPrivateKey* key, return false; } - PrependInteger(item.data, item.len, output); + output->assign(item.data, item.data + item.len); SECITEM_FreeItem(&item, PR_FALSE); return true; } } // namespace - namespace base { // static @@ -170,42 +102,25 @@ RSAPrivateKey::~RSAPrivateKey() { } 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)) { + PrivateKeyInfoCodec private_key_info(true); + + // Manually read the component attributes of the private key and build up + // the PrivateKeyInfo. + if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) || + !ReadAttribute(key_, CKA_PUBLIC_EXPONENT, + private_key_info.public_exponent()) || + !ReadAttribute(key_, CKA_PRIVATE_EXPONENT, + private_key_info.private_exponent()) || + !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) || + !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) || + !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) || + !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) || + !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) { 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; + return private_key_info.Export(output); } bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { diff --git a/base/crypto/rsa_private_key_win.cc b/base/crypto/rsa_private_key_win.cc index b1846fa..3683d86 100644 --- a/base/crypto/rsa_private_key_win.cc +++ b/base/crypto/rsa_private_key_win.cc @@ -11,215 +11,15 @@ #include "base/scoped_ptr.h" #include "base/string_util.h" - -// This file manually encodes and decodes RSA private keys using PrivateKeyInfo -// from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are: -// -// PrivateKeyInfo ::= SEQUENCE { -// version Version, -// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, -// privateKey PrivateKey, -// attributes [0] IMPLICIT Attributes OPTIONAL -// } -// -// RSAPrivateKey ::= SEQUENCE { -// version Version, -// modulus INTEGER, -// publicExponent INTEGER, -// privateExponent INTEGER, -// prime1 INTEGER, -// prime2 INTEGER, -// exponent1 INTEGER, -// exponent2 INTEGER, -// coefficient INTEGER -// } - - 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; - -// Helper function to prepend an array of bytes into a list, reversing their -// order. This is needed because ASN.1 integers are big-endian, while CryptoAPI -// uses little-endian. -static void PrependBytesInReverseOrder(uint8* val, int num_bytes, - std::list<uint8>* data) { - for (int i = 0; i < num_bytes; ++i) - data->push_front(val[i]); -} - -// 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) { - // Skip trailing null bytes off the MSB end, which is the tail since the input - // is little endian. - while (num_bytes > 1 && val[num_bytes - 1] == 0x00) - num_bytes--; - - PrependBytesInReverseOrder(val, num_bytes, data); - - // If the MSB is set, we need to add an extra null byte, otherwise the integer - // could be interpreted as negative. - if ((val[num_bytes - 1] & 0x80) != 0) { - data->push_front(0x00); - num_bytes++; - } - - PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); -} - -// Helper for error handling during key import. + // Helper for error handling during key import. #define READ_ASSERT(truth) \ if (!(truth)) { \ - NOTREACHED(); \ - return false; \ - } - -// Read an ASN.1 length field. This also checks that the length does not extend -// beyond |end|. -static bool ReadLength(uint8** pos, uint8* end, uint32* result) { - READ_ASSERT(*pos < end); - int length = 0; - - // If the MSB is not set, the length is just the byte itself. - if (!(**pos & 0x80)) { - length = **pos; - (*pos)++; - } else { - // Otherwise, the lower 7 indicate the length of the length. - int length_of_length = **pos & 0x7F; - READ_ASSERT(length_of_length <= 4); - (*pos)++; - READ_ASSERT(*pos + length_of_length < end); - - length = 0; - for (int i = 0; i < length_of_length; ++i) { - length <<= 8; - length |= **pos; - (*pos)++; - } + NOTREACHED(); \ + return false; \ } - - READ_ASSERT(*pos + length <= end); - if (result) *result = length; - return true; -} - -// Read an ASN.1 type header and its length. -static bool ReadTypeHeaderAndLength(uint8** pos, uint8* end, - uint8 expected_tag, uint32* length) { - READ_ASSERT(*pos < end); - READ_ASSERT(**pos == expected_tag); - (*pos)++; - - return ReadLength(pos, end, length); -} - -// Read an ASN.1 sequence declaration. This consumes the type header and length -// field, but not the contents of the sequence. -static bool ReadSequence(uint8** pos, uint8* end) { - return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); -} - -// Read the RSA AlgorithmIdentifier. -static bool ReadAlgorithmIdentifier(uint8** pos, uint8* end) { - READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); - READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, - sizeof(kRsaAlgorithmIdentifier)) == 0); - (*pos) += sizeof(kRsaAlgorithmIdentifier); - return true; -} - -// Read one of the two version fields in PrivateKeyInfo. -static bool ReadVersion(uint8** pos, uint8* end) { - uint32 length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) - return false; - - // The version should be zero. - for (uint32 i = 0; i < length; ++i) { - READ_ASSERT(**pos == 0x00); - (*pos)++; - } - - return true; -} - -// Read an ASN.1 integer. -static bool ReadInteger(uint8** pos, uint8* end, std::vector<uint8>* out) { - uint32 length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) - return false; - - // Read the bytes out in reverse order because of endianness. - for (uint32 i = length - 1; i > 0; --i) - out->push_back(*(*pos + i)); - - // The last byte can be zero to force positiveness. We can ignore this. - if (**pos != 0x00) - out->push_back(**pos); - - (*pos) += length; - return true; -} - -static bool ReadIntegerWithExpectedSize(uint8** pos, uint8* end, - int expected_size, - std::vector<uint8>* out) { - if (!ReadInteger(pos, end, out)) - return false; - - if (out->size() == expected_size + 1) { - READ_ASSERT(out->back() == 0x00); - out->pop_back(); - } else { - READ_ASSERT(out->size() <= expected_size); - } - - // Pad out any missing bytes with null. - for (size_t i = out->size(); i < expected_size; ++i) - out->push_back(0x00); - - return true; -} - } // namespace - namespace base { // static @@ -245,46 +45,18 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( if (!result->InitProvider()) return NULL; - uint8* src = const_cast<uint8*>(&input.front()); - uint8* end = src + input.size(); - int version = -1; - std::vector<uint8> modulus; - std::vector<uint8> public_exponent; - std::vector<uint8> private_exponent; - std::vector<uint8> prime1; - std::vector<uint8> prime2; - std::vector<uint8> exponent1; - std::vector<uint8> exponent2; - std::vector<uint8> coefficient; - - if (!ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadAlgorithmIdentifier(&src, end) || - !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) || - !ReadSequence(&src, end) || - !ReadVersion(&src, end) || - !ReadInteger(&src, end, &modulus)) - return false; - - int mod_size = modulus.size(); - READ_ASSERT(mod_size % 2 == 0); - int primes_size = mod_size / 2; - - if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent) || - !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2) || - !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient)) - return false; - - READ_ASSERT(src == end); - - int blob_size = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + modulus.size() + - prime1.size() + prime2.size() + - exponent1.size() + exponent2.size() + - coefficient.size() + private_exponent.size(); + PrivateKeyInfoCodec pki(false); // Little-Endian + pki.Import(input); + + int blob_size = sizeof(PUBLICKEYSTRUC) + + sizeof(RSAPUBKEY) + + pki.modulus()->size() + + pki.prime1()->size() + + pki.prime2()->size() + + pki.exponent1()->size() + + pki.exponent2()->size() + + pki.coefficient()->size() + + pki.private_exponent()->size(); scoped_array<BYTE> blob(new BYTE[blob_size]); uint8* dest = blob.get(); @@ -297,29 +69,29 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( RSAPUBKEY* rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(dest); rsa_pub_key->magic = 0x32415352; - rsa_pub_key->bitlen = modulus.size() * 8; + rsa_pub_key->bitlen = pki.modulus()->size() * 8; int public_exponent_int = 0; - for (size_t i = public_exponent.size(); i > 0; --i) { + for (size_t i = pki.public_exponent()->size(); i > 0; --i) { public_exponent_int <<= 8; - public_exponent_int |= public_exponent[i - 1]; + public_exponent_int |= (*pki.public_exponent())[i - 1]; } rsa_pub_key->pubexp = public_exponent_int; dest += sizeof(RSAPUBKEY); - memcpy(dest, &modulus.front(), modulus.size()); - dest += modulus.size(); - memcpy(dest, &prime1.front(), prime1.size()); - dest += prime1.size(); - memcpy(dest, &prime2.front(), prime2.size()); - dest += prime2.size(); - memcpy(dest, &exponent1.front(), exponent1.size()); - dest += exponent1.size(); - memcpy(dest, &exponent2.front(), exponent2.size()); - dest += exponent2.size(); - memcpy(dest, &coefficient.front(), coefficient.size()); - dest += coefficient.size(); - memcpy(dest, &private_exponent.front(), private_exponent.size()); - dest += private_exponent.size(); + memcpy(dest, &pki.modulus()->front(), pki.modulus()->size()); + dest += pki.modulus()->size(); + memcpy(dest, &pki.prime1()->front(), pki.prime1()->size()); + dest += pki.prime1()->size(); + memcpy(dest, &pki.prime2()->front(), pki.prime2()->size()); + dest += pki.prime2()->size(); + memcpy(dest, &pki.exponent1()->front(), pki.exponent1()->size()); + dest += pki.exponent1()->size(); + memcpy(dest, &pki.exponent2()->front(), pki.exponent2()->size()); + dest += pki.exponent2()->size(); + memcpy(dest, &pki.coefficient()->front(), pki.coefficient()->size()); + dest += pki.coefficient()->size(); + memcpy(dest, &pki.private_exponent()->front(), pki.private_exponent()->size()); + dest += pki.private_exponent()->size(); READ_ASSERT(dest == blob.get() + blob_size); if (!CryptImportKey( @@ -375,59 +147,33 @@ bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) { int mod_size = rsa_pub_key->bitlen / 8; int primes_size = rsa_pub_key->bitlen / 16; - uint8* modulus = pos; + PrivateKeyInfoCodec pki(false); // Little-Endian + + pki.modulus()->assign(pos, pos + mod_size); pos += mod_size; - uint8* prime1 = pos; + pki.prime1()->assign(pos, pos + primes_size); pos += primes_size; - uint8* prime2 = pos; + pki.prime2()->assign(pos, pos + primes_size); pos += primes_size; - uint8* exponent1 = pos; + pki.exponent1()->assign(pos, pos + primes_size); pos += primes_size; - uint8* exponent2 = pos; + pki.exponent2()->assign(pos, pos + primes_size); pos += primes_size; - uint8* coefficient = pos; + pki.coefficient()->assign(pos, pos + primes_size); pos += primes_size; - uint8* private_exponent = pos; + pki.private_exponent()->assign(pos, pos + mod_size); pos += mod_size; - CHECK((pos - blob_length) == reinterpret_cast<BYTE*>(publickey_struct)); + pki.public_exponent()->assign(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp), + reinterpret_cast<uint8*>(&rsa_pub_key->pubexp) + 4); - std::list<uint8> content; - - // Version (always zero) - uint8 version = 0; - - // We build up the output in reverse order to prevent having to do copies to - // figure out the length. - PrependInteger(coefficient, primes_size, &content); - PrependInteger(exponent2, primes_size, &content); - PrependInteger(exponent1, primes_size, &content); - PrependInteger(prime2, primes_size, &content); - PrependInteger(prime1, primes_size, &content); - PrependInteger(private_exponent, mod_size, &content); - PrependInteger(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp), 4, &content); - PrependInteger(modulus, mod_size, &content); - 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); + CHECK((pos - blob_length) == reinterpret_cast<BYTE*>(publickey_struct)); - return true; + return pki.Export(output); } bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { diff --git a/base/crypto/signature_creator_unittest.cc b/base/crypto/signature_creator_unittest.cc index 71aaba1..11959cb 100644 --- a/base/crypto/signature_creator_unittest.cc +++ b/base/crypto/signature_creator_unittest.cc @@ -19,6 +19,7 @@ TEST(SignatureCreatorTest, BasicTest) { key_original->ExportPrivateKey(&key_info); scoped_ptr<base::RSAPrivateKey> key( base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info)); + ASSERT_TRUE(key.get()); scoped_ptr<base::SignatureCreator> signer( base::SignatureCreator::Create(key.get())); |