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