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