1 // Copyright 2015 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/ssl_platform_key.h"
7 #include <openssl/ecdsa.h>
8 #include <openssl/obj.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/sequenced_task_runner.h"
25 #include "base/stl_util.h"
26 #include "base/synchronization/lock.h"
27 #include "crypto/mac_security_services_lock.h"
28 #include "crypto/openssl_util.h"
29 #include "crypto/scoped_openssl_types.h"
30 #include "net/base/net_errors.h"
31 #include "net/cert/x509_certificate.h"
32 #include "net/ssl/ssl_private_key.h"
33 #include "net/ssl/threaded_ssl_private_key.h"
39 class ScopedCSSM_CC_HANDLE
{
41 ScopedCSSM_CC_HANDLE() : handle_(0) {}
42 explicit ScopedCSSM_CC_HANDLE(CSSM_CC_HANDLE handle
) : handle_(handle
) {}
44 ~ScopedCSSM_CC_HANDLE() { reset(); }
46 CSSM_CC_HANDLE
get() const { return handle_
; }
50 CSSM_DeleteContext(handle_
);
55 CSSM_CC_HANDLE handle_
;
57 DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE
);
60 // Looks up the private key for |certificate| in KeyChain and returns
61 // a SecKeyRef or nullptr on failure. The caller takes ownership of the
63 SecKeyRef
FetchSecKeyRefForCertificate(const X509Certificate
* certificate
) {
65 base::ScopedCFTypeRef
<SecIdentityRef
> identity
;
67 base::AutoLock
lock(crypto::GetMacSecurityServicesLock());
68 status
= SecIdentityCreateWithCertificate(
69 nullptr, certificate
->os_cert_handle(), identity
.InitializeInto());
71 if (status
!= noErr
) {
72 OSSTATUS_LOG(WARNING
, status
);
76 base::ScopedCFTypeRef
<SecKeyRef
> private_key
;
77 status
= SecIdentityCopyPrivateKey(identity
, private_key
.InitializeInto());
78 if (status
!= noErr
) {
79 OSSTATUS_LOG(WARNING
, status
);
83 return private_key
.release();
86 class SSLPlatformKeyMac
: public ThreadedSSLPrivateKey::Delegate
{
88 SSLPlatformKeyMac(SecKeyRef key
, const CSSM_KEY
* cssm_key
)
89 : key_(key
, base::scoped_policy::RETAIN
), cssm_key_(cssm_key
) {
90 DCHECK(cssm_key_
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
||
91 cssm_key_
->KeyHeader
.AlgorithmId
== CSSM_ALGID_ECDSA
);
94 ~SSLPlatformKeyMac() override
{}
96 SSLPrivateKey::Type
GetType() override
{
97 if (cssm_key_
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
) {
98 return SSLPrivateKey::Type::RSA
;
100 DCHECK_EQ(CSSM_ALGID_ECDSA
, cssm_key_
->KeyHeader
.AlgorithmId
);
101 return SSLPrivateKey::Type::ECDSA
;
105 bool SupportsHash(SSLPrivateKey::Hash hash
) override
{ return true; }
107 size_t GetMaxSignatureLengthInBytes() override
{
108 if (cssm_key_
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
) {
109 return (cssm_key_
->KeyHeader
.LogicalKeySizeInBits
+ 7) / 8;
111 // LogicalKeySizeInBits is the size of an EC public key. But an
112 // ECDSA signature length depends on the size of the base point's
113 // order. For P-256, P-384, and P-521, these two sizes are the same.
114 return ECDSA_SIG_max_len((cssm_key_
->KeyHeader
.LogicalKeySizeInBits
+ 7) /
119 Error
SignDigest(SSLPrivateKey::Hash hash
,
120 const base::StringPiece
& input
,
121 std::vector
<uint8_t>* signature
) override
{
122 crypto::OpenSSLErrStackTracer
tracer(FROM_HERE
);
124 CSSM_CSP_HANDLE csp_handle
;
125 OSStatus status
= SecKeyGetCSPHandle(key_
.get(), &csp_handle
);
126 if (status
!= noErr
) {
127 OSSTATUS_LOG(WARNING
, status
);
128 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
;
131 const CSSM_ACCESS_CREDENTIALS
* cssm_creds
= nullptr;
132 status
= SecKeyGetCredentials(key_
.get(), CSSM_ACL_AUTHORIZATION_SIGN
,
133 kSecCredentialTypeDefault
, &cssm_creds
);
134 if (status
!= noErr
) {
135 OSSTATUS_LOG(WARNING
, status
);
136 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
;
139 CSSM_CC_HANDLE cssm_signature_raw
= 0;
140 if (CSSM_CSP_CreateSignatureContext(
141 csp_handle
, cssm_key_
->KeyHeader
.AlgorithmId
, cssm_creds
, cssm_key_
,
142 &cssm_signature_raw
) != CSSM_OK
) {
143 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
;
145 ScopedCSSM_CC_HANDLE
cssm_signature(cssm_signature_raw
);
148 hash_data
.Length
= input
.size();
150 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(input
.data()));
152 crypto::ScopedOpenSSLBytes free_digest_info
;
153 if (cssm_key_
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
) {
154 // CSSM expects the caller to prepend the DigestInfo.
155 int hash_nid
= NID_undef
;
157 case SSLPrivateKey::Hash::MD5_SHA1
:
158 hash_nid
= NID_md5_sha1
;
160 case SSLPrivateKey::Hash::SHA1
:
163 case SSLPrivateKey::Hash::SHA256
:
164 hash_nid
= NID_sha256
;
166 case SSLPrivateKey::Hash::SHA384
:
167 hash_nid
= NID_sha384
;
169 case SSLPrivateKey::Hash::SHA512
:
170 hash_nid
= NID_sha512
;
173 DCHECK_NE(NID_undef
, hash_nid
);
175 if (!RSA_add_pkcs1_prefix(&hash_data
.Data
, &hash_data
.Length
, &is_alloced
,
176 hash_nid
, hash_data
.Data
, hash_data
.Length
)) {
177 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
;
180 free_digest_info
.reset(hash_data
.Data
);
183 CSSM_CONTEXT_ATTRIBUTE blinding_attr
;
184 blinding_attr
.AttributeType
= CSSM_ATTRIBUTE_RSA_BLINDING
;
185 blinding_attr
.AttributeLength
= sizeof(uint32_t);
186 blinding_attr
.Attribute
.Uint32
= 1;
187 if (CSSM_UpdateContextAttributes(cssm_signature
.get(), 1,
188 &blinding_attr
) != CSSM_OK
) {
189 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
;
193 signature
->resize(GetMaxSignatureLengthInBytes());
194 CSSM_DATA signature_data
;
195 signature_data
.Length
= signature
->size();
196 signature_data
.Data
= vector_as_array(signature
);
198 if (CSSM_SignData(cssm_signature
.get(), &hash_data
, 1, CSSM_ALGID_NONE
,
199 &signature_data
) != CSSM_OK
) {
200 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED
;
202 signature
->resize(signature_data
.Length
);
207 base::ScopedCFTypeRef
<SecKeyRef
> key_
;
208 const CSSM_KEY
* cssm_key_
;
210 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyMac
);
215 scoped_ptr
<SSLPrivateKey
> FetchClientCertPrivateKey(
216 X509Certificate
* certificate
,
217 scoped_refptr
<base::SequencedTaskRunner
> task_runner
) {
218 // Look up the private key.
219 base::ScopedCFTypeRef
<SecKeyRef
> private_key(
220 FetchSecKeyRefForCertificate(certificate
));
224 const CSSM_KEY
* cssm_key
;
225 OSStatus status
= SecKeyGetCSSMKey(private_key
.get(), &cssm_key
);
229 if (cssm_key
->KeyHeader
.AlgorithmId
!= CSSM_ALGID_RSA
&&
230 cssm_key
->KeyHeader
.AlgorithmId
!= CSSM_ALGID_ECDSA
) {
231 LOG(ERROR
) << "Unknown key type: " << cssm_key
->KeyHeader
.AlgorithmId
;
234 return make_scoped_ptr(new ThreadedSSLPrivateKey(
235 make_scoped_ptr(new SSLPlatformKeyMac(private_key
.get(), cssm_key
)),
236 task_runner
.Pass()));