| Index: net/ssl/openssl_platform_key_mac.cc
|
| diff --git a/net/ssl/openssl_platform_key_mac.cc b/net/ssl/openssl_platform_key_mac.cc
|
| deleted file mode 100644
|
| index 34857afda35f85c578e2ec31dbe9b6137941b7a5..0000000000000000000000000000000000000000
|
| --- a/net/ssl/openssl_platform_key_mac.cc
|
| +++ /dev/null
|
| @@ -1,466 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/ssl/openssl_platform_key.h"
|
| -
|
| -#include <openssl/ec_key.h>
|
| -#include <openssl/err.h>
|
| -#include <openssl/engine.h>
|
| -#include <openssl/evp.h>
|
| -#include <openssl/rsa.h>
|
| -
|
| -#include <Security/cssm.h>
|
| -#include <Security/SecBase.h>
|
| -#include <Security/SecCertificate.h>
|
| -#include <Security/SecIdentity.h>
|
| -#include <Security/SecKey.h>
|
| -
|
| -#include "base/lazy_instance.h"
|
| -#include "base/location.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac/mac_logging.h"
|
| -#include "base/mac/scoped_cftyperef.h"
|
| -#include "base/memory/scoped_policy.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/synchronization/lock.h"
|
| -#include "crypto/mac_security_services_lock.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/cert/x509_certificate.h"
|
| -#include "net/ssl/openssl_ssl_util.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -class ScopedCSSM_CC_HANDLE {
|
| - public:
|
| - ScopedCSSM_CC_HANDLE() : handle_(0) {
|
| - }
|
| -
|
| - ~ScopedCSSM_CC_HANDLE() {
|
| - reset();
|
| - }
|
| -
|
| - CSSM_CC_HANDLE get() const {
|
| - return handle_;
|
| - }
|
| -
|
| - void reset() {
|
| - if (handle_)
|
| - CSSM_DeleteContext(handle_);
|
| - handle_ = 0;
|
| - }
|
| -
|
| - CSSM_CC_HANDLE* InitializeInto() {
|
| - reset();
|
| - return &handle_;
|
| - }
|
| - private:
|
| - CSSM_CC_HANDLE handle_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE);
|
| -};
|
| -
|
| -// Looks up the private key for |certificate| in KeyChain and returns
|
| -// a SecKeyRef or NULL on failure. The caller takes ownership of the
|
| -// result.
|
| -SecKeyRef FetchSecKeyRefForCertificate(const X509Certificate* certificate) {
|
| - OSStatus status;
|
| - base::ScopedCFTypeRef<SecIdentityRef> identity;
|
| - {
|
| - base::AutoLock lock(crypto::GetMacSecurityServicesLock());
|
| - status = SecIdentityCreateWithCertificate(
|
| - NULL, certificate->os_cert_handle(), identity.InitializeInto());
|
| - }
|
| - if (status != noErr) {
|
| - OSSTATUS_LOG(WARNING, status);
|
| - return NULL;
|
| - }
|
| -
|
| - base::ScopedCFTypeRef<SecKeyRef> private_key;
|
| - status = SecIdentityCopyPrivateKey(identity, private_key.InitializeInto());
|
| - if (status != noErr) {
|
| - OSSTATUS_LOG(WARNING, status);
|
| - return NULL;
|
| - }
|
| -
|
| - return private_key.release();
|
| -}
|
| -
|
| -extern const RSA_METHOD mac_rsa_method;
|
| -extern const ECDSA_METHOD mac_ecdsa_method;
|
| -
|
| -// KeyExData contains the data that is contained in the EX_DATA of the
|
| -// RSA and ECDSA objects that are created to wrap Mac system keys.
|
| -struct KeyExData {
|
| - KeyExData(SecKeyRef key, const CSSM_KEY* cssm_key)
|
| - : key(key, base::scoped_policy::RETAIN), cssm_key(cssm_key) {}
|
| -
|
| - base::ScopedCFTypeRef<SecKeyRef> key;
|
| - const CSSM_KEY* cssm_key;
|
| -};
|
| -
|
| -// ExDataDup is called when one of the RSA or EC_KEY objects is
|
| -// duplicated. This is not supported and should never happen.
|
| -int ExDataDup(CRYPTO_EX_DATA* to,
|
| - const CRYPTO_EX_DATA* from,
|
| - void** from_d,
|
| - int idx,
|
| - long argl,
|
| - void* argp) {
|
| - CHECK_EQ((void*)NULL, *from_d);
|
| - return 0;
|
| -}
|
| -
|
| -// ExDataFree is called when one of the RSA or EC_KEY objects is freed.
|
| -void ExDataFree(void* parent,
|
| - void* ptr,
|
| - CRYPTO_EX_DATA* ex_data,
|
| - int idx,
|
| - long argl, void* argp) {
|
| - KeyExData* data = reinterpret_cast<KeyExData*>(ptr);
|
| - delete data;
|
| -}
|
| -
|
| -// BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA
|
| -// by forwarding the requested operations to Apple's CSSM
|
| -// implementation.
|
| -class BoringSSLEngine {
|
| - public:
|
| - BoringSSLEngine()
|
| - : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
|
| - NULL /* argp */,
|
| - NULL /* new_func */,
|
| - ExDataDup,
|
| - ExDataFree)),
|
| - ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
|
| - NULL /* argp */,
|
| - NULL /* new_func */,
|
| - ExDataDup,
|
| - ExDataFree)),
|
| - engine_(ENGINE_new()) {
|
| - ENGINE_set_RSA_method(
|
| - engine_, &mac_rsa_method, sizeof(mac_rsa_method));
|
| - ENGINE_set_ECDSA_method(
|
| - engine_, &mac_ecdsa_method, sizeof(mac_ecdsa_method));
|
| - }
|
| -
|
| - int rsa_ex_index() const { return rsa_index_; }
|
| - int ec_key_ex_index() const { return ec_key_index_; }
|
| -
|
| - const ENGINE* engine() const { return engine_; }
|
| -
|
| - private:
|
| - const int rsa_index_;
|
| - const int ec_key_index_;
|
| - ENGINE* const engine_;
|
| -};
|
| -
|
| -base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -
|
| -// Helper function for making a signature.
|
| -
|
| -// MakeCSSMSignature uses the key information in |ex_data| to sign the
|
| -// |in_len| bytes pointed by |in|. It writes up to |max_out| bytes
|
| -// into the buffer pointed to by |out|, setting |*out_len| to the
|
| -// number of bytes written. It returns 1 on success and 0 on failure.
|
| -int MakeCSSMSignature(const KeyExData* ex_data,
|
| - size_t* out_len,
|
| - uint8_t* out,
|
| - size_t max_out,
|
| - const uint8_t* in,
|
| - size_t in_len) {
|
| - CSSM_CSP_HANDLE csp_handle;
|
| - OSStatus status = SecKeyGetCSPHandle(ex_data->key.get(), &csp_handle);
|
| - if (status != noErr) {
|
| - OSSTATUS_LOG(WARNING, status);
|
| - OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
|
| - return 0;
|
| - }
|
| -
|
| - const CSSM_ACCESS_CREDENTIALS* cssm_creds = NULL;
|
| - status = SecKeyGetCredentials(ex_data->key.get(), CSSM_ACL_AUTHORIZATION_SIGN,
|
| - kSecCredentialTypeDefault, &cssm_creds);
|
| - if (status != noErr) {
|
| - OSSTATUS_LOG(WARNING, status);
|
| - OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| - return 0;
|
| - }
|
| -
|
| - ScopedCSSM_CC_HANDLE cssm_signature;
|
| - if (CSSM_CSP_CreateSignatureContext(
|
| - csp_handle, ex_data->cssm_key->KeyHeader.AlgorithmId, cssm_creds,
|
| - ex_data->cssm_key, cssm_signature.InitializeInto()) != CSSM_OK) {
|
| - OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| - return 0;
|
| - }
|
| -
|
| - if (ex_data->cssm_key->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
|
| - // Set RSA blinding.
|
| - CSSM_CONTEXT_ATTRIBUTE blinding_attr;
|
| - blinding_attr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
|
| - blinding_attr.AttributeLength = sizeof(uint32);
|
| - blinding_attr.Attribute.Uint32 = 1;
|
| - if (CSSM_UpdateContextAttributes(
|
| - cssm_signature.get(), 1, &blinding_attr) != CSSM_OK) {
|
| - OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| - return 0;
|
| - }
|
| - }
|
| -
|
| - CSSM_DATA hash_data;
|
| - hash_data.Length = in_len;
|
| - hash_data.Data = const_cast<uint8*>(in);
|
| -
|
| - CSSM_DATA signature_data;
|
| - signature_data.Length = max_out;
|
| - signature_data.Data = out;
|
| -
|
| - if (CSSM_SignData(cssm_signature.get(), &hash_data, 1,
|
| - CSSM_ALGID_NONE, &signature_data) != CSSM_OK) {
|
| - OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
|
| - return 0;
|
| - }
|
| -
|
| - *out_len = signature_data.Length;
|
| - return 1;
|
| -}
|
| -
|
| -// Custom RSA_METHOD that uses the platform APIs for signing.
|
| -
|
| -const KeyExData* RsaGetExData(const RSA* rsa) {
|
| - return reinterpret_cast<const KeyExData*>(
|
| - RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index()));
|
| -}
|
| -
|
| -size_t RsaMethodSize(const RSA *rsa) {
|
| - const KeyExData *ex_data = RsaGetExData(rsa);
|
| - return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8;
|
| -}
|
| -
|
| -int RsaMethodEncrypt(RSA* rsa,
|
| - size_t* out_len,
|
| - uint8_t* out,
|
| - size_t max_out,
|
| - const uint8_t* in,
|
| - size_t in_len,
|
| - int padding) {
|
| - NOTIMPLEMENTED();
|
| - OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
|
| - return 0;
|
| -}
|
| -
|
| -int RsaMethodSignRaw(RSA* rsa,
|
| - size_t* out_len,
|
| - uint8_t* out,
|
| - size_t max_out,
|
| - const uint8_t* in,
|
| - size_t in_len,
|
| - int padding) {
|
| - // Only support PKCS#1 padding.
|
| - DCHECK_EQ(RSA_PKCS1_PADDING, padding);
|
| - if (padding != RSA_PKCS1_PADDING) {
|
| - OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE);
|
| - return 0;
|
| - }
|
| -
|
| - const KeyExData *ex_data = RsaGetExData(rsa);
|
| - if (!ex_data) {
|
| - OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
|
| - return 0;
|
| - }
|
| - DCHECK_EQ(CSSM_ALGID_RSA, ex_data->cssm_key->KeyHeader.AlgorithmId);
|
| -
|
| - return MakeCSSMSignature(ex_data, out_len, out, max_out, in, in_len);
|
| -}
|
| -
|
| -int RsaMethodDecrypt(RSA* rsa,
|
| - size_t* out_len,
|
| - uint8_t* out,
|
| - size_t max_out,
|
| - const uint8_t* in,
|
| - size_t in_len,
|
| - int padding) {
|
| - NOTIMPLEMENTED();
|
| - OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
|
| - return 0;
|
| -}
|
| -
|
| -int RsaMethodVerifyRaw(RSA* rsa,
|
| - size_t* out_len,
|
| - uint8_t* out,
|
| - size_t max_out,
|
| - const uint8_t* in,
|
| - size_t in_len,
|
| - int padding) {
|
| - NOTIMPLEMENTED();
|
| - OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE);
|
| - return 0;
|
| -}
|
| -
|
| -const RSA_METHOD mac_rsa_method = {
|
| - {
|
| - 0 /* references */,
|
| - 1 /* is_static */
|
| - } /* common */,
|
| - NULL /* app_data */,
|
| -
|
| - NULL /* init */,
|
| - NULL /* finish */,
|
| - RsaMethodSize,
|
| - NULL /* sign */,
|
| - NULL /* verify */,
|
| - RsaMethodEncrypt,
|
| - RsaMethodSignRaw,
|
| - RsaMethodDecrypt,
|
| - RsaMethodVerifyRaw,
|
| - NULL /* private_transform */,
|
| - NULL /* mod_exp */,
|
| - NULL /* bn_mod_exp */,
|
| - RSA_FLAG_OPAQUE,
|
| - NULL /* keygen */,
|
| -};
|
| -
|
| -crypto::ScopedEVP_PKEY CreateRSAWrapper(SecKeyRef key,
|
| - const CSSM_KEY* cssm_key) {
|
| - crypto::ScopedRSA rsa(
|
| - RSA_new_method(global_boringssl_engine.Get().engine()));
|
| - if (!rsa)
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - RSA_set_ex_data(
|
| - rsa.get(), global_boringssl_engine.Get().rsa_ex_index(),
|
| - new KeyExData(key, cssm_key));
|
| -
|
| - crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
|
| - if (!pkey)
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - if (!EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - return pkey.Pass();
|
| -}
|
| -
|
| -// Custom ECDSA_METHOD that uses the platform APIs.
|
| -// Note that for now, only signing through ECDSA_sign() is really supported.
|
| -// all other method pointers are either stubs returning errors, or no-ops.
|
| -
|
| -const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) {
|
| - return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data(
|
| - ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
|
| -}
|
| -
|
| -size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) {
|
| - const KeyExData* ex_data = EcKeyGetExData(ec_key);
|
| - // LogicalKeySizeInBits is the size of an EC public key. But an
|
| - // ECDSA signature length depends on the size of the base point's
|
| - // order. For P-256, P-384, and P-521, these two sizes are the same.
|
| - return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8;
|
| -}
|
| -
|
| -int EcdsaMethodSign(const uint8_t* digest,
|
| - size_t digest_len,
|
| - uint8_t* sig,
|
| - unsigned int* sig_len,
|
| - EC_KEY* ec_key) {
|
| - const KeyExData *ex_data = EcKeyGetExData(ec_key);
|
| - if (!ex_data) {
|
| - OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
|
| - return 0;
|
| - }
|
| - DCHECK_EQ(CSSM_ALGID_ECDSA, ex_data->cssm_key->KeyHeader.AlgorithmId);
|
| -
|
| - // TODO(davidben): Fix BoringSSL to make sig_len a size_t*.
|
| - size_t out_len;
|
| - int ret = MakeCSSMSignature(
|
| - ex_data, &out_len, sig, ECDSA_size(ec_key), digest, digest_len);
|
| - if (!ret)
|
| - return 0;
|
| - *sig_len = out_len;
|
| - return 1;
|
| -}
|
| -
|
| -int EcdsaMethodVerify(const uint8_t* digest,
|
| - size_t digest_len,
|
| - const uint8_t* sig,
|
| - size_t sig_len,
|
| - EC_KEY* eckey) {
|
| - NOTIMPLEMENTED();
|
| - OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
|
| - return 0;
|
| -}
|
| -
|
| -const ECDSA_METHOD mac_ecdsa_method = {
|
| - {
|
| - 0 /* references */,
|
| - 1 /* is_static */
|
| - } /* common */,
|
| - NULL /* app_data */,
|
| -
|
| - NULL /* init */,
|
| - NULL /* finish */,
|
| - EcdsaMethodGroupOrderSize,
|
| - EcdsaMethodSign,
|
| - EcdsaMethodVerify,
|
| - ECDSA_FLAG_OPAQUE,
|
| -};
|
| -
|
| -crypto::ScopedEVP_PKEY CreateECDSAWrapper(SecKeyRef key,
|
| - const CSSM_KEY* cssm_key) {
|
| - crypto::ScopedEC_KEY ec_key(
|
| - EC_KEY_new_method(global_boringssl_engine.Get().engine()));
|
| - if (!ec_key)
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - EC_KEY_set_ex_data(
|
| - ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(),
|
| - new KeyExData(key, cssm_key));
|
| -
|
| - crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
|
| - if (!pkey)
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - if (!EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()))
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - return pkey.Pass();
|
| -}
|
| -
|
| -crypto::ScopedEVP_PKEY CreatePkeyWrapper(SecKeyRef key) {
|
| - const CSSM_KEY* cssm_key;
|
| - OSStatus status = SecKeyGetCSSMKey(key, &cssm_key);
|
| - if (status != noErr)
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - switch (cssm_key->KeyHeader.AlgorithmId) {
|
| - case CSSM_ALGID_RSA:
|
| - return CreateRSAWrapper(key, cssm_key);
|
| - case CSSM_ALGID_ECDSA:
|
| - return CreateECDSAWrapper(key, cssm_key);
|
| - default:
|
| - // TODO(davidben): Filter out anything other than ECDSA and RSA
|
| - // elsewhere. We don't support other key types.
|
| - NOTREACHED();
|
| - LOG(ERROR) << "Unknown key type";
|
| - return crypto::ScopedEVP_PKEY();
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -crypto::ScopedEVP_PKEY FetchClientCertPrivateKey(
|
| - const X509Certificate* certificate) {
|
| - // Look up the private key.
|
| - base::ScopedCFTypeRef<SecKeyRef> private_key(
|
| - FetchSecKeyRefForCertificate(certificate));
|
| - if (!private_key)
|
| - return crypto::ScopedEVP_PKEY();
|
| -
|
| - // Create an EVP_PKEY wrapper.
|
| - return CreatePkeyWrapper(private_key.get());
|
| -}
|
| -
|
| -} // namespace net
|
|
|