Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: net/ssl/ssl_platform_key_mac.cc

Issue 1178193002: Sign CertificateVerify messages on a background thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rsleevi comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "net/ssl/ssl_platform_key.h"
6
7 #include <openssl/ecdsa.h>
8 #include <openssl/obj.h>
9 #include <openssl/rsa.h>
10
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>
16
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/stl_util.h"
25 #include "base/synchronization/lock.h"
26 #include "crypto/mac_security_services_lock.h"
27 #include "crypto/openssl_util.h"
28 #include "crypto/scoped_openssl_types.h"
29 #include "net/base/net_errors.h"
30 #include "net/cert/x509_certificate.h"
31 #include "net/ssl/ssl_private_key.h"
32 #include "net/ssl/threaded_ssl_private_key.h"
33
34 namespace net {
35
36 namespace {
37
38 class ScopedCSSM_CC_HANDLE {
39 public:
40 ScopedCSSM_CC_HANDLE() : handle_(0) {}
41
42 ~ScopedCSSM_CC_HANDLE() { reset(); }
43
44 CSSM_CC_HANDLE get() const { return handle_; }
45
46 void reset() {
47 if (handle_)
48 CSSM_DeleteContext(handle_);
49 handle_ = 0;
50 }
51
52 CSSM_CC_HANDLE* InitializeInto() {
53 reset();
54 return &handle_;
55 }
56
57 private:
58 CSSM_CC_HANDLE handle_;
59
60 DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE);
61 };
62
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
65 // result.
66 SecKeyRef FetchSecKeyRefForCertificate(const X509Certificate* certificate) {
67 OSStatus status;
68 base::ScopedCFTypeRef<SecIdentityRef> identity;
69 {
70 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
Ryan Sleevi 2015/06/15 22:55:23 BUG: Not sure why this lock wasn't extended to cov
davidben 2015/06/17 20:47:02 It came from here: https://chromium.googlesource.c
71 status = SecIdentityCreateWithCertificate(
72 NULL, certificate->os_cert_handle(), identity.InitializeInto());
73 }
74 if (status != noErr) {
75 OSSTATUS_LOG(WARNING, status);
76 return NULL;
77 }
78
79 base::ScopedCFTypeRef<SecKeyRef> private_key;
80 status = SecIdentityCopyPrivateKey(identity, private_key.InitializeInto());
81 if (status != noErr) {
82 OSSTATUS_LOG(WARNING, status);
83 return NULL;
84 }
85
86 return private_key.release();
87 }
88
89 class SSLPlatformKeyMac : public ThreadedSSLPrivateKey::Delegate {
90 public:
91 SSLPlatformKeyMac(SecKeyRef key, const CSSM_KEY* cssm_key)
92 : key_(key, base::scoped_policy::RETAIN), cssm_key_(cssm_key) {
93 DCHECK(cssm_key_->KeyHeader.AlgorithmId == CSSM_ALGID_RSA ||
94 cssm_key_->KeyHeader.AlgorithmId == CSSM_ALGID_ECDSA);
95 }
96
97 ~SSLPlatformKeyMac() override {}
98
99 SSLPrivateKey::Type GetType() override {
100 if (cssm_key_->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
101 return SSLPrivateKey::Type::RSA;
102 } else {
103 DCHECK_EQ(CSSM_ALGID_ECDSA, cssm_key_->KeyHeader.AlgorithmId);
Ryan Sleevi 2015/06/15 22:55:23 This just strikes me as dangerous :/ switch (cssm
davidben 2015/06/17 20:47:02 I'm somewhat unhappy about the static_cast<EnumCla
104 return SSLPrivateKey::Type::ECDSA;
105 }
106 }
107
108 bool SupportsHash(SSLPrivateKey::Hash hash) override { return true; }
109
110 size_t GetMaxSignatureLength() override {
111 if (cssm_key_->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
112 return (cssm_key_->KeyHeader.LogicalKeySizeInBits + 7) / 8;
113 } else {
114 // LogicalKeySizeInBits is the size of an EC public key. But an
115 // ECDSA signature length depends on the size of the base point's
116 // order. For P-256, P-384, and P-521, these two sizes are the same.
117 return ECDSA_SIG_max_len((cssm_key_->KeyHeader.LogicalKeySizeInBits + 7) /
118 8);
119 }
120 }
121
122 Error SignDigest(SSLPrivateKey::Hash hash,
123 const base::StringPiece& input,
124 std::vector<uint8_t>* signature) override {
125 crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
126
127 CSSM_CSP_HANDLE csp_handle;
128 OSStatus status = SecKeyGetCSPHandle(key_.get(), &csp_handle);
129 if (status != noErr) {
130 OSSTATUS_LOG(WARNING, status);
131 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
132 }
133
134 const CSSM_ACCESS_CREDENTIALS* cssm_creds = NULL;
135 status = SecKeyGetCredentials(key_.get(), CSSM_ACL_AUTHORIZATION_SIGN,
136 kSecCredentialTypeDefault, &cssm_creds);
137 if (status != noErr) {
138 OSSTATUS_LOG(WARNING, status);
139 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
140 }
141
142 ScopedCSSM_CC_HANDLE cssm_signature;
143 if (CSSM_CSP_CreateSignatureContext(
144 csp_handle, cssm_key_->KeyHeader.AlgorithmId, cssm_creds, cssm_key_,
145 cssm_signature.InitializeInto()) != CSSM_OK) {
146 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
147 }
148
149 CSSM_DATA hash_data;
150 hash_data.Length = input.size();
151 hash_data.Data =
152 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(input.data()));
153
154 crypto::ScopedOpenSSLBytes free_digest_info;
155 if (cssm_key_->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
156 // CSSM expects the caller to prepend the DigestInfo.
157 int hash_nid = NID_undef;
158 switch (hash) {
159 case SSLPrivateKey::Hash::MD5_SHA1:
160 hash_nid = NID_md5_sha1;
161 break;
162 case SSLPrivateKey::Hash::MD5:
163 hash_nid = NID_md5;
164 break;
165 case SSLPrivateKey::Hash::SHA1:
166 hash_nid = NID_sha1;
167 break;
168 case SSLPrivateKey::Hash::SHA224:
169 hash_nid = NID_sha224;
170 break;
171 case SSLPrivateKey::Hash::SHA256:
172 hash_nid = NID_sha256;
173 break;
174 case SSLPrivateKey::Hash::SHA384:
175 hash_nid = NID_sha384;
176 break;
177 case SSLPrivateKey::Hash::SHA512:
178 hash_nid = NID_sha512;
179 break;
180 }
181 DCHECK_NE(NID_undef, hash_nid);
182 int is_alloced;
183 if (!RSA_add_pkcs1_prefix(&hash_data.Data, &hash_data.Length, &is_alloced,
184 hash_nid, hash_data.Data, hash_data.Length)) {
185 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
186 }
187 if (is_alloced)
188 free_digest_info.reset(hash_data.Data);
189
190 // Set RSA blinding.
191 CSSM_CONTEXT_ATTRIBUTE blinding_attr;
192 blinding_attr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
193 blinding_attr.AttributeLength = sizeof(uint32_t);
194 blinding_attr.Attribute.Uint32 = 1;
195 if (CSSM_UpdateContextAttributes(cssm_signature.get(), 1,
196 &blinding_attr) != CSSM_OK) {
197 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
198 }
199 }
200
201 signature->resize(GetMaxSignatureLength());
202 CSSM_DATA signature_data;
203 signature_data.Length = signature->size();
204 signature_data.Data = vector_as_array(signature);
205
206 if (CSSM_SignData(cssm_signature.get(), &hash_data, 1, CSSM_ALGID_NONE,
207 &signature_data) != CSSM_OK) {
208 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
209 }
210 signature->resize(signature_data.Length);
211 return OK;
212 }
213
214 private:
215 base::ScopedCFTypeRef<SecKeyRef> key_;
216 const CSSM_KEY* cssm_key_;
217
218 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyMac);
219 };
220
221 } // namespace
222
223 scoped_ptr<SSLPrivateKey> FetchClientCertPrivateKey(
224 const X509Certificate* certificate,
225 const scoped_refptr<base::TaskRunner>& task_runner) {
226 // Look up the private key.
227 base::ScopedCFTypeRef<SecKeyRef> private_key(
228 FetchSecKeyRefForCertificate(certificate));
229 if (!private_key)
230 return nullptr;
231
232 const CSSM_KEY* cssm_key;
233 OSStatus status = SecKeyGetCSSMKey(private_key.get(), &cssm_key);
234 if (status != noErr)
235 return nullptr;
236
237 if (cssm_key->KeyHeader.AlgorithmId != CSSM_ALGID_RSA &&
238 cssm_key->KeyHeader.AlgorithmId != CSSM_ALGID_ECDSA) {
239 LOG(ERROR) << "Unknown key type: " << cssm_key->KeyHeader.AlgorithmId;
240 return nullptr;
241 }
242 return make_scoped_ptr(new ThreadedSSLPrivateKey(
243 make_scoped_ptr(new SSLPlatformKeyMac(private_key.get(), cssm_key)),
244 task_runner));
245 }
246
247 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698