15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/keygen_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wincrypt.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(lib, "crypt32.lib") 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <rpc.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(lib, "rpcrt4.lib") 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/capi_util.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/scoped_capi_types.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Assigns the contents of a CERT_PUBLIC_KEY_INFO structure for the signing 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// key in |prov| to |output|. Returns true if encoding was successful. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetSubjectPublicKeyInfo(HCRYPTPROV prov, std::vector<BYTE>* output) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD size = 0; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From the private key stored in HCRYPTPROV, obtain the public key, stored 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as a CERT_PUBLIC_KEY_INFO structure. Currently, only RSA public keys are 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // supported. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) szOID_RSA_RSA, 0, NULL, NULL, &size); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->resize(size); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PCERT_PUBLIC_KEY_INFO public_key_casted = 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&(*output)[0]); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = CryptExportPublicKeyInfoEx(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) szOID_RSA_RSA, 0, NULL, public_key_casted, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &size); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->resize(size); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generates a DER encoded SignedPublicKeyAndChallenge structure from the 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// signing key of |prov| and the specified ASCII |challenge| string and 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// appends it to |output|. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// True if the encoding was successfully generated. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetSignedPublicKeyAndChallenge(HCRYPTPROV prov, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& challenge, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* output) { 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::wstring wide_challenge = base::ASCIIToWide(challenge); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<BYTE> spki; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetSubjectPublicKeyInfo(prov, &spki)) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PublicKeyAndChallenge ::= SEQUENCE { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spki SubjectPublicKeyInfo, 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // challenge IA5STRING 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_KEYGEN_REQUEST_INFO pkac; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pkac.dwVersion = CERT_KEYGEN_REQUEST_V1; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pkac.SubjectPublicKeyInfo = 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(&spki[0]); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pkac.pwszChallengeString = const_cast<wchar_t*>(wide_challenge.c_str()); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPT_ALGORITHM_IDENTIFIER sig_alg; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&sig_alg, 0, sizeof(sig_alg)); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sig_alg.pszObjId = szOID_RSA_MD5RSA; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD size = 0; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<BYTE> signed_pkac; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) X509_KEYGEN_REQUEST_TO_BE_SIGNED, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &pkac, &sig_alg, NULL, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, &size); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signed_pkac.resize(size); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = CryptSignAndEncodeCertificate(prov, AT_KEYEXCHANGE, X509_ASN_ENCODING, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) X509_KEYGEN_REQUEST_TO_BE_SIGNED, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &pkac, &sig_alg, NULL, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &signed_pkac[0], &size); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->assign(reinterpret_cast<char*>(&signed_pkac[0]), size); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generates a unique name for the container which will store the key that is 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// generated. The traditional Windows approach is to use a GUID here. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring GetNewKeyContainerId() { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RPC_STATUS status = RPC_S_OK; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::wstring result; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UUID id = { 0 }; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = UuidCreateSequential(&id); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RPC_WSTR rpc_string = NULL; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status = UuidToString(&id, &rpc_string); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status != RPC_S_OK) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RPC_WSTR is unsigned short*. wchar_t is a built-in type of Visual C++, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so the type cast is necessary. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.assign(reinterpret_cast<wchar_t*>(rpc_string)); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RpcStringFree(&rpc_string); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a helper struct designed to optionally delete a key after releasing 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the associated provider. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct KeyContainer { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit KeyContainer(bool delete_keyset) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : delete_keyset_(delete_keyset) {} 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~KeyContainer() { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (provider_) { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) provider_.reset(); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (delete_keyset_ && !key_id_.empty()) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCRYPTPROV provider; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) crypto::CryptAcquireContextLocked(&provider, key_id_.c_str(), NULL, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PROV_RSA_FULL, CRYPT_SILENT | CRYPT_DELETEKEYSET); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) crypto::ScopedHCRYPTPROV provider_; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::wstring key_id_; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool delete_keyset_; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string KeygenHandler::GenKeyAndSignChallenge() { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) KeyContainer key_container(!stores_key_); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rsleevi): Have the user choose which provider they should use, which 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // needs to be filtered by those providers which can provide the key type 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // requested or the key size requested. This is especially important for 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // generating certificates that will be stored on smart cards. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kMaxAttempts = 5; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int attempt; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (attempt = 0; attempt < kMaxAttempts; ++attempt) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Per MSDN documentation for CryptAcquireContext, if applications will be 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // creating their own keys, they should ensure unique naming schemes to 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // prevent overlap with any other applications or consumers of CSPs, and 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // *should not* store new keys within the default, NULL key container. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_container.key_id_ = GetNewKeyContainerId(); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key_container.key_id_.empty()) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only create new key containers, so that existing key containers are not 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overwritten. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (crypto::CryptAcquireContextLocked(key_container.provider_.receive(), 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_container.key_id_.c_str(), NULL, PROV_RSA_FULL, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPT_SILENT | CRYPT_NEWKEYSET)) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetLastError() != NTE_BAD_KEYSET) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider " 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "context: " << GetLastError(); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (attempt == kMaxAttempts) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Keygen failed: Couldn't acquire a CryptoAPI provider " 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "context: Max retries exceeded"; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) crypto::ScopedHCRYPTKEY key; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CryptGenKey(key_container.provider_, CALG_RSA_KEYX, 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (key_size_in_bits_ << 16) | CRYPT_EXPORTABLE, key.receive())) { 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Keygen failed: Couldn't generate an RSA key"; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string spkac; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetSignedPublicKeyAndChallenge(key_container.provider_, challenge_, 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &spkac)) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Keygen failed: Couldn't generate the signed public key " 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "and challenge"; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string result; 214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Base64Encode(spkac, &result); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Keygen succeeded"; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 222