summaryrefslogtreecommitdiffstats
path: root/base/crypto
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-07 02:46:31 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-07 02:46:31 +0000
commit308379a5ec38a9cf25a91aeaa3f11f9f7af33e95 (patch)
tree373af2c8453787823641585af0d3a5a07f8c2eb1 /base/crypto
parent4fd4de79c980066d6cfd37d1fc177f0d00bfd9b5 (diff)
downloadchromium_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.cc375
-rw-r--r--base/crypto/rsa_private_key.h127
-rw-r--r--base/crypto/rsa_private_key_mac.cc236
-rw-r--r--base/crypto/rsa_private_key_nss.cc123
-rw-r--r--base/crypto/rsa_private_key_win.cc344
-rw-r--r--base/crypto/signature_creator_unittest.cc1
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()));