summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidben <davidben@chromium.org>2016-03-23 16:55:11 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-23 23:56:19 +0000
commitc8a44434aaa8efe3621cbda4722c7527378fb6d8 (patch)
treee2786529c9a8931b54e03c5028882140de3d459f
parent7c1bd415bfbed8d80249a4e25788fbe967c97699 (diff)
downloadchromium_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.gn1
-rw-r--r--crypto/crypto.gypi1
-rw-r--r--crypto/rsa_private_key.cc389
-rw-r--r--crypto/rsa_private_key.h136
-rw-r--r--crypto/rsa_private_key_nss.cc481
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 {