1 // Copyright (c) 2012 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(
75 GetSharedCSPHandle(), CSSM_INVALID_HANDLE
, &key
, &key_size
);
77 NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn
;
80 key
.KeyHeader
.LogicalKeySizeInBits
= key_size
.LogicalKeySizeInBits
;
82 // Perform a NULL unwrap operation on the key so that result's key_
83 // instance variable points to a key that can be released via CSSM_FreeKey().
84 CSSM_ACCESS_CREDENTIALS creds
;
85 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
86 CSSM_CC_HANDLE cc_handle
;
87 crtn
= CSSM_CSP_CreateSymmetricContext(GetSharedCSPHandle(), CSSM_ALGID_NONE
,
88 CSSM_ALGMODE_NONE
, &creds
, NULL
, NULL
, CSSM_PADDING_NONE
, 0, &cc_handle
);
90 NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn
;
93 CSSM_DATA label_data
, desc_data
= { 0, NULL
};
95 const_cast<uint8
*>(reinterpret_cast<const uint8
*>("unwrapped"));
96 label_data
.Length
= 9;
97 crtn
= CSSM_UnwrapKey(cc_handle
, NULL
, &key
, CSSM_KEYUSE_ANY
,
98 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
, &label_data
,
99 NULL
, result
->key(), &desc_data
);
101 NOTREACHED() << "CSSM_UnwrapKey failed: " << crtn
;
105 // Extract a public key from the private key.
106 // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key
107 // format when attempting to generate certs, so use PKCS1 instead.
108 PrivateKeyInfoCodec
codec(true);
109 std::vector
<uint8
> private_key_data
;
110 private_key_data
.assign(key
.KeyData
.Data
,
111 key
.KeyData
.Data
+ key
.KeyData
.Length
);
112 if (!codec
.Import(private_key_data
)) {
115 std::vector
<uint8
> public_key_data
;
116 if (!codec
.ExportPublicKey(&public_key_data
)) {
120 CSSM_KEY
* public_key
= result
->public_key();
121 size_t size
= public_key_data
.size();
122 public_key
->KeyData
.Data
= reinterpret_cast<uint8
*>(CSSMMalloc(size
));
123 if (!public_key
->KeyData
.Data
) {
124 NOTREACHED() << "CSSMMalloc failed";
127 memcpy(public_key
->KeyData
.Data
, &public_key_data
.front(), size
);
128 public_key
->KeyData
.Length
= size
;
129 public_key
->KeyHeader
.Format
= CSSM_KEYBLOB_RAW_FORMAT_PKCS1
;
130 public_key
->KeyHeader
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
131 public_key
->KeyHeader
.BlobType
= CSSM_KEYBLOB_RAW
;
132 public_key
->KeyHeader
.AlgorithmId
= CSSM_ALGID_RSA
;
133 public_key
->KeyHeader
.KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
134 public_key
->KeyHeader
.KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
135 public_key
->KeyHeader
.KeyUsage
= CSSM_KEYUSE_ANY
;
137 crtn
= CSSM_QueryKeySizeInBits(
138 GetSharedCSPHandle(), CSSM_INVALID_HANDLE
, public_key
, &key_size
);
140 DLOG(ERROR
) << "CSSM_QueryKeySizeInBits failed " << crtn
;
143 public_key
->KeyHeader
.LogicalKeySizeInBits
= key_size
.LogicalKeySizeInBits
;
145 return result
.release();
149 RSAPrivateKey
* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
150 const std::vector
<uint8
>& input
) {
156 RSAPrivateKey
* RSAPrivateKey::FindFromPublicKeyInfo(
157 const std::vector
<uint8
>& input
) {
162 RSAPrivateKey::RSAPrivateKey() {
163 memset(&key_
, 0, sizeof(key_
));
164 memset(&public_key_
, 0, sizeof(public_key_
));
169 RSAPrivateKey::~RSAPrivateKey() {
170 if (key_
.KeyData
.Data
) {
171 CSSM_FreeKey(GetSharedCSPHandle(), NULL
, &key_
, CSSM_FALSE
);
173 if (public_key_
.KeyData
.Data
) {
174 CSSM_FreeKey(GetSharedCSPHandle(), NULL
, &public_key_
, CSSM_FALSE
);
178 RSAPrivateKey
* RSAPrivateKey::Copy() const {
179 std::vector
<uint8
> key_bytes
;
180 if (!ExportPrivateKey(&key_bytes
))
182 return CreateFromPrivateKeyInfo(key_bytes
);
185 bool RSAPrivateKey::ExportPrivateKey(std::vector
<uint8
>* output
) const {
186 if (!key_
.KeyData
.Data
|| !key_
.KeyData
.Length
) {
190 output
->insert(output
->end(), key_
.KeyData
.Data
,
191 key_
.KeyData
.Data
+ key_
.KeyData
.Length
);
195 bool RSAPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) const {
196 PrivateKeyInfoCodec
private_key_info(true);
197 std::vector
<uint8
> private_key_data
;
198 private_key_data
.assign(key_
.KeyData
.Data
,
199 key_
.KeyData
.Data
+ key_
.KeyData
.Length
);
200 return (private_key_info
.Import(private_key_data
) &&
201 private_key_info
.ExportPublicKeyInfo(output
));
204 } // namespace crypto