diff options
| author | davidben <davidben@chromium.org> | 2016-03-23 16:55:11 -0700 |
|---|---|---|
| committer | Commit bot <commit-bot@chromium.org> | 2016-03-23 23:56:19 +0000 |
| commit | c8a44434aaa8efe3621cbda4722c7527378fb6d8 (patch) | |
| tree | e2786529c9a8931b54e03c5028882140de3d459f | |
| parent | 7c1bd415bfbed8d80249a4e25788fbe967c97699 (diff) | |
| download | chromium_src-c8a44434aaa8efe3621cbda4722c7527378fb6d8.zip chromium_src-c8a44434aaa8efe3621cbda4722c7527378fb6d8.tar.gz chromium_src-c8a44434aaa8efe3621cbda4722c7527378fb6d8.tar.bz2 | |
Move PrivateKeyInfoCodec to rsa_private_key_nss.cc
It's only used by that one file.
BUG=580653
Review URL: https://codereview.chromium.org/1829933002
Cr-Commit-Position: refs/heads/master@{#382979}
| -rw-r--r-- | crypto/BUILD.gn | 1 | ||||
| -rw-r--r-- | crypto/crypto.gypi | 1 | ||||
| -rw-r--r-- | crypto/rsa_private_key.cc | 389 | ||||
| -rw-r--r-- | crypto/rsa_private_key.h | 136 | ||||
| -rw-r--r-- | crypto/rsa_private_key_nss.cc | 481 |
5 files changed, 481 insertions, 527 deletions
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn index 0e11b1f7..9bf6624 100644 --- a/crypto/BUILD.gn +++ b/crypto/BUILD.gn @@ -65,7 +65,6 @@ component("crypto") { "p224_spake.h", "random.cc", "random.h", - "rsa_private_key.cc", "rsa_private_key.h", "rsa_private_key_nss.cc", "rsa_private_key_openssl.cc", diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi index 143d555..a7135cf 100644 --- a/crypto/crypto.gypi +++ b/crypto/crypto.gypi @@ -80,7 +80,6 @@ 'p224.h', 'random.h', 'random.cc', - 'rsa_private_key.cc', 'rsa_private_key.h', 'rsa_private_key_nss.cc', 'rsa_private_key_openssl.cc', diff --git a/crypto/rsa_private_key.cc b/crypto/rsa_private_key.cc deleted file mode 100644 index c546c91..0000000 --- a/crypto/rsa_private_key.cc +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (c) 2011 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/rsa_private_key.h" - -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/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 crypto { - -const uint8_t PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = { - 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, - 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00}; - -PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian) - : big_endian_(big_endian) {} - -PrivateKeyInfoCodec::~PrivateKeyInfoCodec() {} - -bool PrivateKeyInfoCodec::Export(std::vector<uint8_t>* output) { - std::list<uint8_t> content; - - // Version (always zero) - uint8_t 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()); - output->assign(content.begin(), content.end()); - - return true; -} - -bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8_t>* output) { - // Create a sequence with the modulus (n) and public exponent (e). - std::vector<uint8_t> bit_string; - if (!ExportPublicKey(&bit_string)) - return false; - - // Add the sequence as the contents of a bit string. - std::list<uint8_t> content; - 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()); - output->assign(content.begin(), content.end()); - - return true; -} - -bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8_t>* output) { - // Create a sequence with the modulus (n) and public exponent (e). - std::list<uint8_t> 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 everything into the output. - output->reserve(content.size()); - output->assign(content.begin(), content.end()); - - return true; -} - -bool PrivateKeyInfoCodec::Import(const std::vector<uint8_t>& input) { - if (input.empty()) { - return false; - } - - // Parse the private key info up to the public key values, ignoring - // the subsequent private key values. - uint8_t* src = const_cast<uint8_t*>(&input.front()); - uint8_t* 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_t>& in, - std::list<uint8_t>* out) { - uint8_t* ptr = const_cast<uint8_t*>(&in.front()); - PrependIntegerImpl(ptr, in.size(), out, big_endian_); -} - -// Helper to prepend an ASN.1 integer. -void PrivateKeyInfoCodec::PrependInteger(uint8_t* val, - int num_bytes, - std::list<uint8_t>* data) { - PrependIntegerImpl(val, num_bytes, data, big_endian_); -} - -void PrivateKeyInfoCodec::PrependIntegerImpl(uint8_t* val, - int num_bytes, - std::list<uint8_t>* data, - bool big_endian) { - // Reverse input if little-endian. - std::vector<uint8_t> tmp; - if (!big_endian) { - tmp.assign(val, val + num_bytes); - std::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_t front = data->front(); - if ((front & 0x80) != 0) { - data->push_front(0x00); - num_bytes++; - } - - PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); -} - -bool PrivateKeyInfoCodec::ReadInteger(uint8_t** pos, - uint8_t* end, - std::vector<uint8_t>* out) { - return ReadIntegerImpl(pos, end, out, big_endian_); -} - -bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize( - uint8_t** pos, - uint8_t* end, - size_t expected_size, - std::vector<uint8_t>* out) { - std::vector<uint8_t> 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); - } - - out->insert(out->end(), pad, 0x00); - out->insert(out->end(), temp.begin(), temp.end()); - - // Reverse output if little-endian. - if (!big_endian_) - std::reverse(out->begin(), out->end()); - return true; -} - -bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8_t** pos, - uint8_t* end, - std::vector<uint8_t>* out, - bool big_endian) { - uint32_t 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) - std::reverse(out->begin(), out->end()); - return true; -} - -void PrivateKeyInfoCodec::PrependBytes(uint8_t* val, - int start, - int num_bytes, - std::list<uint8_t>* data) { - while (num_bytes > 0) { - --num_bytes; - data->push_front(val[start + num_bytes]); - } -} - -void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8_t>* 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_t>(size)); - } else { - uint8_t num_bytes = 0; - while (size > 0) { - data->push_front(static_cast<uint8_t>(size & 0xFF)); - size >>= 8; - num_bytes++; - } - CHECK_LE(num_bytes, 4); - data->push_front(0x80 | num_bytes); - } -} - -void PrivateKeyInfoCodec::PrependTypeHeaderAndLength( - uint8_t type, - uint32_t length, - std::list<uint8_t>* output) { - PrependLength(length, output); - output->push_front(type); -} - -void PrivateKeyInfoCodec::PrependBitString(uint8_t* val, - int num_bytes, - std::list<uint8_t>* 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_t)kBitStringTag); -} - -bool PrivateKeyInfoCodec::ReadLength(uint8_t** pos, - uint8_t* end, - uint32_t* 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_t** pos, - uint8_t* end, - uint8_t expected_tag, - uint32_t* length) { - READ_ASSERT(*pos < end); - READ_ASSERT(**pos == expected_tag); - (*pos)++; - - return ReadLength(pos, end, length); -} - -bool PrivateKeyInfoCodec::ReadSequence(uint8_t** pos, uint8_t* end) { - return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); -} - -bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end) { - READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); - READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, - sizeof(kRsaAlgorithmIdentifier)) == 0); - (*pos) += sizeof(kRsaAlgorithmIdentifier); - return true; -} - -bool PrivateKeyInfoCodec::ReadVersion(uint8_t** pos, uint8_t* end) { - uint32_t length = 0; - if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) - return false; - - // The version should be zero. - for (uint32_t i = 0; i < length; ++i) { - READ_ASSERT(**pos == 0x00); - (*pos)++; - } - - return true; -} - -} // namespace crypto diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h index d4808f5..5a6dc8cf0 100644 --- a/crypto/rsa_private_key.h +++ b/crypto/rsa_private_key.h @@ -25,144 +25,8 @@ typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey; typedef struct SECKEYPublicKeyStr SECKEYPublicKey; #endif - namespace crypto { -// 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_t kRsaAlgorithmIdentifier[]; - - // ASN.1 tags for some types we use. - static const uint8_t kBitStringTag = 0x03; - static const uint8_t kIntegerTag = 0x02; - static const uint8_t kNullTag = 0x05; - static const uint8_t kOctetStringTag = 0x04; - static const uint8_t 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); - - ~PrivateKeyInfoCodec(); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the PrivateKeyInfo structure to |output|. - bool Export(std::vector<uint8_t>* 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_t>* output); - - // Exports the contents of the integer components to the ASN.1 DER encoding - // of the RSAPublicKey structure to |output|. - bool ExportPublicKey(std::vector<uint8_t>* output); - - // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input| - // and populates the integer components with |big_endian_| byte-significance. - // IMPORTANT NOTE: This is currently *not* security-approved for importing - // keys from unstrusted sources. - bool Import(const std::vector<uint8_t>& input); - - // Accessors to the contents of the integer components of the PrivateKeyInfo - // structure. - std::vector<uint8_t>* modulus() { return &modulus_; } - std::vector<uint8_t>* public_exponent() { return &public_exponent_; } - std::vector<uint8_t>* private_exponent() { return &private_exponent_; } - std::vector<uint8_t>* prime1() { return &prime1_; } - std::vector<uint8_t>* prime2() { return &prime2_; } - std::vector<uint8_t>* exponent1() { return &exponent1_; } - std::vector<uint8_t>* exponent2() { return &exponent2_; } - std::vector<uint8_t>* coefficient() { return &coefficient_; } - - private: - // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_| - // value. - void PrependInteger(const std::vector<uint8_t>& in, std::list<uint8_t>* out); - void PrependInteger(uint8_t* val, int num_bytes, std::list<uint8_t>* 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_t* val, - int num_bytes, - std::list<uint8_t>* data, - bool big_endian); - - // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_| - // value. - bool ReadInteger(uint8_t** pos, uint8_t* end, std::vector<uint8_t>* out); - bool ReadIntegerWithExpectedSize(uint8_t** pos, - uint8_t* end, - size_t expected_size, - std::vector<uint8_t>* out); - - // Reads an ASN.1 integer from |pos|, and stores the result into |out| with - // |big_endian| byte-significance. - bool ReadIntegerImpl(uint8_t** pos, - uint8_t* end, - std::vector<uint8_t>* out, - bool big_endian); - - // Prepends the integer stored in |val|, starting a index |start|, for - // |num_bytes| bytes onto |data|. - void PrependBytes(uint8_t* val, - int start, - int num_bytes, - std::list<uint8_t>* data); - - // Helper to prepend an ASN.1 length field. - void PrependLength(size_t size, std::list<uint8_t>* data); - - // Helper to prepend an ASN.1 type header. - void PrependTypeHeaderAndLength(uint8_t type, - uint32_t length, - std::list<uint8_t>* output); - - // Helper to prepend an ASN.1 bit string - void PrependBitString(uint8_t* val, - int num_bytes, - std::list<uint8_t>* output); - - // Read an ASN.1 length field. This also checks that the length does not - // extend beyond |end|. - bool ReadLength(uint8_t** pos, uint8_t* end, uint32_t* result); - - // Read an ASN.1 type header and its length. - bool ReadTypeHeaderAndLength(uint8_t** pos, - uint8_t* end, - uint8_t expected_tag, - uint32_t* 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_t** pos, uint8_t* end); - - // Read the RSA AlgorithmIdentifier. - bool ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end); - - // Read one of the two version fields in PrivateKeyInfo. - bool ReadVersion(uint8_t** pos, uint8_t* end); - - // The byte-significance of the stored components (modulus, etc..). - bool big_endian_; - - // Component integers of the PrivateKeyInfo - std::vector<uint8_t> modulus_; - std::vector<uint8_t> public_exponent_; - std::vector<uint8_t> private_exponent_; - std::vector<uint8_t> prime1_; - std::vector<uint8_t> prime2_; - std::vector<uint8_t> exponent1_; - std::vector<uint8_t> exponent2_; - std::vector<uint8_t> 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. // TODO(hclam): This class should be ref-counted so it can be reused easily. diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc index 349b7ea..7ec5ae4 100644 --- a/crypto/rsa_private_key_nss.cc +++ b/crypto/rsa_private_key_nss.cc @@ -19,6 +19,13 @@ #include "crypto/nss_util.h" #include "crypto/scoped_nss_types.h" +// Helper for error handling during key import. +#define READ_ASSERT(truth) \ + if (!(truth)) { \ + NOTREACHED(); \ + return false; \ + } + // TODO(rafaelw): Consider using NSS's ASN.1 encoder. namespace { @@ -38,6 +45,480 @@ static bool ReadAttribute(SECKEYPrivateKey* key, return true; } +// 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_t kRsaAlgorithmIdentifier[]; + + // ASN.1 tags for some types we use. + static const uint8_t kBitStringTag = 0x03; + static const uint8_t kIntegerTag = 0x02; + static const uint8_t kOctetStringTag = 0x04; + static const uint8_t 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); + + ~PrivateKeyInfoCodec(); + + // Exports the contents of the integer components to the ASN.1 DER encoding + // of the PrivateKeyInfo structure to |output|. + bool Export(std::vector<uint8_t>* 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_t>* output); + + // Exports the contents of the integer components to the ASN.1 DER encoding + // of the RSAPublicKey structure to |output|. + bool ExportPublicKey(std::vector<uint8_t>* output); + + // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input| + // and populates the integer components with |big_endian_| byte-significance. + // IMPORTANT NOTE: This is currently *not* security-approved for importing + // keys from unstrusted sources. + bool Import(const std::vector<uint8_t>& input); + + // Accessors to the contents of the integer components of the PrivateKeyInfo + // structure. + std::vector<uint8_t>* modulus() { return &modulus_; } + std::vector<uint8_t>* public_exponent() { return &public_exponent_; } + std::vector<uint8_t>* private_exponent() { return &private_exponent_; } + std::vector<uint8_t>* prime1() { return &prime1_; } + std::vector<uint8_t>* prime2() { return &prime2_; } + std::vector<uint8_t>* exponent1() { return &exponent1_; } + std::vector<uint8_t>* exponent2() { return &exponent2_; } + std::vector<uint8_t>* coefficient() { return &coefficient_; } + + private: + // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_| + // value. + void PrependInteger(const std::vector<uint8_t>& in, std::list<uint8_t>* out); + void PrependInteger(uint8_t* val, int num_bytes, std::list<uint8_t>* 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_t* val, + int num_bytes, + std::list<uint8_t>* data, + bool big_endian); + + // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_| + // value. + bool ReadInteger(uint8_t** pos, uint8_t* end, std::vector<uint8_t>* out); + bool ReadIntegerWithExpectedSize(uint8_t** pos, + uint8_t* end, + size_t expected_size, + std::vector<uint8_t>* out); + + // Reads an ASN.1 integer from |pos|, and stores the result into |out| with + // |big_endian| byte-significance. + bool ReadIntegerImpl(uint8_t** pos, + uint8_t* end, + std::vector<uint8_t>* out, + bool big_endian); + + // Prepends the integer stored in |val|, starting a index |start|, for + // |num_bytes| bytes onto |data|. + void PrependBytes(uint8_t* val, + int start, + int num_bytes, + std::list<uint8_t>* data); + + // Helper to prepend an ASN.1 length field. + void PrependLength(size_t size, std::list<uint8_t>* data); + + // Helper to prepend an ASN.1 type header. + void PrependTypeHeaderAndLength(uint8_t type, + uint32_t length, + std::list<uint8_t>* output); + + // Helper to prepend an ASN.1 bit string + void PrependBitString(uint8_t* val, + int num_bytes, + std::list<uint8_t>* output); + + // Read an ASN.1 length field. This also checks that the length does not + // extend beyond |end|. + bool ReadLength(uint8_t** pos, uint8_t* end, uint32_t* result); + + // Read an ASN.1 type header and its length. + bool ReadTypeHeaderAndLength(uint8_t** pos, + uint8_t* end, + uint8_t expected_tag, + uint32_t* 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_t** pos, uint8_t* end); + + // Read the RSA AlgorithmIdentifier. + bool ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end); + + // Read one of the two version fields in PrivateKeyInfo. + bool ReadVersion(uint8_t** pos, uint8_t* end); + + // The byte-significance of the stored components (modulus, etc..). + bool big_endian_; + + // Component integers of the PrivateKeyInfo + std::vector<uint8_t> modulus_; + std::vector<uint8_t> public_exponent_; + std::vector<uint8_t> private_exponent_; + std::vector<uint8_t> prime1_; + std::vector<uint8_t> prime2_; + std::vector<uint8_t> exponent1_; + std::vector<uint8_t> exponent2_; + std::vector<uint8_t> coefficient_; + + DISALLOW_COPY_AND_ASSIGN(PrivateKeyInfoCodec); +}; + +const uint8_t PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = { + 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00}; + +PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian) + : big_endian_(big_endian) {} + +PrivateKeyInfoCodec::~PrivateKeyInfoCodec() {} + +bool PrivateKeyInfoCodec::Export(std::vector<uint8_t>* output) { + std::list<uint8_t> content; + + // Version (always zero) + uint8_t 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()); + output->assign(content.begin(), content.end()); + + return true; +} + +bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8_t>* output) { + // Create a sequence with the modulus (n) and public exponent (e). + std::vector<uint8_t> bit_string; + if (!ExportPublicKey(&bit_string)) + return false; + + // Add the sequence as the contents of a bit string. + std::list<uint8_t> content; + 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()); + output->assign(content.begin(), content.end()); + + return true; +} + +bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8_t>* output) { + // Create a sequence with the modulus (n) and public exponent (e). + std::list<uint8_t> 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 everything into the output. + output->reserve(content.size()); + output->assign(content.begin(), content.end()); + + return true; +} + +bool PrivateKeyInfoCodec::Import(const std::vector<uint8_t>& input) { + if (input.empty()) { + return false; + } + + // Parse the private key info up to the public key values, ignoring + // the subsequent private key values. + uint8_t* src = const_cast<uint8_t*>(&input.front()); + uint8_t* 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_t>& in, + std::list<uint8_t>* out) { + uint8_t* ptr = const_cast<uint8_t*>(&in.front()); + PrependIntegerImpl(ptr, in.size(), out, big_endian_); +} + +// Helper to prepend an ASN.1 integer. +void PrivateKeyInfoCodec::PrependInteger(uint8_t* val, + int num_bytes, + std::list<uint8_t>* data) { + PrependIntegerImpl(val, num_bytes, data, big_endian_); +} + +void PrivateKeyInfoCodec::PrependIntegerImpl(uint8_t* val, + int num_bytes, + std::list<uint8_t>* data, + bool big_endian) { + // Reverse input if little-endian. + std::vector<uint8_t> tmp; + if (!big_endian) { + tmp.assign(val, val + num_bytes); + std::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_t front = data->front(); + if ((front & 0x80) != 0) { + data->push_front(0x00); + num_bytes++; + } + + PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data); +} + +bool PrivateKeyInfoCodec::ReadInteger(uint8_t** pos, + uint8_t* end, + std::vector<uint8_t>* out) { + return ReadIntegerImpl(pos, end, out, big_endian_); +} + +bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize( + uint8_t** pos, + uint8_t* end, + size_t expected_size, + std::vector<uint8_t>* out) { + std::vector<uint8_t> 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); + } + + out->insert(out->end(), pad, 0x00); + out->insert(out->end(), temp.begin(), temp.end()); + + // Reverse output if little-endian. + if (!big_endian_) + std::reverse(out->begin(), out->end()); + return true; +} + +bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8_t** pos, + uint8_t* end, + std::vector<uint8_t>* out, + bool big_endian) { + uint32_t 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) + std::reverse(out->begin(), out->end()); + return true; +} + +void PrivateKeyInfoCodec::PrependBytes(uint8_t* val, + int start, + int num_bytes, + std::list<uint8_t>* data) { + while (num_bytes > 0) { + --num_bytes; + data->push_front(val[start + num_bytes]); + } +} + +void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8_t>* 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_t>(size)); + } else { + uint8_t num_bytes = 0; + while (size > 0) { + data->push_front(static_cast<uint8_t>(size & 0xFF)); + size >>= 8; + num_bytes++; + } + CHECK_LE(num_bytes, 4); + data->push_front(0x80 | num_bytes); + } +} + +void PrivateKeyInfoCodec::PrependTypeHeaderAndLength( + uint8_t type, + uint32_t length, + std::list<uint8_t>* output) { + PrependLength(length, output); + output->push_front(type); +} + +void PrivateKeyInfoCodec::PrependBitString(uint8_t* val, + int num_bytes, + std::list<uint8_t>* 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_t)kBitStringTag); +} + +bool PrivateKeyInfoCodec::ReadLength(uint8_t** pos, + uint8_t* end, + uint32_t* 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_t** pos, + uint8_t* end, + uint8_t expected_tag, + uint32_t* length) { + READ_ASSERT(*pos < end); + READ_ASSERT(**pos == expected_tag); + (*pos)++; + + return ReadLength(pos, end, length); +} + +bool PrivateKeyInfoCodec::ReadSequence(uint8_t** pos, uint8_t* end) { + return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL); +} + +bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end) { + READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end); + READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier, + sizeof(kRsaAlgorithmIdentifier)) == 0); + (*pos) += sizeof(kRsaAlgorithmIdentifier); + return true; +} + +bool PrivateKeyInfoCodec::ReadVersion(uint8_t** pos, uint8_t* end) { + uint32_t length = 0; + if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length)) + return false; + + // The version should be zero. + for (uint32_t i = 0; i < length; ++i) { + READ_ASSERT(**pos == 0x00); + (*pos)++; + } + + return true; +} + } // namespace namespace crypto { |
