diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-06 21:50:15 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-06 21:50:15 +0000 |
commit | 328abdba888397ce1da982f15a0083306a5be9d8 (patch) | |
tree | d1483154af9028242c2b5d2731c7c21df9170bf4 /net/base/keygen_handler_win.cc | |
parent | ef005e0346f65ab433306888a83278f08dfebc42 (diff) | |
download | chromium_src-328abdba888397ce1da982f15a0083306a5be9d8.zip chromium_src-328abdba888397ce1da982f15a0083306a5be9d8.tar.gz chromium_src-328abdba888397ce1da982f15a0083306a5be9d8.tar.bz2 |
Simplify the Windows <keygen> implementation by making
better use of CryptoAPI.
Contributed by Ryan Sleevi <ryan.sleevi@gmail.com>.
Original review URL: http://codereview.chromium.org/1934001
R=wtc
BUG=148
TEST=Keygenhandler.SmokeTest
Review URL: http://codereview.chromium.org/2021003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46630 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base/keygen_handler_win.cc')
-rw-r--r-- | net/base/keygen_handler_win.cc | 154 |
1 files changed, 49 insertions, 105 deletions
diff --git a/net/base/keygen_handler_win.cc b/net/base/keygen_handler_win.cc index d6e5402..42997b6 100644 --- a/net/base/keygen_handler_win.cc +++ b/net/base/keygen_handler_win.cc @@ -18,42 +18,11 @@ #include "base/basictypes.h" #include "base/logging.h" #include "base/string_piece.h" +#include "base/string_util.h" #include "base/utf_string_conversions.h" namespace net { -// TODO(rsleevi): The following encoding functions are adapted from -// base/crypto/rsa_private_key.h and can/should probably be refactored. -static const uint8 kSequenceTag = 0x30; - -void PrependLength(size_t size, std::list<BYTE>* 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<BYTE>(size)); - } else { - uint8 num_bytes = 0; - while (size > 0) { - data->push_front(static_cast<BYTE>(size & 0xFF)); - size >>= 8; - num_bytes++; - } - CHECK_LE(num_bytes, 4); - data->push_front(0x80 | num_bytes); - } -} - -void PrependTypeHeaderAndLength(uint8 type, uint32 length, - std::vector<BYTE>* output) { - std::list<BYTE> type_and_length; - - PrependLength(length, &type_and_length); - type_and_length.push_front(type); - - output->insert(output->begin(), type_and_length.begin(), - type_and_length.end()); -} - bool EncodeAndAppendType(LPCSTR type, const void* to_encode, std::vector<BYTE>* output) { BOOL ok; @@ -79,22 +48,9 @@ bool EncodeAndAppendType(LPCSTR type, const void* to_encode, return true; } -// Appends a DER IA5String containing |challenge| to |output|. -// Returns true if encoding was successful. -bool EncodeChallenge(const std::string& challenge, std::vector<BYTE>* output) { - CERT_NAME_VALUE challenge_nv; - challenge_nv.dwValueType = CERT_RDN_IA5_STRING; - challenge_nv.Value.pbData = const_cast<BYTE*>( - reinterpret_cast<const BYTE*>(challenge.data())); - challenge_nv.Value.cbData = challenge.size(); - - return EncodeAndAppendType(X509_ANY_STRING, &challenge_nv, output); -} - -// Appends a DER SubjectPublicKeyInfo structure for the signing key in |prov| -// to |output|. -// Returns true if encoding was successful. -bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { +// Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing +// key in |prov| to |output|. Returns true if encoding was successful. +bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { BOOL ok; DWORD size = 0; @@ -107,9 +63,10 @@ bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { if (!ok) return false; - std::vector<BYTE> public_key_info(size); + output->resize(size); + PCERT_PUBLIC_KEY_INFO public_key_casted = - reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&public_key_info[0]); + reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&(*output)[0]); ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, szOID_RSA_RSA, 0, NULL, public_key_casted, &size); @@ -117,84 +74,71 @@ bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { if (!ok) return false; - public_key_info.resize(size); + output->resize(size); - return EncodeAndAppendType(X509_PUBLIC_KEY_INFO, &public_key_info[0], - output); + return true; } -// Generates an ASN.1 DER representation of the PublicKeyAndChallenge structure -// from the signing key of |prov| and the specified |challenge| and appends it +// Appends a DER SubjectPublicKeyInfo structure for the signing key in |prov| // to |output|. -// True if the the encoding was successfully generated. -bool GetPublicKeyAndChallenge(HCRYPTPROV prov, const std::string& challenge, - std::vector<BYTE>* output) { - if (!EncodeSubjectPublicKeyInfo(prov, output) || - !EncodeChallenge(challenge, output)) { +// Returns true if encoding was successful. +bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { + std::vector<BYTE> public_key_info; + if (!GetSubjectPublicKeyInfo(prov, &public_key_info)) return false; - } - PrependTypeHeaderAndLength(kSequenceTag, output->size(), output); - return true; + return EncodeAndAppendType(X509_PUBLIC_KEY_INFO, &public_key_info[0], + output); } // Generates a DER encoded SignedPublicKeyAndChallenge structure from the -// signing key of |prov| and the specified |challenge| string and appends it -// to |output|. +// signing key of |prov| and the specified ASCII |challenge| string and +// appends it to |output|. // True if the encoding was successfully generated. bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov, const std::string& challenge, std::string* output) { - std::vector<BYTE> pkac; - if (!GetPublicKeyAndChallenge(prov, challenge, &pkac)) + std::wstring wide_challenge = ASCIIToWide(challenge); + std::vector<BYTE> spki; + + if (!GetSubjectPublicKeyInfo(prov, &spki)) return false; - std::vector<BYTE> signature; - std::vector<BYTE> signed_pkac; - DWORD size = 0; - BOOL ok; + // PublicKeyAndChallenge ::= SEQUENCE { + // spki SubjectPublicKeyInfo, + // challenge IA5STRING + // } + CERT_KEYGEN_REQUEST_INFO pkac; + pkac.dwVersion = CERT_KEYGEN_REQUEST_V1; + pkac.SubjectPublicKeyInfo = + *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]); + pkac.pwszChallengeString = const_cast<wchar_t*>(wide_challenge.c_str()); - // While the MSDN documentation states that CERT_SIGNED_CONTENT_INFO should - // be an X.509 certificate type, for encoding this is not necessary. The - // result of encoding this structure will be a DER-encoded structure with - // the ASN.1 equivalent of - // ::= SEQUENCE { - // ToBeSigned IMPLICIT OCTET STRING, - // SignatureAlgorithm AlgorithmIdentifier, - // Signature BIT STRING - // } - // - // This happens to be the same naive type as an SPKAC, so this works. - CERT_SIGNED_CONTENT_INFO info; - info.ToBeSigned.cbData = pkac.size(); - info.ToBeSigned.pbData = &pkac[0]; - info.SignatureAlgorithm.pszObjId = szOID_RSA_MD5RSA; - info.SignatureAlgorithm.Parameters.cbData = 0; - info.SignatureAlgorithm.Parameters.pbData = NULL; - - ok = CryptSignCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, - info.ToBeSigned.pbData, info.ToBeSigned.cbData, - &info.SignatureAlgorithm, NULL, NULL, &size); + CRYPT_ALGORITHM_IDENTIFIER sig_alg; + memset(&sig_alg, 0, sizeof(sig_alg)); + sig_alg.pszObjId = szOID_RSA_MD5RSA; + + BOOL ok; + DWORD size = 0; + std::vector<BYTE> signed_pkac; + ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, + X509_KEYGEN_REQUEST_TO_BE_SIGNED, + &pkac, &sig_alg, NULL, + NULL, &size); DCHECK(ok); if (!ok) return false; - signature.resize(size); - info.Signature.cbData = signature.size(); - info.Signature.pbData = &signature[0]; - info.Signature.cUnusedBits = 0; - - ok = CryptSignCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, - info.ToBeSigned.pbData, info.ToBeSigned.cbData, - &info.SignatureAlgorithm, NULL, - info.Signature.pbData, &info.Signature.cbData); + signed_pkac.resize(size); + ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, + X509_KEYGEN_REQUEST_TO_BE_SIGNED, + &pkac, &sig_alg, NULL, + &signed_pkac[0], &size); DCHECK(ok); - if (!ok || !EncodeAndAppendType(X509_CERT, &info, &signed_pkac)) + if (!ok) return false; - output->assign(reinterpret_cast<char*>(&signed_pkac[0]), - signed_pkac.size()); - + output->assign(reinterpret_cast<char*>(&signed_pkac[0]), size); return true; } |