1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/rsa_private_key.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <list>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Helper for error handling during key import.
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define READ_ASSERT(truth) \
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!(truth)) { \
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  NOTREACHED(); \
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false; \
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace crypto {
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottRSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!result->InitProvider())
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD flags = CRYPT_EXPORTABLE;
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The size is encoded as the upper 16 bits of the flags. :: sigh ::.
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  flags |= (num_bits << 16);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!CryptGenKey(result->provider_, CALG_RSA_SIGN, flags,
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   result->key_.receive()))
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result.release();
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickRSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTIMPLEMENTED();
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return NULL;
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottRSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const std::vector<uint8>& input) {
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!result->InitProvider())
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PrivateKeyInfoCodec pki(false);  // Little-Endian
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.Import(input);
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int blob_size = sizeof(PUBLICKEYSTRUC) +
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  sizeof(RSAPUBKEY) +
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.modulus()->size() +
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.prime1()->size() +
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.prime2()->size() +
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.exponent1()->size() +
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.exponent2()->size() +
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.coefficient()->size() +
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  pki.private_exponent()->size();
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_array<BYTE> blob(new BYTE[blob_size]);
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8* dest = blob.get();
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PUBLICKEYSTRUC* public_key_struc = reinterpret_cast<PUBLICKEYSTRUC*>(dest);
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  public_key_struc->bType = PRIVATEKEYBLOB;
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  public_key_struc->bVersion = 0x02;
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  public_key_struc->reserved = 0;
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  public_key_struc->aiKeyAlg = CALG_RSA_SIGN;
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += sizeof(PUBLICKEYSTRUC);
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  RSAPUBKEY* rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(dest);
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rsa_pub_key->magic = 0x32415352;
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rsa_pub_key->bitlen = pki.modulus()->size() * 8;
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int public_exponent_int = 0;
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (size_t i = pki.public_exponent()->size(); i > 0; --i) {
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    public_exponent_int <<= 8;
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    public_exponent_int |= (*pki.public_exponent())[i - 1];
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  rsa_pub_key->pubexp = public_exponent_int;
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += sizeof(RSAPUBKEY);
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(dest, &pki.modulus()->front(), pki.modulus()->size());
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.modulus()->size();
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(dest, &pki.prime1()->front(), pki.prime1()->size());
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.prime1()->size();
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(dest, &pki.prime2()->front(), pki.prime2()->size());
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.prime2()->size();
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(dest, &pki.exponent1()->front(), pki.exponent1()->size());
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.exponent1()->size();
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(dest, &pki.exponent2()->front(), pki.exponent2()->size());
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.exponent2()->size();
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(dest, &pki.coefficient()->front(), pki.coefficient()->size());
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.coefficient()->size();
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  memcpy(dest, &pki.private_exponent()->front(),
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         pki.private_exponent()->size());
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  dest += pki.private_exponent()->size();
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  READ_ASSERT(dest == blob.get() + blob_size);
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!CryptImportKey(result->provider_,
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      reinterpret_cast<uint8*>(public_key_struc), blob_size, 0,
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      CRYPT_EXPORTABLE, result->key_.receive()))
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result.release();
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickRSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::vector<uint8>& input) {
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTIMPLEMENTED();
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return NULL;
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickRSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::vector<uint8>& input) {
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NOTIMPLEMENTED();
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return NULL;
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottRSAPrivateKey::RSAPrivateKey() : provider_(NULL), key_(NULL) {}
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochRSAPrivateKey::~RSAPrivateKey() {}
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool RSAPrivateKey::InitProvider() {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE != CryptAcquireContext(provider_.receive(), NULL, NULL,
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                      PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Export the key
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD blob_length = 0;
138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!CryptExportKey(key_, 0, PRIVATEKEYBLOB, 0, NULL, &blob_length)) {
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_array<uint8> blob(new uint8[blob_length]);
144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!CryptExportKey(key_, 0, PRIVATEKEYBLOB, 0, blob.get(), &blob_length)) {
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8* pos = blob.get();
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PUBLICKEYSTRUC *publickey_struct = reinterpret_cast<PUBLICKEYSTRUC*>(pos);
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += sizeof(PUBLICKEYSTRUC);
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  RSAPUBKEY *rsa_pub_key = reinterpret_cast<RSAPUBKEY*>(pos);
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += sizeof(RSAPUBKEY);
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int mod_size = rsa_pub_key->bitlen / 8;
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int primes_size = rsa_pub_key->bitlen / 16;
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PrivateKeyInfoCodec pki(false);  // Little-Endian
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.modulus()->assign(pos, pos + mod_size);
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += mod_size;
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.prime1()->assign(pos, pos + primes_size);
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += primes_size;
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.prime2()->assign(pos, pos + primes_size);
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += primes_size;
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.exponent1()->assign(pos, pos + primes_size);
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += primes_size;
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.exponent2()->assign(pos, pos + primes_size);
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += primes_size;
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.coefficient()->assign(pos, pos + primes_size);
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += primes_size;
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.private_exponent()->assign(pos, pos + mod_size);
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pos += mod_size;
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pki.public_exponent()->assign(reinterpret_cast<uint8*>(&rsa_pub_key->pubexp),
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<uint8*>(&rsa_pub_key->pubexp) + 4);
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK_EQ(pos - blob_length, reinterpret_cast<BYTE*>(publickey_struct));
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return pki.Export(output);
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD key_info_len;
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!CryptExportPublicKeyInfo(
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      provider_, AT_SIGNATURE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NULL, &key_info_len)) {
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_array<uint8> key_info(new uint8[key_info_len]);
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!CryptExportPublicKeyInfo(
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      provider_, AT_SIGNATURE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), &key_info_len)) {
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD encoded_length;
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!CryptEncodeObject(
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), NULL,
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &encoded_length)) {
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_array<BYTE> encoded(new BYTE[encoded_length]);
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!CryptEncodeObject(
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      reinterpret_cast<CERT_PUBLIC_KEY_INFO*>(key_info.get()), encoded.get(),
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      &encoded_length)) {
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (size_t i = 0; i < encoded_length; ++i)
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    output->push_back(encoded[i]);
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace crypto
230