Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / ssl / openssl_platform_key_mac.cc
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/openssl_platform_key.h"
6
7 #include <openssl/err.h>
8 #include <openssl/evp.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/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"
29
30 namespace net {
31
32 namespace {
33
34 class ScopedCSSM_CC_HANDLE {
35  public:
36   ScopedCSSM_CC_HANDLE() : handle_(0) {
37   }
38
39   ~ScopedCSSM_CC_HANDLE() {
40     reset();
41   }
42
43   CSSM_CC_HANDLE get() const {
44     return handle_;
45   }
46
47   void reset() {
48     if (handle_)
49       CSSM_DeleteContext(handle_);
50     handle_ = 0;
51   }
52
53   CSSM_CC_HANDLE* InitializeInto() {
54     reset();
55     return &handle_;
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());
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 extern const RSA_METHOD mac_rsa_method;
90 extern const ECDSA_METHOD mac_ecdsa_method;
91
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.
94 struct KeyExData {
95   KeyExData(SecKeyRef key, const CSSM_KEY* cssm_key)
96       : key(key, base::scoped_policy::RETAIN), cssm_key(cssm_key) {}
97
98   base::ScopedCFTypeRef<SecKeyRef> key;
99   const CSSM_KEY* cssm_key;
100 };
101
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,
106               void** from_d,
107               int idx,
108               long argl,
109               void* argp) {
110   CHECK_EQ((void*)NULL, *from_d);
111   return 0;
112 }
113
114 // ExDataFree is called when one of the RSA or EC_KEY objects is freed.
115 void ExDataFree(void* parent,
116                 void* ptr,
117                 CRYPTO_EX_DATA* ex_data,
118                 int idx,
119                 long argl, void* argp) {
120   KeyExData* data = reinterpret_cast<KeyExData*>(ptr);
121   delete data;
122 }
123
124 // BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA
125 // by forwarding the requested operations to Apple's CSSM
126 // implementation.
127 class BoringSSLEngine {
128  public:
129   BoringSSLEngine()
130       : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
131                                         NULL /* argp */,
132                                         NULL /* new_func */,
133                                         ExDataDup,
134                                         ExDataFree)),
135         ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
136                                               NULL /* argp */,
137                                               NULL /* new_func */,
138                                               ExDataDup,
139                                               ExDataFree)),
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));
145   }
146
147   int rsa_ex_index() const { return rsa_index_; }
148   int ec_key_ex_index() const { return ec_key_index_; }
149
150   const ENGINE* engine() const { return engine_; }
151
152  private:
153   const int rsa_index_;
154   const int ec_key_index_;
155   ENGINE* const engine_;
156 };
157
158 base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine =
159     LAZY_INSTANCE_INITIALIZER;
160
161 // Helper function for making a signature.
162
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,
168                       size_t* out_len,
169                       uint8_t* out,
170                       size_t max_out,
171                       const uint8_t* in,
172                       size_t in_len) {
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);
178     return 0;
179   }
180
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);
187     return 0;
188   }
189
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);
195     return 0;
196   }
197
198   if (ex_data->cssm_key->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
199     // Set RSA blinding.
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);
207       return 0;
208     }
209   }
210
211   CSSM_DATA hash_data;
212   hash_data.Length = in_len;
213   hash_data.Data = const_cast<uint8*>(in);
214
215   CSSM_DATA signature_data;
216   signature_data.Length = max_out;
217   signature_data.Data = out;
218
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);
222     return 0;
223   }
224
225   *out_len = signature_data.Length;
226   return 1;
227 }
228
229 // Custom RSA_METHOD that uses the platform APIs for signing.
230
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()));
234 }
235
236 size_t RsaMethodSize(const RSA *rsa) {
237   const KeyExData *ex_data = RsaGetExData(rsa);
238   return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8;
239 }
240
241 int RsaMethodEncrypt(RSA* rsa,
242                      size_t* out_len,
243                      uint8_t* out,
244                      size_t max_out,
245                      const uint8_t* in,
246                      size_t in_len,
247                      int padding) {
248   NOTIMPLEMENTED();
249   OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
250   return 0;
251 }
252
253 int RsaMethodSignRaw(RSA* rsa,
254                      size_t* out_len,
255                      uint8_t* out,
256                      size_t max_out,
257                      const uint8_t* in,
258                      size_t in_len,
259                      int padding) {
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);
264     return 0;
265   }
266
267   const KeyExData *ex_data = RsaGetExData(rsa);
268   if (!ex_data) {
269     OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
270     return 0;
271   }
272   DCHECK_EQ(CSSM_ALGID_RSA, ex_data->cssm_key->KeyHeader.AlgorithmId);
273
274   return MakeCSSMSignature(ex_data, out_len, out, max_out, in, in_len);
275 }
276
277 int RsaMethodDecrypt(RSA* rsa,
278                      size_t* out_len,
279                      uint8_t* out,
280                      size_t max_out,
281                      const uint8_t* in,
282                      size_t in_len,
283                      int padding) {
284   NOTIMPLEMENTED();
285   OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
286   return 0;
287 }
288
289 int RsaMethodVerifyRaw(RSA* rsa,
290                        size_t* out_len,
291                        uint8_t* out,
292                        size_t max_out,
293                        const uint8_t* in,
294                        size_t in_len,
295                        int padding) {
296   NOTIMPLEMENTED();
297   OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE);
298   return 0;
299 }
300
301 const RSA_METHOD mac_rsa_method = {
302     {
303      0 /* references */,
304      1 /* is_static */
305     } /* common */,
306     NULL /* app_data */,
307
308     NULL /* init */,
309     NULL /* finish */,
310     RsaMethodSize,
311     NULL /* sign */,
312     NULL /* verify */,
313     RsaMethodEncrypt,
314     RsaMethodSignRaw,
315     RsaMethodDecrypt,
316     RsaMethodVerifyRaw,
317     NULL /* private_transform */,
318     NULL /* mod_exp */,
319     NULL /* bn_mod_exp */,
320     RSA_FLAG_OPAQUE,
321     NULL /* keygen */,
322 };
323
324 crypto::ScopedEVP_PKEY CreateRSAWrapper(SecKeyRef key,
325                                         const CSSM_KEY* cssm_key) {
326   crypto::ScopedRSA rsa(
327       RSA_new_method(global_boringssl_engine.Get().engine()));
328   if (!rsa)
329     return crypto::ScopedEVP_PKEY();
330
331   RSA_set_ex_data(
332       rsa.get(), global_boringssl_engine.Get().rsa_ex_index(),
333       new KeyExData(key, cssm_key));
334
335   crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
336   if (!pkey)
337     return crypto::ScopedEVP_PKEY();
338
339   if (!EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
340     return crypto::ScopedEVP_PKEY();
341
342   return pkey.Pass();
343 }
344
345 // Custom ECDSA_METHOD that uses the platform APIs.
346 // Note that for now, only signing through ECDSA_sign() is really supported.
347 // all other method pointers are either stubs returning errors, or no-ops.
348
349 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) {
350   return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data(
351       ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
352 }
353
354 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) {
355   const KeyExData* ex_data = EcKeyGetExData(ec_key);
356   // LogicalKeySizeInBits is the size of an EC public key. But an
357   // ECDSA signature length depends on the size of the base point's
358   // order. For P-256, P-384, and P-521, these two sizes are the same.
359   return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8;
360 }
361
362 int EcdsaMethodSign(const uint8_t* digest,
363                     size_t digest_len,
364                     uint8_t* sig,
365                     unsigned int* sig_len,
366                     EC_KEY* ec_key) {
367   const KeyExData *ex_data = EcKeyGetExData(ec_key);
368   if (!ex_data) {
369     OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
370     return 0;
371   }
372   DCHECK_EQ(CSSM_ALGID_ECDSA, ex_data->cssm_key->KeyHeader.AlgorithmId);
373
374   // TODO(davidben): Fix BoringSSL to make sig_len a size_t*.
375   size_t out_len;
376   int ret = MakeCSSMSignature(
377       ex_data, &out_len, sig, ECDSA_size(ec_key), digest, digest_len);
378   if (!ret)
379     return 0;
380   *sig_len = out_len;
381   return 1;
382 }
383
384 int EcdsaMethodVerify(const uint8_t* digest,
385                       size_t digest_len,
386                       const uint8_t* sig,
387                       size_t sig_len,
388                       EC_KEY* eckey) {
389   NOTIMPLEMENTED();
390   OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
391   return 0;
392 }
393
394 const ECDSA_METHOD mac_ecdsa_method = {
395     {
396      0 /* references */,
397      1 /* is_static */
398     } /* common */,
399     NULL /* app_data */,
400
401     NULL /* init */,
402     NULL /* finish */,
403     EcdsaMethodGroupOrderSize,
404     EcdsaMethodSign,
405     EcdsaMethodVerify,
406     ECDSA_FLAG_OPAQUE,
407 };
408
409 crypto::ScopedEVP_PKEY CreateECDSAWrapper(SecKeyRef key,
410                                           const CSSM_KEY* cssm_key) {
411   crypto::ScopedEC_KEY ec_key(
412       EC_KEY_new_method(global_boringssl_engine.Get().engine()));
413   if (!ec_key)
414     return crypto::ScopedEVP_PKEY();
415
416   EC_KEY_set_ex_data(
417       ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(),
418       new KeyExData(key, cssm_key));
419
420   crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
421   if (!pkey)
422     return crypto::ScopedEVP_PKEY();
423
424   if (!EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()))
425     return crypto::ScopedEVP_PKEY();
426
427   return pkey.Pass();
428 }
429
430 crypto::ScopedEVP_PKEY CreatePkeyWrapper(SecKeyRef key) {
431   const CSSM_KEY* cssm_key;
432   OSStatus status = SecKeyGetCSSMKey(key, &cssm_key);
433   if (status != noErr)
434     return crypto::ScopedEVP_PKEY();
435
436   switch (cssm_key->KeyHeader.AlgorithmId) {
437     case CSSM_ALGID_RSA:
438       return CreateRSAWrapper(key, cssm_key);
439     case CSSM_ALGID_ECDSA:
440       return CreateECDSAWrapper(key, cssm_key);
441     default:
442       // TODO(davidben): Filter out anything other than ECDSA and RSA
443       // elsewhere. We don't support other key types.
444       NOTREACHED();
445       LOG(ERROR) << "Unknown key type";
446       return crypto::ScopedEVP_PKEY();
447   }
448 }
449
450 }  // namespace
451
452 crypto::ScopedEVP_PKEY FetchClientCertPrivateKey(
453     const X509Certificate* certificate) {
454   // Look up the private key.
455   base::ScopedCFTypeRef<SecKeyRef> private_key(
456       FetchSecKeyRefForCertificate(certificate));
457   if (!private_key)
458     return crypto::ScopedEVP_PKEY();
459
460   // Create an EVP_PKEY wrapper.
461   return CreatePkeyWrapper(private_key.get());
462 }
463
464 }  // namespace net