From 328abdba888397ce1da982f15a0083306a5be9d8 Mon Sep 17 00:00:00 2001 From: "wtc@chromium.org" Date: Thu, 6 May 2010 21:50:15 +0000 Subject: Simplify the Windows implementation by making better use of CryptoAPI. Contributed by Ryan Sleevi . 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 --- net/base/keygen_handler_win.cc | 154 +++++++++++++---------------------------- 1 file changed, 49 insertions(+), 105 deletions(-) (limited to 'net/base/keygen_handler_win.cc') 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* 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(size)); - } else { - uint8 num_bytes = 0; - while (size > 0) { - data->push_front(static_cast(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* output) { - std::list 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* 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* output) { - CERT_NAME_VALUE challenge_nv; - challenge_nv.dwValueType = CERT_RDN_IA5_STRING; - challenge_nv.Value.pbData = const_cast( - reinterpret_cast(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* 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* output) { BOOL ok; DWORD size = 0; @@ -107,9 +63,10 @@ bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector* output) { if (!ok) return false; - std::vector public_key_info(size); + output->resize(size); + PCERT_PUBLIC_KEY_INFO public_key_casted = - reinterpret_cast(&public_key_info[0]); + reinterpret_cast(&(*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* 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* output) { - if (!EncodeSubjectPublicKeyInfo(prov, output) || - !EncodeChallenge(challenge, output)) { +// Returns true if encoding was successful. +bool EncodeSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector* output) { + std::vector 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 pkac; - if (!GetPublicKeyAndChallenge(prov, challenge, &pkac)) + std::wstring wide_challenge = ASCIIToWide(challenge); + std::vector spki; + + if (!GetSubjectPublicKeyInfo(prov, &spki)) return false; - std::vector signature; - std::vector 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(&spki[0]); + pkac.pwszChallengeString = const_cast(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 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(&signed_pkac[0]), - signed_pkac.size()); - + output->assign(reinterpret_cast(&signed_pkac[0]), size); return true; } -- cgit v1.1