diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-07 02:46:31 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-07 02:46:31 +0000 |
commit | 308379a5ec38a9cf25a91aeaa3f11f9f7af33e95 (patch) | |
tree | 373af2c8453787823641585af0d3a5a07f8c2eb1 /base/crypto/rsa_private_key_win.cc | |
parent | 4fd4de79c980066d6cfd37d1fc177f0d00bfd9b5 (diff) | |
download | chromium_src-308379a5ec38a9cf25a91aeaa3f11f9f7af33e95.zip chromium_src-308379a5ec38a9cf25a91aeaa3f11f9f7af33e95.tar.gz chromium_src-308379a5ec38a9cf25a91aeaa3f11f9f7af33e95.tar.bz2 |
Refactor ASN1 parsing/serialization
Review URL: http://codereview.chromium.org/242136
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28223 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/crypto/rsa_private_key_win.cc')
-rw-r--r-- | base/crypto/rsa_private_key_win.cc | 344 |
1 files changed, 45 insertions, 299 deletions
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) { |