| Index: net/base/keygen_handler_mac.cc
|
| diff --git a/net/base/keygen_handler_mac.cc b/net/base/keygen_handler_mac.cc
|
| deleted file mode 100644
|
| index 13814fea820b4f5b3934b784b08e8a60fdcf95f9..0000000000000000000000000000000000000000
|
| --- a/net/base/keygen_handler_mac.cc
|
| +++ /dev/null
|
| @@ -1,339 +0,0 @@
|
| -// Copyright (c) 2012 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/base/keygen_handler.h"
|
| -
|
| -#include <Security/SecAsn1Coder.h>
|
| -#include <Security/SecAsn1Templates.h>
|
| -#include <Security/Security.h>
|
| -
|
| -#include "base/base64.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac/mac_logging.h"
|
| -#include "base/mac/scoped_cftyperef.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/sys_string_conversions.h"
|
| -#include "base/synchronization/lock.h"
|
| -#include "crypto/cssm_init.h"
|
| -#include "crypto/mac_security_services_lock.h"
|
| -
|
| -// CSSM functions are deprecated as of OSX 10.7, but have no replacement.
|
| -// https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1
|
| -#pragma clang diagnostic push
|
| -#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
| -
|
| -// These are in Security.framework but not declared in a public header.
|
| -extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[];
|
| -extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[];
|
| -
|
| -namespace net {
|
| -
|
| -// Declarations of Netscape keygen cert structures for ASN.1 encoding:
|
| -
|
| -struct PublicKeyAndChallenge {
|
| - CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki;
|
| - CSSM_DATA challenge_string;
|
| -};
|
| -
|
| -// This is a copy of the built-in kSecAsn1IA5StringTemplate, but without the
|
| -// 'streamable' flag, which was causing bogus data to be written.
|
| -const SecAsn1Template kIA5StringTemplate[] = {
|
| - { SEC_ASN1_IA5_STRING, 0, NULL, sizeof(CSSM_DATA) }
|
| -};
|
| -
|
| -static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = {
|
| - {
|
| - SEC_ASN1_SEQUENCE,
|
| - 0,
|
| - NULL,
|
| - sizeof(PublicKeyAndChallenge)
|
| - },
|
| - {
|
| - SEC_ASN1_INLINE,
|
| - offsetof(PublicKeyAndChallenge, spki),
|
| - kSecAsn1SubjectPublicKeyInfoTemplate
|
| - },
|
| - {
|
| - SEC_ASN1_INLINE,
|
| - offsetof(PublicKeyAndChallenge, challenge_string),
|
| - kIA5StringTemplate
|
| - },
|
| - {
|
| - 0
|
| - }
|
| -};
|
| -
|
| -struct SignedPublicKeyAndChallenge {
|
| - PublicKeyAndChallenge pkac;
|
| - CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm;
|
| - CSSM_DATA signature;
|
| -};
|
| -
|
| -static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = {
|
| - {
|
| - SEC_ASN1_SEQUENCE,
|
| - 0,
|
| - NULL,
|
| - sizeof(SignedPublicKeyAndChallenge)
|
| - },
|
| - {
|
| - SEC_ASN1_INLINE,
|
| - offsetof(SignedPublicKeyAndChallenge, pkac),
|
| - kPublicKeyAndChallengeTemplate
|
| - },
|
| - {
|
| - SEC_ASN1_INLINE,
|
| - offsetof(SignedPublicKeyAndChallenge, signature_algorithm),
|
| - kSecAsn1AlgorithmIDTemplate
|
| - },
|
| - {
|
| - SEC_ASN1_BIT_STRING,
|
| - offsetof(SignedPublicKeyAndChallenge, signature)
|
| - },
|
| - {
|
| - 0
|
| - }
|
| -};
|
| -
|
| -
|
| -static OSStatus CreateRSAKeyPair(int size_in_bits,
|
| - SecAccessRef initial_access,
|
| - SecKeyRef* out_pub_key,
|
| - SecKeyRef* out_priv_key);
|
| -static OSStatus SignData(CSSM_DATA data,
|
| - SecKeyRef private_key,
|
| - CSSM_DATA* signature);
|
| -
|
| -std::string KeygenHandler::GenKeyAndSignChallenge() {
|
| - std::string result;
|
| - OSStatus err;
|
| - SecAccessRef initial_access = NULL;
|
| - SecKeyRef public_key = NULL;
|
| - SecKeyRef private_key = NULL;
|
| - SecAsn1CoderRef coder = NULL;
|
| - CSSM_DATA signature = {0, NULL};
|
| -
|
| - {
|
| - if (url_.has_host()) {
|
| - // TODO(davidben): Use something like "Key generated for
|
| - // example.com", but localize it.
|
| - base::ScopedCFTypeRef<CFStringRef> label(
|
| - base::SysUTF8ToCFStringRef(url_.host()));
|
| - // Create an initial access object to set the SecAccessRef. This
|
| - // sets a label on the Keychain dialogs. Pass NULL as the second
|
| - // argument to use the default trusted list; only allow the
|
| - // current application to access without user confirmation.
|
| - err = SecAccessCreate(label, NULL, &initial_access);
|
| - // If we fail, just continue without a label.
|
| - if (err)
|
| - crypto::LogCSSMError("SecAccessCreate", err);
|
| - }
|
| -
|
| - // Create the key-pair.
|
| - err = CreateRSAKeyPair(key_size_in_bits_, initial_access,
|
| - &public_key, &private_key);
|
| - if (err)
|
| - goto failure;
|
| -
|
| - // Get the public key data (DER sequence of modulus, exponent).
|
| - CFDataRef key_data = NULL;
|
| - err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL,
|
| - &key_data);
|
| - if (err) {
|
| - crypto::LogCSSMError("SecKeychainItemExpor", err);
|
| - goto failure;
|
| - }
|
| - base::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data);
|
| -
|
| - // Create an ASN.1 encoder.
|
| - err = SecAsn1CoderCreate(&coder);
|
| - if (err) {
|
| - crypto::LogCSSMError("SecAsn1CoderCreate", err);
|
| - goto failure;
|
| - }
|
| -
|
| - // The DER encoding of a NULL.
|
| - static const uint8_t kNullDer[] = {0x05, 0x00};
|
| -
|
| - // Fill in and DER-encode the PublicKeyAndChallenge:
|
| - SignedPublicKeyAndChallenge spkac;
|
| - memset(&spkac, 0, sizeof(spkac));
|
| - spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA;
|
| - spkac.pkac.spki.algorithm.parameters.Data = const_cast<uint8_t*>(kNullDer);
|
| - spkac.pkac.spki.algorithm.parameters.Length = sizeof(kNullDer);
|
| - spkac.pkac.spki.subjectPublicKey.Length =
|
| - CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count
|
| - spkac.pkac.spki.subjectPublicKey.Data =
|
| - const_cast<uint8_t*>(CFDataGetBytePtr(key_data));
|
| - spkac.pkac.challenge_string.Length = challenge_.length();
|
| - spkac.pkac.challenge_string.Data =
|
| - reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data()));
|
| -
|
| - CSSM_DATA encoded;
|
| - err = SecAsn1EncodeItem(coder, &spkac.pkac,
|
| - kPublicKeyAndChallengeTemplate, &encoded);
|
| - if (err) {
|
| - crypto::LogCSSMError("SecAsn1EncodeItem", err);
|
| - goto failure;
|
| - }
|
| -
|
| - // Compute a signature of the result:
|
| - err = SignData(encoded, private_key, &signature);
|
| - if (err)
|
| - goto failure;
|
| - spkac.signature.Data = signature.Data;
|
| - spkac.signature.Length = signature.Length * 8; // a _bit_ count
|
| - spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA;
|
| - spkac.signature_algorithm.parameters.Data = const_cast<uint8_t*>(kNullDer);
|
| - spkac.signature_algorithm.parameters.Length = sizeof(kNullDer);
|
| - // TODO(snej): MD5 is weak. Can we use SHA1 instead?
|
| - // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460>
|
| -
|
| - // DER-encode the entire SignedPublicKeyAndChallenge:
|
| - err = SecAsn1EncodeItem(coder, &spkac,
|
| - kSignedPublicKeyAndChallengeTemplate, &encoded);
|
| - if (err) {
|
| - crypto::LogCSSMError("SecAsn1EncodeItem", err);
|
| - goto failure;
|
| - }
|
| -
|
| - // Base64 encode the result.
|
| - std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length);
|
| - base::Base64Encode(input, &result);
|
| - }
|
| -
|
| - failure:
|
| - if (err)
|
| - OSSTATUS_LOG(ERROR, err) << "SSL Keygen failed!";
|
| - else
|
| - VLOG(1) << "SSL Keygen succeeded! Output is: " << result;
|
| -
|
| - // Remove keys from keychain if asked to during unit testing:
|
| - if (!stores_key_) {
|
| - if (public_key)
|
| - SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key));
|
| - if (private_key)
|
| - SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key));
|
| - }
|
| -
|
| - // Clean up:
|
| - free(signature.Data);
|
| - if (coder)
|
| - SecAsn1CoderRelease(coder);
|
| - if (initial_access)
|
| - CFRelease(initial_access);
|
| - if (public_key)
|
| - CFRelease(public_key);
|
| - if (private_key)
|
| - CFRelease(private_key);
|
| - return result;
|
| -}
|
| -
|
| -
|
| -// Create an RSA key pair with size |size_in_bits|. |initial_access|
|
| -// is passed as the initial access control list in Keychain. The
|
| -// public and private keys are placed in |out_pub_key| and
|
| -// |out_priv_key|, respectively.
|
| -static OSStatus CreateRSAKeyPair(int size_in_bits,
|
| - SecAccessRef initial_access,
|
| - SecKeyRef* out_pub_key,
|
| - SecKeyRef* out_priv_key) {
|
| - OSStatus err;
|
| - SecKeychainRef keychain;
|
| - err = SecKeychainCopyDefault(&keychain);
|
| - if (err) {
|
| - crypto::LogCSSMError("SecKeychainCopyDefault", err);
|
| - return err;
|
| - }
|
| - base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
|
| - {
|
| - base::AutoLock locked(crypto::GetMacSecurityServicesLock());
|
| - err = SecKeyCreatePair(
|
| - keychain,
|
| - CSSM_ALGID_RSA,
|
| - size_in_bits,
|
| - 0LL,
|
| - // public key usage and attributes:
|
| - CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP,
|
| - CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
|
| - // private key usage and attributes:
|
| - CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP,
|
| - CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT |
|
| - CSSM_KEYATTR_SENSITIVE,
|
| - initial_access,
|
| - out_pub_key, out_priv_key);
|
| - }
|
| - if (err)
|
| - crypto::LogCSSMError("SecKeyCreatePair", err);
|
| - return err;
|
| -}
|
| -
|
| -static OSStatus CreateSignatureContext(SecKeyRef key,
|
| - CSSM_ALGORITHMS algorithm,
|
| - CSSM_CC_HANDLE* out_cc_handle) {
|
| - OSStatus err;
|
| - const CSSM_ACCESS_CREDENTIALS* credentials = NULL;
|
| - {
|
| - base::AutoLock locked(crypto::GetMacSecurityServicesLock());
|
| - err = SecKeyGetCredentials(key,
|
| - CSSM_ACL_AUTHORIZATION_SIGN,
|
| - kSecCredentialTypeDefault,
|
| - &credentials);
|
| - }
|
| - if (err) {
|
| - crypto::LogCSSMError("SecKeyGetCredentials", err);
|
| - return err;
|
| - }
|
| -
|
| - CSSM_CSP_HANDLE csp_handle = 0;
|
| - {
|
| - base::AutoLock locked(crypto::GetMacSecurityServicesLock());
|
| - err = SecKeyGetCSPHandle(key, &csp_handle);
|
| - }
|
| - if (err) {
|
| - crypto::LogCSSMError("SecKeyGetCSPHandle", err);
|
| - return err;
|
| - }
|
| -
|
| - const CSSM_KEY* cssm_key = NULL;
|
| - {
|
| - base::AutoLock locked(crypto::GetMacSecurityServicesLock());
|
| - err = SecKeyGetCSSMKey(key, &cssm_key);
|
| - }
|
| - if (err) {
|
| - crypto::LogCSSMError("SecKeyGetCSSMKey", err);
|
| - return err;
|
| - }
|
| -
|
| - err = CSSM_CSP_CreateSignatureContext(csp_handle,
|
| - algorithm,
|
| - credentials,
|
| - cssm_key,
|
| - out_cc_handle);
|
| - if (err)
|
| - crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err);
|
| - return err;
|
| -}
|
| -
|
| -static OSStatus SignData(CSSM_DATA data,
|
| - SecKeyRef private_key,
|
| - CSSM_DATA* signature) {
|
| - CSSM_CC_HANDLE cc_handle;
|
| - OSStatus err = CreateSignatureContext(private_key,
|
| - CSSM_ALGID_MD5WithRSA,
|
| - &cc_handle);
|
| - if (err) {
|
| - crypto::LogCSSMError("CreateSignatureContext", err);
|
| - return err;
|
| - }
|
| - err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature);
|
| - if (err)
|
| - crypto::LogCSSMError("CSSM_SignData", err);
|
| - CSSM_DeleteContext(cc_handle);
|
| - return err;
|
| -}
|
| -
|
| -} // namespace net
|
| -
|
| -#pragma clang diagnostic pop // "-Wdeprecated-declarations"
|
|
|