15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/keygen_handler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Security/SecAsn1Coder.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Security/SecAsn1Templates.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Security/Security.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_logging.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h"
155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/cssm_init.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/mac_security_services_lock.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These are in Security.framework but not declared in a public header.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[];
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[];
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Declarations of Netscape keygen cert structures for ASN.1 encoding:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PublicKeyAndChallenge {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA challenge_string;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a copy of the built-in kSecAsn1IA5StringTemplate, but without the
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'streamable' flag, which was causing bogus data to be written.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SecAsn1Template kIA5StringTemplate[] = {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { SEC_ASN1_IA5_STRING, 0, NULL, sizeof(CSSM_DATA) }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_SEQUENCE,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sizeof(PublicKeyAndChallenge)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_INLINE,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offsetof(PublicKeyAndChallenge, spki),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAsn1SubjectPublicKeyInfoTemplate
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_INLINE,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offsetof(PublicKeyAndChallenge, challenge_string),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kIA5StringTemplate
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct SignedPublicKeyAndChallenge {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PublicKeyAndChallenge pkac;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA signature;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_SEQUENCE,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NULL,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sizeof(SignedPublicKeyAndChallenge)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_INLINE,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offsetof(SignedPublicKeyAndChallenge, pkac),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kPublicKeyAndChallengeTemplate
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_INLINE,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offsetof(SignedPublicKeyAndChallenge, signature_algorithm),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAsn1AlgorithmIDTemplate
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SEC_ASN1_BIT_STRING,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offsetof(SignedPublicKeyAndChallenge, signature)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static OSStatus CreateRSAKeyPair(int size_in_bits,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SecAccessRef initial_access,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SecKeyRef* out_pub_key,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SecKeyRef* out_priv_key);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static OSStatus SignData(CSSM_DATA data,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         SecKeyRef private_key,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         CSSM_DATA* signature);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string KeygenHandler::GenKeyAndSignChallenge() {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string result;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus err;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecAccessRef initial_access = NULL;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeyRef public_key = NULL;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeyRef private_key = NULL;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecAsn1CoderRef coder = NULL;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DATA signature = {0, NULL};
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_.has_host()) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(davidben): Use something like "Key generated for
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // example.com", but localize it.
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::ScopedCFTypeRef<CFStringRef> label(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::SysUTF8ToCFStringRef(url_.host()));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Create an initial access object to set the SecAccessRef. This
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // sets a label on the Keychain dialogs. Pass NULL as the second
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // argument to use the default trusted list; only allow the
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // current application to access without user confirmation.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      err = SecAccessCreate(label, NULL, &initial_access);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we fail, just continue without a label.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (err)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        crypto::LogCSSMError("SecAccessCreate", err);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create the key-pair.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = CreateRSAKeyPair(key_size_in_bits_, initial_access,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &public_key, &private_key);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the public key data (DER sequence of modulus, exponent).
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFDataRef key_data = NULL;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &key_data);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::LogCSSMError("SecKeychainItemExpor", err);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create an ASN.1 encoder.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecAsn1CoderCreate(&coder);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::LogCSSMError("SecAsn1CoderCreate", err);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Fill in and DER-encode the PublicKeyAndChallenge:
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SignedPublicKeyAndChallenge spkac;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&spkac, 0, sizeof(spkac));
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.pkac.spki.subjectPublicKey.Length =
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CFDataGetLength(key_data) * 8;  // interpreted as a _bit_ count
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.pkac.spki.subjectPublicKey.Data =
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<uint8_t*>(CFDataGetBytePtr(key_data));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.pkac.challenge_string.Length = challenge_.length();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.pkac.challenge_string.Data =
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data()));
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CSSM_DATA encoded;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecAsn1EncodeItem(coder, &spkac.pkac,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kPublicKeyAndChallengeTemplate, &encoded);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::LogCSSMError("SecAsn1EncodeItem", err);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compute a signature of the result:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SignData(encoded, private_key, &signature);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.signature.Data = signature.Data;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.signature.Length = signature.Length * 8;  // a _bit_ count
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(snej): MD5 is weak. Can we use SHA1 instead?
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460>
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DER-encode the entire SignedPublicKeyAndChallenge:
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecAsn1EncodeItem(coder, &spkac,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kSignedPublicKeyAndChallengeTemplate, &encoded);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (err) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crypto::LogCSSMError("SecAsn1EncodeItem", err);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Base64 encode the result.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Base64Encode(input, &result);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) failure:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSSTATUS_LOG(ERROR, err) << "SSL Keygen failed!";
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "SSL Keygen succeeded! Output is: " << result;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove keys from keychain if asked to during unit testing:
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stores_key_) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (public_key)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (private_key)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clean up:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free(signature.Data);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (coder)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecAsn1CoderRelease(coder);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initial_access)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRelease(initial_access);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (public_key)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRelease(public_key);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (private_key)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRelease(private_key);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create an RSA key pair with size |size_in_bits|. |initial_access|
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is passed as the initial access control list in Keychain. The
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// public and private keys are placed in |out_pub_key| and
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |out_priv_key|, respectively.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static OSStatus CreateRSAKeyPair(int size_in_bits,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SecAccessRef initial_access,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SecKeyRef* out_pub_key,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SecKeyRef* out_priv_key) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus err;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainRef keychain;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  err = SecKeychainCopyDefault(&keychain);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("SecKeychainCopyDefault", err);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return err;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(crypto::GetMacSecurityServicesLock());
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecKeyCreatePair(
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        keychain,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CSSM_ALGID_RSA,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_in_bits,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0LL,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // public key usage and attributes:
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // private key usage and attributes:
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT |
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CSSM_KEYATTR_SENSITIVE,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        initial_access,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        out_pub_key, out_priv_key);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("SecKeyCreatePair", err);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return err;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static OSStatus CreateSignatureContext(SecKeyRef key,
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       CSSM_ALGORITHMS algorithm,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       CSSM_CC_HANDLE* out_cc_handle) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus err;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CSSM_ACCESS_CREDENTIALS* credentials = NULL;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(crypto::GetMacSecurityServicesLock());
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecKeyGetCredentials(key,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               CSSM_ACL_AUTHORIZATION_SIGN,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               kSecCredentialTypeDefault,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &credentials);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("SecKeyGetCredentials", err);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return err;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_CSP_HANDLE csp_handle = 0;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(crypto::GetMacSecurityServicesLock());
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecKeyGetCSPHandle(key, &csp_handle);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("SecKeyGetCSPHandle", err);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return err;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CSSM_KEY* cssm_key = NULL;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock locked(crypto::GetMacSecurityServicesLock());
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    err = SecKeyGetCSSMKey(key, &cssm_key);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("SecKeyGetCSSMKey", err);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return err;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  err = CSSM_CSP_CreateSignatureContext(csp_handle,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        algorithm,
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        credentials,
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        cssm_key,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        out_cc_handle);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return err;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static OSStatus SignData(CSSM_DATA data,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         SecKeyRef private_key,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         CSSM_DATA* signature) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_CC_HANDLE cc_handle;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus err = CreateSignatureContext(private_key,
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        CSSM_ALGID_MD5WithRSA,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        &cc_handle);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("CreateSignatureContext", err);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return err;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (err)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::LogCSSMError("CSSM_SignData", err);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CSSM_DeleteContext(cc_handle);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return err;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
326