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