• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace crypto {
14 
15 // static
Create(uint16 num_bits)16 RSAPrivateKey* 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
CreateSensitive(uint16 num_bits)47 RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
48   NOTIMPLEMENTED();
49   return NULL;
50 }
51 
52 // static
CreateFromPrivateKeyInfo(const std::vector<uint8> & input)53 RSAPrivateKey* 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
CreateSensitiveFromPrivateKeyInfo(const std::vector<uint8> & input)148 RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
149     const std::vector<uint8>& input) {
150   NOTIMPLEMENTED();
151   return NULL;
152 }
153 
154 // static
FindFromPublicKeyInfo(const std::vector<uint8> & input)155 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
156     const std::vector<uint8>& input) {
157   NOTIMPLEMENTED();
158   return NULL;
159 }
160 
RSAPrivateKey()161 RSAPrivateKey::RSAPrivateKey() {
162   memset(&key_, 0, sizeof(key_));
163   memset(&public_key_, 0, sizeof(public_key_));
164 
165   EnsureCSSMInit();
166 }
167 
~RSAPrivateKey()168 RSAPrivateKey::~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 
ExportPrivateKey(std::vector<uint8> * output)177 bool 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 
ExportPublicKey(std::vector<uint8> * output)187 bool 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