| Index: net/base/keygen_handler_win.cc
|
| ===================================================================
|
| --- net/base/keygen_handler_win.cc (revision 46203)
|
| +++ net/base/keygen_handler_win.cc (working copy)
|
| @@ -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 @@
|
| 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 @@
|
| 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,67 @@
|
| 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;
|
| + CERT_KEYGEN_REQUEST_INFO request;
|
| + request.dwVersion = CERT_KEYGEN_REQUEST_V1;
|
| + request.SubjectPublicKeyInfo =
|
| + *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]);
|
| + request.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;
|
| + CRYPT_ALGORITHM_IDENTIFIER sig_alg;
|
| + memset(&sig_alg, 0, sizeof(sig_alg));
|
| + sig_alg.pszObjId = szOID_RSA_MD5RSA;
|
|
|
| - ok = CryptSignCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
|
| - info.ToBeSigned.pbData, info.ToBeSigned.cbData,
|
| - &info.SignatureAlgorithm, NULL, NULL, &size);
|
| + BOOL ok;
|
| + DWORD size = 0;
|
| + std::vector<BYTE> signed_pkac;
|
| + ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING,
|
| + X509_KEYGEN_REQUEST_TO_BE_SIGNED,
|
| + &request, &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,
|
| + &request, &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;
|
| }
|
|
|
|
|