1 // Copyright 2014 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 "net/ssl/openssl_platform_key.h"
7 #include <openssl/err.h>
8 #include <openssl/evp.h>
9 #include <openssl/rsa.h>
11 #include <Security/cssm.h>
12 #include <Security/SecBase.h>
13 #include <Security/SecCertificate.h>
14 #include <Security/SecIdentity.h>
15 #include <Security/SecKey.h>
17 #include "base/lazy_instance.h"
18 #include "base/location.h"
19 #include "base/logging.h"
20 #include "base/mac/mac_logging.h"
21 #include "base/mac/scoped_cftyperef.h"
22 #include "base/memory/scoped_policy.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/synchronization/lock.h"
25 #include "crypto/mac_security_services_lock.h"
26 #include "net/base/net_errors.h"
27 #include "net/cert/x509_certificate.h"
28 #include "net/ssl/openssl_ssl_util.h"
34 class ScopedCSSM_CC_HANDLE
{
36 ScopedCSSM_CC_HANDLE() : handle_(0) {
39 ~ScopedCSSM_CC_HANDLE() {
43 CSSM_CC_HANDLE
get() const {
49 CSSM_DeleteContext(handle_
);
53 CSSM_CC_HANDLE
* InitializeInto() {
58 CSSM_CC_HANDLE handle_
;
60 DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE
);
63 // Looks up the private key for |certificate| in KeyChain and returns
64 // a SecKeyRef or NULL on failure. The caller takes ownership of the
66 SecKeyRef
FetchSecKeyRefForCertificate(const X509Certificate
* certificate
) {
68 base::ScopedCFTypeRef
<SecIdentityRef
> identity
;
70 base::AutoLock
lock(crypto::GetMacSecurityServicesLock());
71 status
= SecIdentityCreateWithCertificate(
72 NULL
, certificate
->os_cert_handle(), identity
.InitializeInto());
74 if (status
!= noErr
) {
75 OSSTATUS_LOG(WARNING
, status
);
79 base::ScopedCFTypeRef
<SecKeyRef
> private_key
;
80 status
= SecIdentityCopyPrivateKey(identity
, private_key
.InitializeInto());
81 if (status
!= noErr
) {
82 OSSTATUS_LOG(WARNING
, status
);
86 return private_key
.release();
89 extern const RSA_METHOD mac_rsa_method
;
90 extern const ECDSA_METHOD mac_ecdsa_method
;
92 // KeyExData contains the data that is contained in the EX_DATA of the
93 // RSA and ECDSA objects that are created to wrap Mac system keys.
95 KeyExData(SecKeyRef key
, const CSSM_KEY
* cssm_key
)
96 : key(key
, base::scoped_policy::RETAIN
), cssm_key(cssm_key
) {}
98 base::ScopedCFTypeRef
<SecKeyRef
> key
;
99 const CSSM_KEY
* cssm_key
;
102 // ExDataDup is called when one of the RSA or EC_KEY objects is
103 // duplicated. This is not supported and should never happen.
104 int ExDataDup(CRYPTO_EX_DATA
* to
,
105 const CRYPTO_EX_DATA
* from
,
114 // ExDataFree is called when one of the RSA or EC_KEY objects is freed.
115 void ExDataFree(void* parent
,
117 CRYPTO_EX_DATA
* ex_data
,
119 long argl
, void* argp
) {
120 KeyExData
* data
= reinterpret_cast<KeyExData
*>(ptr
);
124 // BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA
125 // by forwarding the requested operations to Apple's CSSM
127 class BoringSSLEngine
{
130 : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
135 ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
140 engine_(ENGINE_new()) {
141 ENGINE_set_RSA_method(
142 engine_
, &mac_rsa_method
, sizeof(mac_rsa_method
));
143 ENGINE_set_ECDSA_method(
144 engine_
, &mac_ecdsa_method
, sizeof(mac_ecdsa_method
));
147 int rsa_ex_index() const { return rsa_index_
; }
148 int ec_key_ex_index() const { return ec_key_index_
; }
150 const ENGINE
* engine() const { return engine_
; }
153 const int rsa_index_
;
154 const int ec_key_index_
;
155 ENGINE
* const engine_
;
158 base::LazyInstance
<BoringSSLEngine
>::Leaky global_boringssl_engine
=
159 LAZY_INSTANCE_INITIALIZER
;
161 // Helper function for making a signature.
163 // MakeCSSMSignature uses the key information in |ex_data| to sign the
164 // |in_len| bytes pointed by |in|. It writes up to |max_out| bytes
165 // into the buffer pointed to by |out|, setting |*out_len| to the
166 // number of bytes written. It returns 1 on success and 0 on failure.
167 int MakeCSSMSignature(const KeyExData
* ex_data
,
173 CSSM_CSP_HANDLE csp_handle
;
174 OSStatus status
= SecKeyGetCSPHandle(ex_data
->key
.get(), &csp_handle
);
175 if (status
!= noErr
) {
176 OSSTATUS_LOG(WARNING
, status
);
177 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
181 const CSSM_ACCESS_CREDENTIALS
* cssm_creds
= NULL
;
182 status
= SecKeyGetCredentials(ex_data
->key
.get(), CSSM_ACL_AUTHORIZATION_SIGN
,
183 kSecCredentialTypeDefault
, &cssm_creds
);
184 if (status
!= noErr
) {
185 OSSTATUS_LOG(WARNING
, status
);
186 OpenSSLPutNetError(FROM_HERE
, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
);
190 ScopedCSSM_CC_HANDLE cssm_signature
;
191 if (CSSM_CSP_CreateSignatureContext(
192 csp_handle
, ex_data
->cssm_key
->KeyHeader
.AlgorithmId
, cssm_creds
,
193 ex_data
->cssm_key
, cssm_signature
.InitializeInto()) != CSSM_OK
) {
194 OpenSSLPutNetError(FROM_HERE
, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
);
198 if (ex_data
->cssm_key
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
) {
200 CSSM_CONTEXT_ATTRIBUTE blinding_attr
;
201 blinding_attr
.AttributeType
= CSSM_ATTRIBUTE_RSA_BLINDING
;
202 blinding_attr
.AttributeLength
= sizeof(uint32
);
203 blinding_attr
.Attribute
.Uint32
= 1;
204 if (CSSM_UpdateContextAttributes(
205 cssm_signature
.get(), 1, &blinding_attr
) != CSSM_OK
) {
206 OpenSSLPutNetError(FROM_HERE
, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
);
212 hash_data
.Length
= in_len
;
213 hash_data
.Data
= const_cast<uint8
*>(in
);
215 CSSM_DATA signature_data
;
216 signature_data
.Length
= max_out
;
217 signature_data
.Data
= out
;
219 if (CSSM_SignData(cssm_signature
.get(), &hash_data
, 1,
220 CSSM_ALGID_NONE
, &signature_data
) != CSSM_OK
) {
221 OpenSSLPutNetError(FROM_HERE
, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
);
225 *out_len
= signature_data
.Length
;
229 // Custom RSA_METHOD that uses the platform APIs for signing.
231 const KeyExData
* RsaGetExData(const RSA
* rsa
) {
232 return reinterpret_cast<const KeyExData
*>(
233 RSA_get_ex_data(rsa
, global_boringssl_engine
.Get().rsa_ex_index()));
236 size_t RsaMethodSize(const RSA
*rsa
) {
237 const KeyExData
*ex_data
= RsaGetExData(rsa
);
238 return (ex_data
->cssm_key
->KeyHeader
.LogicalKeySizeInBits
+ 7) / 8;
241 int RsaMethodEncrypt(RSA
* rsa
,
249 OPENSSL_PUT_ERROR(RSA
, encrypt
, RSA_R_UNKNOWN_ALGORITHM_TYPE
);
253 int RsaMethodSignRaw(RSA
* rsa
,
260 // Only support PKCS#1 padding.
261 DCHECK_EQ(RSA_PKCS1_PADDING
, padding
);
262 if (padding
!= RSA_PKCS1_PADDING
) {
263 OPENSSL_PUT_ERROR(RSA
, sign_raw
, RSA_R_UNKNOWN_PADDING_TYPE
);
267 const KeyExData
*ex_data
= RsaGetExData(rsa
);
269 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
272 DCHECK_EQ(CSSM_ALGID_RSA
, ex_data
->cssm_key
->KeyHeader
.AlgorithmId
);
274 return MakeCSSMSignature(ex_data
, out_len
, out
, max_out
, in
, in_len
);
277 int RsaMethodDecrypt(RSA
* rsa
,
285 OPENSSL_PUT_ERROR(RSA
, decrypt
, RSA_R_UNKNOWN_ALGORITHM_TYPE
);
289 int RsaMethodVerifyRaw(RSA
* rsa
,
297 OPENSSL_PUT_ERROR(RSA
, verify_raw
, RSA_R_UNKNOWN_ALGORITHM_TYPE
);
301 const RSA_METHOD mac_rsa_method
= {
318 NULL
/* bn_mod_exp */,
323 crypto::ScopedEVP_PKEY
CreateRSAWrapper(SecKeyRef key
,
324 const CSSM_KEY
* cssm_key
) {
325 crypto::ScopedRSA
rsa(
326 RSA_new_method(global_boringssl_engine
.Get().engine()));
328 return crypto::ScopedEVP_PKEY();
331 rsa
.get(), global_boringssl_engine
.Get().rsa_ex_index(),
332 new KeyExData(key
, cssm_key
));
334 crypto::ScopedEVP_PKEY
pkey(EVP_PKEY_new());
336 return crypto::ScopedEVP_PKEY();
338 if (!EVP_PKEY_set1_RSA(pkey
.get(), rsa
.get()))
339 return crypto::ScopedEVP_PKEY();
344 // Custom ECDSA_METHOD that uses the platform APIs.
345 // Note that for now, only signing through ECDSA_sign() is really supported.
346 // all other method pointers are either stubs returning errors, or no-ops.
348 const KeyExData
* EcKeyGetExData(const EC_KEY
* ec_key
) {
349 return reinterpret_cast<const KeyExData
*>(EC_KEY_get_ex_data(
350 ec_key
, global_boringssl_engine
.Get().ec_key_ex_index()));
353 size_t EcdsaMethodGroupOrderSize(const EC_KEY
* ec_key
) {
354 const KeyExData
* ex_data
= EcKeyGetExData(ec_key
);
355 // LogicalKeySizeInBits is the size of an EC public key. But an
356 // ECDSA signature length depends on the size of the base point's
357 // order. For P-256, P-384, and P-521, these two sizes are the same.
358 return (ex_data
->cssm_key
->KeyHeader
.LogicalKeySizeInBits
+ 7) / 8;
361 int EcdsaMethodSign(const uint8_t* digest
,
364 unsigned int* sig_len
,
366 const KeyExData
*ex_data
= EcKeyGetExData(ec_key
);
368 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
371 DCHECK_EQ(CSSM_ALGID_ECDSA
, ex_data
->cssm_key
->KeyHeader
.AlgorithmId
);
373 // TODO(davidben): Fix BoringSSL to make sig_len a size_t*.
375 int ret
= MakeCSSMSignature(
376 ex_data
, &out_len
, sig
, ECDSA_size(ec_key
), digest
, digest_len
);
383 int EcdsaMethodVerify(const uint8_t* digest
,
389 OPENSSL_PUT_ERROR(ECDSA
, ECDSA_do_verify
, ECDSA_R_NOT_IMPLEMENTED
);
393 const ECDSA_METHOD mac_ecdsa_method
= {
402 EcdsaMethodGroupOrderSize
,
408 crypto::ScopedEVP_PKEY
CreateECDSAWrapper(SecKeyRef key
,
409 const CSSM_KEY
* cssm_key
) {
410 crypto::ScopedEC_KEY
ec_key(
411 EC_KEY_new_method(global_boringssl_engine
.Get().engine()));
413 return crypto::ScopedEVP_PKEY();
416 ec_key
.get(), global_boringssl_engine
.Get().ec_key_ex_index(),
417 new KeyExData(key
, cssm_key
));
419 crypto::ScopedEVP_PKEY
pkey(EVP_PKEY_new());
421 return crypto::ScopedEVP_PKEY();
423 if (!EVP_PKEY_set1_EC_KEY(pkey
.get(), ec_key
.get()))
424 return crypto::ScopedEVP_PKEY();
429 crypto::ScopedEVP_PKEY
CreatePkeyWrapper(SecKeyRef key
) {
430 const CSSM_KEY
* cssm_key
;
431 OSStatus status
= SecKeyGetCSSMKey(key
, &cssm_key
);
433 return crypto::ScopedEVP_PKEY();
435 switch (cssm_key
->KeyHeader
.AlgorithmId
) {
437 return CreateRSAWrapper(key
, cssm_key
);
438 case CSSM_ALGID_ECDSA
:
439 return CreateECDSAWrapper(key
, cssm_key
);
441 // TODO(davidben): Filter out anything other than ECDSA and RSA
442 // elsewhere. We don't support other key types.
444 LOG(ERROR
) << "Unknown key type";
445 return crypto::ScopedEVP_PKEY();
451 crypto::ScopedEVP_PKEY
FetchClientCertPrivateKey(
452 const X509Certificate
* certificate
) {
453 // Look up the private key.
454 base::ScopedCFTypeRef
<SecKeyRef
> private_key(
455 FetchSecKeyRefForCertificate(certificate
));
457 return crypto::ScopedEVP_PKEY();
459 // Create an EVP_PKEY wrapper.
460 return CreatePkeyWrapper(private_key
.get());