Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/keygen_handler.h" | 5 #include "net/base/keygen_handler.h" |
| 6 | 6 |
| 7 #include <Security/SecAsn1Coder.h> | |
| 8 #include <Security/SecAsn1Templates.h> | |
| 9 #include <Security/Security.h> | |
| 10 | |
| 11 #include "base/base64.h" | |
| 7 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/scoped_cftyperef.h" | |
| 14 | |
| 15 // These are in Security.framework but not declared in a public header. | |
| 16 extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[]; | |
| 17 extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[]; | |
| 8 | 18 |
| 9 namespace net { | 19 namespace net { |
| 10 | 20 |
| 11 KeygenHandler::KeygenHandler(int key_size_index, | 21 // Declarations of Netscape keygen cert structures for ASN.1 encoding: |
| 12 const std::string& challenge) | 22 |
| 13 : key_size_index_(key_size_index), | 23 struct PublicKeyAndChallenge { |
| 14 challenge_(challenge) { | 24 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki; |
| 15 NOTIMPLEMENTED(); | 25 CSSM_DATA challenge_string; |
| 16 } | 26 }; |
| 27 | |
| 28 static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = { | |
| 29 { | |
| 30 SEC_ASN1_SEQUENCE, | |
| 31 0, | |
| 32 NULL, | |
| 33 sizeof(PublicKeyAndChallenge) | |
| 34 }, | |
| 35 { | |
| 36 SEC_ASN1_INLINE, | |
| 37 offsetof(PublicKeyAndChallenge, spki), | |
| 38 kSecAsn1SubjectPublicKeyInfoTemplate | |
| 39 }, | |
| 40 { | |
| 41 SEC_ASN1_INLINE, | |
| 42 offsetof(PublicKeyAndChallenge, challenge_string), | |
| 43 kSecAsn1IA5StringTemplate | |
| 44 }, | |
| 45 { | |
| 46 0 | |
| 47 } | |
| 48 }; | |
| 49 | |
| 50 struct SignedPublicKeyAndChallenge { | |
| 51 PublicKeyAndChallenge pkac; | |
| 52 CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm; | |
| 53 CSSM_DATA signature; | |
| 54 }; | |
| 55 | |
| 56 static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = { | |
| 57 { | |
| 58 SEC_ASN1_SEQUENCE, | |
| 59 0, | |
| 60 NULL, | |
| 61 sizeof(SignedPublicKeyAndChallenge) | |
| 62 }, | |
| 63 { | |
| 64 SEC_ASN1_INLINE, | |
| 65 offsetof(SignedPublicKeyAndChallenge, pkac), | |
| 66 kPublicKeyAndChallengeTemplate | |
| 67 }, | |
| 68 { | |
| 69 SEC_ASN1_INLINE, | |
| 70 offsetof(SignedPublicKeyAndChallenge, signature_algorithm), | |
| 71 kSecAsn1AlgorithmIDTemplate | |
| 72 }, | |
| 73 { | |
| 74 SEC_ASN1_BIT_STRING, | |
| 75 offsetof(SignedPublicKeyAndChallenge, signature) | |
| 76 }, | |
| 77 { | |
| 78 0 | |
| 79 } | |
| 80 }; | |
| 81 | |
| 82 | |
| 83 static OSStatus CreateRSAKeyPair(int size_in_bits, | |
| 84 SecKeyRef* out_pub_key, | |
| 85 SecKeyRef* out_priv_key); | |
| 86 static OSStatus SignData(CSSM_DATA data, | |
| 87 SecKeyRef private_key, | |
| 88 CSSM_DATA* signature); | |
| 89 | |
| 17 | 90 |
| 18 std::string KeygenHandler::GenKeyAndSignChallenge() { | 91 std::string KeygenHandler::GenKeyAndSignChallenge() { |
| 19 NOTIMPLEMENTED(); | 92 std::string result; |
| 20 return std::string(); | 93 OSStatus err; |
| 94 SecKeyRef public_key = NULL; | |
| 95 SecKeyRef private_key = NULL; | |
| 96 SecAsn1CoderRef coder = NULL; | |
| 97 CSSM_DATA signature = {0, NULL}; | |
| 98 | |
| 99 { | |
| 100 // Create the key-pair. | |
| 101 err = CreateRSAKeyPair(key_size_in_bits_, &public_key, &private_key); | |
| 102 if (err) | |
| 103 goto failure; | |
| 104 | |
| 105 // Get the public key data (DER sequence of modulus, exponent). | |
| 106 CFDataRef key_data = NULL; | |
| 107 err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL, | |
| 108 &key_data); | |
| 109 if (err) | |
| 110 goto failure; | |
| 111 scoped_cftyperef<CFDataRef> scoped_key_data(key_data); | |
| 112 | |
| 113 // Create an ASN.1 encoder. | |
| 114 err = SecAsn1CoderCreate(&coder); | |
| 115 if (err) | |
| 116 goto failure; | |
| 117 | |
| 118 // Fill in and DER-encode the PublicKeyAndChallenge: | |
| 119 SignedPublicKeyAndChallenge spkac; | |
| 120 memset(&spkac, 0, sizeof(spkac)); | |
| 121 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; | |
| 122 spkac.pkac.spki.subjectPublicKey.Length = | |
| 123 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count | |
| 124 spkac.pkac.spki.subjectPublicKey.Data = | |
| 125 const_cast<uint8_t*>(CFDataGetBytePtr(key_data)); | |
| 126 spkac.pkac.challenge_string.Length = challenge_.length(); | |
| 127 spkac.pkac.challenge_string.Data = | |
| 128 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data())); | |
| 129 | |
| 130 CSSM_DATA encoded; | |
| 131 err = SecAsn1EncodeItem(coder, &spkac.pkac, | |
| 132 kPublicKeyAndChallengeTemplate, &encoded); | |
| 133 if (err) | |
| 134 goto failure; | |
| 135 | |
| 136 // Compute a signature of the result: | |
| 137 err = SignData(encoded, private_key, &signature); | |
| 138 if (err) | |
| 139 goto failure; | |
| 140 spkac.signature.Data = signature.Data; | |
| 141 spkac.signature.Length = signature.Length * 8; // a _bit_ count | |
| 142 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; | |
|
wtc
2010/03/01 23:05:40
Can we use SHA1WithRSA instead of MD5WithRSA? (Th
| |
| 143 | |
| 144 // DER-encode the entire SignedPublicKeyAndChallenge: | |
| 145 err = SecAsn1EncodeItem(coder, &spkac, | |
| 146 kSignedPublicKeyAndChallengeTemplate, &encoded); | |
| 147 if (err) | |
| 148 goto failure; | |
| 149 | |
| 150 // Base64 encode the result. | |
| 151 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length); | |
| 152 base::Base64Encode(input, &result); | |
| 153 } | |
| 154 | |
| 155 failure: | |
| 156 if (err) { | |
| 157 LOG(ERROR) << "SSL Keygen failed! OSStatus = " << err; | |
| 158 } else { | |
| 159 LOG(INFO) << "SSL Keygen succeeded! Output is: " << result; | |
| 160 } | |
| 161 | |
| 162 // Remove keys from keychain if asked to during unit testing: | |
| 163 if (!stores_key_) { | |
| 164 if (public_key) | |
| 165 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key)); | |
| 166 if (private_key) | |
| 167 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key)); | |
| 168 } | |
| 169 | |
| 170 // Clean up: | |
| 171 free(signature.Data); | |
| 172 if (coder) | |
| 173 SecAsn1CoderRelease(coder); | |
| 174 if (public_key) | |
| 175 CFRelease(public_key); | |
| 176 if (private_key) | |
| 177 CFRelease(private_key); | |
| 178 return result; | |
| 179 } | |
| 180 | |
| 181 | |
| 182 static OSStatus CreateRSAKeyPair(int size_in_bits, | |
| 183 SecKeyRef* out_pub_key, | |
| 184 SecKeyRef* out_priv_key) { | |
| 185 OSStatus err; | |
| 186 SecKeychainRef keychain; | |
| 187 err = SecKeychainCopyDefault(&keychain); | |
| 188 if (err) | |
| 189 return err; | |
| 190 scoped_cftyperef<SecKeychainRef> scoped_keychain(keychain); | |
| 191 return SecKeyCreatePair( | |
| 192 keychain, | |
| 193 CSSM_ALGID_RSA, | |
| 194 size_in_bits, | |
| 195 0LL, | |
| 196 // public key usage and attributes: | |
| 197 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, | |
| 198 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT, | |
| 199 // private key usage and attributes: | |
| 200 CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP, // private key | |
| 201 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | | |
| 202 CSSM_KEYATTR_SENSITIVE, | |
| 203 NULL, | |
| 204 out_pub_key, out_priv_key); | |
| 205 } | |
| 206 | |
| 207 static OSStatus CreateSignatureContext(SecKeyRef key, | |
| 208 CSSM_ALGORITHMS algorithm, | |
| 209 CSSM_CC_HANDLE* out_cc_handle) { | |
| 210 OSStatus err; | |
| 211 const CSSM_ACCESS_CREDENTIALS* credentials = NULL; | |
| 212 err = SecKeyGetCredentials(key, | |
| 213 CSSM_ACL_AUTHORIZATION_SIGN, | |
| 214 kSecCredentialTypeDefault, | |
| 215 &credentials); | |
| 216 if (err) | |
| 217 return err; | |
| 218 | |
| 219 CSSM_CSP_HANDLE csp_handle = 0; | |
| 220 err = SecKeyGetCSPHandle(key, &csp_handle); | |
| 221 if (err) | |
| 222 return err; | |
| 223 | |
| 224 const CSSM_KEY* cssm_key = NULL; | |
| 225 err = SecKeyGetCSSMKey(key, &cssm_key); | |
| 226 if (err) | |
| 227 return err; | |
| 228 | |
| 229 return CSSM_CSP_CreateSignatureContext(csp_handle, | |
| 230 algorithm, | |
| 231 credentials, | |
| 232 cssm_key, | |
| 233 out_cc_handle); | |
| 234 } | |
| 235 | |
| 236 static OSStatus SignData(CSSM_DATA data, | |
| 237 SecKeyRef private_key, | |
| 238 CSSM_DATA* signature) { | |
| 239 CSSM_CC_HANDLE cc_handle; | |
| 240 OSStatus err = CreateSignatureContext(private_key, | |
| 241 CSSM_ALGID_MD5WithRSA, | |
| 242 &cc_handle); | |
| 243 if (err) | |
| 244 return err; | |
| 245 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature); | |
| 246 CSSM_DeleteContext(cc_handle); | |
| 247 return err; | |
| 21 } | 248 } |
| 22 | 249 |
| 23 } // namespace net | 250 } // namespace net |
| OLD | NEW |