1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "crypto/rsa_private_key.h"
6
7#include <list>
8
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "crypto/cssm_init.h"
12
13namespace crypto {
14
15// static
16RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
17  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
18
19  CSSM_CC_HANDLE cc_handle;
20  CSSM_RETURN crtn;
21  crtn = CSSM_CSP_CreateKeyGenContext(GetSharedCSPHandle(), CSSM_ALGID_RSA,
22                                      num_bits, NULL, NULL, NULL, NULL, NULL,
23                                      &cc_handle);
24  if (crtn) {
25    NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn;
26    return NULL;
27  }
28
29  CSSM_DATA label = { 9,
30      const_cast<uint8*>(reinterpret_cast<const uint8*>("temp_key")) };
31  crtn = CSSM_GenerateKeyPair(cc_handle,
32      CSSM_KEYUSE_VERIFY,
33      CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label,
34      result->public_key(), CSSM_KEYUSE_SIGN,
35      CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, NULL,
36      result->key());
37  CSSM_DeleteContext(cc_handle);
38  if (crtn) {
39    NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn;
40    return NULL;
41  }
42
43  return result.release();
44}
45
46// static
47RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
48  NOTIMPLEMENTED();
49  return NULL;
50}
51
52// static
53RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
54    const std::vector<uint8>& input) {
55  if (input.empty())
56    return NULL;
57
58  scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
59
60  CSSM_KEY key;
61  memset(&key, 0, sizeof(key));
62  key.KeyData.Data = const_cast<uint8*>(&input.front());
63  key.KeyData.Length = input.size();
64  key.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
65  key.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
66  key.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
67  key.KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
68  key.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
69  key.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
70  key.KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
71
72  CSSM_KEY_SIZE key_size;
73  CSSM_RETURN crtn;
74  crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, &key, &key_size);
75  if (crtn) {
76    NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn;
77    return NULL;
78  }
79  key.KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
80
81  // Perform a NULL unwrap operation on the key so that result's key_
82  // instance variable points to a key that can be released via CSSM_FreeKey().
83  CSSM_ACCESS_CREDENTIALS creds;
84  memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
85  CSSM_CC_HANDLE cc_handle;
86  crtn = CSSM_CSP_CreateSymmetricContext(GetSharedCSPHandle(), CSSM_ALGID_NONE,
87      CSSM_ALGMODE_NONE, &creds, NULL, NULL, CSSM_PADDING_NONE, 0, &cc_handle);
88  if (crtn) {
89    NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn;
90    return NULL;
91  }
92  CSSM_DATA label_data, desc_data = { 0, NULL };
93  label_data.Data =
94      const_cast<uint8*>(reinterpret_cast<const uint8*>("unwrapped"));
95  label_data.Length = 9;
96  crtn = CSSM_UnwrapKey(cc_handle, NULL, &key, CSSM_KEYUSE_ANY,
97      CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label_data,
98      NULL, result->key(), &desc_data);
99  if (crtn) {
100    NOTREACHED() << "CSSM_UnwrapKey failed: " << crtn;
101    return NULL;
102  }
103
104  // Extract a public key from the private key.
105  // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key
106  // format when attempting to generate certs, so use PKCS1 instead.
107  PrivateKeyInfoCodec codec(true);
108  std::vector<uint8> private_key_data;
109  private_key_data.assign(key.KeyData.Data,
110                          key.KeyData.Data + key.KeyData.Length);
111  if (!codec.Import(private_key_data)) {
112    return NULL;
113  }
114  std::vector<uint8> public_key_data;
115  if (!codec.ExportPublicKey(&public_key_data)) {
116    return NULL;
117  }
118
119  CSSM_KEY* public_key = result->public_key();
120  size_t size = public_key_data.size();
121  public_key->KeyData.Data = reinterpret_cast<uint8*>(CSSMMalloc(size));
122  if (!public_key->KeyData.Data) {
123    NOTREACHED() << "CSSMMalloc failed";
124    return NULL;
125  }
126  memcpy(public_key->KeyData.Data, &public_key_data.front(), size);
127  public_key->KeyData.Length = size;
128  public_key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
129  public_key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
130  public_key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
131  public_key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
132  public_key->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
133  public_key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
134  public_key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
135
136  crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, public_key,
137                                 &key_size);
138  if (crtn) {
139    DLOG(ERROR) << "CSSM_QueryKeySizeInBits failed " << crtn;
140    return NULL;
141  }
142  public_key->KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
143
144  return result.release();
145}
146
147// static
148RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
149    const std::vector<uint8>& input) {
150  NOTIMPLEMENTED();
151  return NULL;
152}
153
154// static
155RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
156    const std::vector<uint8>& input) {
157  NOTIMPLEMENTED();
158  return NULL;
159}
160
161RSAPrivateKey::RSAPrivateKey() {
162  memset(&key_, 0, sizeof(key_));
163  memset(&public_key_, 0, sizeof(public_key_));
164
165  EnsureCSSMInit();
166}
167
168RSAPrivateKey::~RSAPrivateKey() {
169  if (key_.KeyData.Data) {
170    CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE);
171  }
172  if (public_key_.KeyData.Data) {
173    CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key_, CSSM_FALSE);
174  }
175}
176
177bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
178  if (!key_.KeyData.Data || !key_.KeyData.Length) {
179    return false;
180  }
181  output->clear();
182  output->insert(output->end(), key_.KeyData.Data,
183                key_.KeyData.Data + key_.KeyData.Length);
184  return true;
185}
186
187bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
188  PrivateKeyInfoCodec private_key_info(true);
189  std::vector<uint8> private_key_data;
190  private_key_data.assign(key_.KeyData.Data,
191                          key_.KeyData.Data + key_.KeyData.Length);
192  return (private_key_info.Import(private_key_data) &&
193          private_key_info.ExportPublicKeyInfo(output));
194}
195
196}  // namespace crypto
197