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.
5 #include "crypto/rsa_private_key.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "crypto/cssm_init.h"
16 RSAPrivateKey
* RSAPrivateKey::Create(uint16 num_bits
) {
17 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
19 CSSM_CC_HANDLE cc_handle
;
21 crtn
= CSSM_CSP_CreateKeyGenContext(GetSharedCSPHandle(), CSSM_ALGID_RSA
,
22 num_bits
, NULL
, NULL
, NULL
, NULL
, NULL
,
25 NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn
;
29 CSSM_DATA label
= { 9,
30 const_cast<uint8
*>(reinterpret_cast<const uint8
*>("temp_key")) };
31 crtn
= CSSM_GenerateKeyPair(cc_handle
,
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
,
37 CSSM_DeleteContext(cc_handle
);
39 NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn
;
43 return result
.release();
47 RSAPrivateKey
* RSAPrivateKey::CreateSensitive(uint16 num_bits
) {
53 RSAPrivateKey
* RSAPrivateKey::CreateFromPrivateKeyInfo(
54 const std::vector
<uint8
>& input
) {
58 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
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
;
72 CSSM_KEY_SIZE key_size
;
74 crtn
= CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL
, &key
, &key_size
);
76 NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn
;
79 key
.KeyHeader
.LogicalKeySizeInBits
= key_size
.LogicalKeySizeInBits
;
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
);
89 NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn
;
92 CSSM_DATA label_data
, desc_data
= { 0, NULL
};
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
);
100 NOTREACHED() << "CSSM_UnwrapKey failed: " << crtn
;
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
)) {
114 std::vector
<uint8
> public_key_data
;
115 if (!codec
.ExportPublicKey(&public_key_data
)) {
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";
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
;
136 crtn
= CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL
, public_key
,
139 DLOG(ERROR
) << "CSSM_QueryKeySizeInBits failed " << crtn
;
142 public_key
->KeyHeader
.LogicalKeySizeInBits
= key_size
.LogicalKeySizeInBits
;
144 return result
.release();
148 RSAPrivateKey
* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
149 const std::vector
<uint8
>& input
) {
155 RSAPrivateKey
* RSAPrivateKey::FindFromPublicKeyInfo(
156 const std::vector
<uint8
>& input
) {
161 RSAPrivateKey::RSAPrivateKey() {
162 memset(&key_
, 0, sizeof(key_
));
163 memset(&public_key_
, 0, sizeof(public_key_
));
168 RSAPrivateKey::~RSAPrivateKey() {
169 if (key_
.KeyData
.Data
) {
170 CSSM_FreeKey(GetSharedCSPHandle(), NULL
, &key_
, CSSM_FALSE
);
172 if (public_key_
.KeyData
.Data
) {
173 CSSM_FreeKey(GetSharedCSPHandle(), NULL
, &public_key_
, CSSM_FALSE
);
177 bool RSAPrivateKey::ExportPrivateKey(std::vector
<uint8
>* output
) {
178 if (!key_
.KeyData
.Data
|| !key_
.KeyData
.Length
) {
182 output
->insert(output
->end(), key_
.KeyData
.Data
,
183 key_
.KeyData
.Data
+ key_
.KeyData
.Length
);
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
));
196 } // namespace crypto