| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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> | 7 #include <Security/SecAsn1Coder.h> |
| 8 #include <Security/SecAsn1Templates.h> | 8 #include <Security/SecAsn1Templates.h> |
| 9 #include <Security/Security.h> | 9 #include <Security/Security.h> |
| 10 | 10 |
| 11 #include "base/base64.h" | 11 #include "base/base64.h" |
| 12 #include "base/crypto/cssm_init.h" | |
| 13 #include "base/crypto/mac_security_services_lock.h" | |
| 14 #include "base/logging.h" | 12 #include "base/logging.h" |
| 15 #include "base/mac/scoped_cftyperef.h" | 13 #include "base/mac/scoped_cftyperef.h" |
| 16 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 17 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
| 18 #include "base/sys_string_conversions.h" | 16 #include "base/sys_string_conversions.h" |
| 17 #include "crypto/cssm_init.h" |
| 18 #include "crypto/mac_security_services_lock.h" |
| 19 | 19 |
| 20 // These are in Security.framework but not declared in a public header. | 20 // These are in Security.framework but not declared in a public header. |
| 21 extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[]; | 21 extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[]; |
| 22 extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[]; | 22 extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[]; |
| 23 | 23 |
| 24 namespace net { | 24 namespace net { |
| 25 | 25 |
| 26 // Declarations of Netscape keygen cert structures for ASN.1 encoding: | 26 // Declarations of Netscape keygen cert structures for ASN.1 encoding: |
| 27 | 27 |
| 28 struct PublicKeyAndChallenge { | 28 struct PublicKeyAndChallenge { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 // example.com", but localize it. | 114 // example.com", but localize it. |
| 115 base::mac::ScopedCFTypeRef<CFStringRef> label( | 115 base::mac::ScopedCFTypeRef<CFStringRef> label( |
| 116 base::SysUTF8ToCFStringRef(url_.host())); | 116 base::SysUTF8ToCFStringRef(url_.host())); |
| 117 // Create an initial access object to set the SecAccessRef. This | 117 // Create an initial access object to set the SecAccessRef. This |
| 118 // sets a label on the Keychain dialogs. Pass NULL as the second | 118 // sets a label on the Keychain dialogs. Pass NULL as the second |
| 119 // argument to use the default trusted list; only allow the | 119 // argument to use the default trusted list; only allow the |
| 120 // current application to access without user confirmation. | 120 // current application to access without user confirmation. |
| 121 err = SecAccessCreate(label, NULL, &initial_access); | 121 err = SecAccessCreate(label, NULL, &initial_access); |
| 122 // If we fail, just continue without a label. | 122 // If we fail, just continue without a label. |
| 123 if (err) | 123 if (err) |
| 124 base::LogCSSMError("SecAccessCreate", err); | 124 crypto::LogCSSMError("SecAccessCreate", err); |
| 125 } | 125 } |
| 126 | 126 |
| 127 // Create the key-pair. | 127 // Create the key-pair. |
| 128 err = CreateRSAKeyPair(key_size_in_bits_, initial_access, | 128 err = CreateRSAKeyPair(key_size_in_bits_, initial_access, |
| 129 &public_key, &private_key); | 129 &public_key, &private_key); |
| 130 if (err) | 130 if (err) |
| 131 goto failure; | 131 goto failure; |
| 132 | 132 |
| 133 // Get the public key data (DER sequence of modulus, exponent). | 133 // Get the public key data (DER sequence of modulus, exponent). |
| 134 CFDataRef key_data = NULL; | 134 CFDataRef key_data = NULL; |
| 135 err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL, | 135 err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL, |
| 136 &key_data); | 136 &key_data); |
| 137 if (err) { | 137 if (err) { |
| 138 base::LogCSSMError("SecKeychainItemExpor", err); | 138 crypto::LogCSSMError("SecKeychainItemExpor", err); |
| 139 goto failure; | 139 goto failure; |
| 140 } | 140 } |
| 141 base::mac::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data); | 141 base::mac::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data); |
| 142 | 142 |
| 143 // Create an ASN.1 encoder. | 143 // Create an ASN.1 encoder. |
| 144 err = SecAsn1CoderCreate(&coder); | 144 err = SecAsn1CoderCreate(&coder); |
| 145 if (err) { | 145 if (err) { |
| 146 base::LogCSSMError("SecAsn1CoderCreate", err); | 146 crypto::LogCSSMError("SecAsn1CoderCreate", err); |
| 147 goto failure; | 147 goto failure; |
| 148 } | 148 } |
| 149 | 149 |
| 150 // Fill in and DER-encode the PublicKeyAndChallenge: | 150 // Fill in and DER-encode the PublicKeyAndChallenge: |
| 151 SignedPublicKeyAndChallenge spkac; | 151 SignedPublicKeyAndChallenge spkac; |
| 152 memset(&spkac, 0, sizeof(spkac)); | 152 memset(&spkac, 0, sizeof(spkac)); |
| 153 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; | 153 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; |
| 154 spkac.pkac.spki.subjectPublicKey.Length = | 154 spkac.pkac.spki.subjectPublicKey.Length = |
| 155 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count | 155 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count |
| 156 spkac.pkac.spki.subjectPublicKey.Data = | 156 spkac.pkac.spki.subjectPublicKey.Data = |
| 157 const_cast<uint8_t*>(CFDataGetBytePtr(key_data)); | 157 const_cast<uint8_t*>(CFDataGetBytePtr(key_data)); |
| 158 spkac.pkac.challenge_string.Length = challenge_.length(); | 158 spkac.pkac.challenge_string.Length = challenge_.length(); |
| 159 spkac.pkac.challenge_string.Data = | 159 spkac.pkac.challenge_string.Data = |
| 160 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data())); | 160 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data())); |
| 161 | 161 |
| 162 CSSM_DATA encoded; | 162 CSSM_DATA encoded; |
| 163 err = SecAsn1EncodeItem(coder, &spkac.pkac, | 163 err = SecAsn1EncodeItem(coder, &spkac.pkac, |
| 164 kPublicKeyAndChallengeTemplate, &encoded); | 164 kPublicKeyAndChallengeTemplate, &encoded); |
| 165 if (err) { | 165 if (err) { |
| 166 base::LogCSSMError("SecAsn1EncodeItem", err); | 166 crypto::LogCSSMError("SecAsn1EncodeItem", err); |
| 167 goto failure; | 167 goto failure; |
| 168 } | 168 } |
| 169 | 169 |
| 170 // Compute a signature of the result: | 170 // Compute a signature of the result: |
| 171 err = SignData(encoded, private_key, &signature); | 171 err = SignData(encoded, private_key, &signature); |
| 172 if (err) | 172 if (err) |
| 173 goto failure; | 173 goto failure; |
| 174 spkac.signature.Data = signature.Data; | 174 spkac.signature.Data = signature.Data; |
| 175 spkac.signature.Length = signature.Length * 8; // a _bit_ count | 175 spkac.signature.Length = signature.Length * 8; // a _bit_ count |
| 176 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; | 176 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; |
| 177 // TODO(snej): MD5 is weak. Can we use SHA1 instead? | 177 // TODO(snej): MD5 is weak. Can we use SHA1 instead? |
| 178 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460> | 178 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460> |
| 179 | 179 |
| 180 // DER-encode the entire SignedPublicKeyAndChallenge: | 180 // DER-encode the entire SignedPublicKeyAndChallenge: |
| 181 err = SecAsn1EncodeItem(coder, &spkac, | 181 err = SecAsn1EncodeItem(coder, &spkac, |
| 182 kSignedPublicKeyAndChallengeTemplate, &encoded); | 182 kSignedPublicKeyAndChallengeTemplate, &encoded); |
| 183 if (err) { | 183 if (err) { |
| 184 base::LogCSSMError("SecAsn1EncodeItem", err); | 184 crypto::LogCSSMError("SecAsn1EncodeItem", err); |
| 185 goto failure; | 185 goto failure; |
| 186 } | 186 } |
| 187 | 187 |
| 188 // Base64 encode the result. | 188 // Base64 encode the result. |
| 189 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length); | 189 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length); |
| 190 base::Base64Encode(input, &result); | 190 base::Base64Encode(input, &result); |
| 191 } | 191 } |
| 192 | 192 |
| 193 failure: | 193 failure: |
| 194 if (err) | 194 if (err) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 223 // public and private keys are placed in |out_pub_key| and | 223 // public and private keys are placed in |out_pub_key| and |
| 224 // |out_priv_key|, respectively. | 224 // |out_priv_key|, respectively. |
| 225 static OSStatus CreateRSAKeyPair(int size_in_bits, | 225 static OSStatus CreateRSAKeyPair(int size_in_bits, |
| 226 SecAccessRef initial_access, | 226 SecAccessRef initial_access, |
| 227 SecKeyRef* out_pub_key, | 227 SecKeyRef* out_pub_key, |
| 228 SecKeyRef* out_priv_key) { | 228 SecKeyRef* out_priv_key) { |
| 229 OSStatus err; | 229 OSStatus err; |
| 230 SecKeychainRef keychain; | 230 SecKeychainRef keychain; |
| 231 err = SecKeychainCopyDefault(&keychain); | 231 err = SecKeychainCopyDefault(&keychain); |
| 232 if (err) { | 232 if (err) { |
| 233 base::LogCSSMError("SecKeychainCopyDefault", err); | 233 crypto::LogCSSMError("SecKeychainCopyDefault", err); |
| 234 return err; | 234 return err; |
| 235 } | 235 } |
| 236 base::mac::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain); | 236 base::mac::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain); |
| 237 { | 237 { |
| 238 base::AutoLock locked(base::GetMacSecurityServicesLock()); | 238 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); |
| 239 err = SecKeyCreatePair( | 239 err = SecKeyCreatePair( |
| 240 keychain, | 240 keychain, |
| 241 CSSM_ALGID_RSA, | 241 CSSM_ALGID_RSA, |
| 242 size_in_bits, | 242 size_in_bits, |
| 243 0LL, | 243 0LL, |
| 244 // public key usage and attributes: | 244 // public key usage and attributes: |
| 245 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, | 245 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, |
| 246 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT, | 246 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT, |
| 247 // private key usage and attributes: | 247 // private key usage and attributes: |
| 248 CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP, | 248 CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP, |
| 249 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | | 249 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | |
| 250 CSSM_KEYATTR_SENSITIVE, | 250 CSSM_KEYATTR_SENSITIVE, |
| 251 initial_access, | 251 initial_access, |
| 252 out_pub_key, out_priv_key); | 252 out_pub_key, out_priv_key); |
| 253 } | 253 } |
| 254 if (err) | 254 if (err) |
| 255 base::LogCSSMError("SecKeyCreatePair", err); | 255 crypto::LogCSSMError("SecKeyCreatePair", err); |
| 256 return err; | 256 return err; |
| 257 } | 257 } |
| 258 | 258 |
| 259 static OSStatus CreateSignatureContext(SecKeyRef key, | 259 static OSStatus CreateSignatureContext(SecKeyRef key, |
| 260 CSSM_ALGORITHMS algorithm, | 260 CSSM_ALGORITHMS algorithm, |
| 261 CSSM_CC_HANDLE* out_cc_handle) { | 261 CSSM_CC_HANDLE* out_cc_handle) { |
| 262 OSStatus err; | 262 OSStatus err; |
| 263 const CSSM_ACCESS_CREDENTIALS* credentials = NULL; | 263 const CSSM_ACCESS_CREDENTIALS* credentials = NULL; |
| 264 { | 264 { |
| 265 base::AutoLock locked(base::GetMacSecurityServicesLock()); | 265 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); |
| 266 err = SecKeyGetCredentials(key, | 266 err = SecKeyGetCredentials(key, |
| 267 CSSM_ACL_AUTHORIZATION_SIGN, | 267 CSSM_ACL_AUTHORIZATION_SIGN, |
| 268 kSecCredentialTypeDefault, | 268 kSecCredentialTypeDefault, |
| 269 &credentials); | 269 &credentials); |
| 270 } | 270 } |
| 271 if (err) { | 271 if (err) { |
| 272 base::LogCSSMError("SecKeyGetCredentials", err); | 272 crypto::LogCSSMError("SecKeyGetCredentials", err); |
| 273 return err; | 273 return err; |
| 274 } | 274 } |
| 275 | 275 |
| 276 CSSM_CSP_HANDLE csp_handle = 0; | 276 CSSM_CSP_HANDLE csp_handle = 0; |
| 277 { | 277 { |
| 278 base::AutoLock locked(base::GetMacSecurityServicesLock()); | 278 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); |
| 279 err = SecKeyGetCSPHandle(key, &csp_handle); | 279 err = SecKeyGetCSPHandle(key, &csp_handle); |
| 280 } | 280 } |
| 281 if (err) { | 281 if (err) { |
| 282 base::LogCSSMError("SecKeyGetCSPHandle", err); | 282 crypto::LogCSSMError("SecKeyGetCSPHandle", err); |
| 283 return err; | 283 return err; |
| 284 } | 284 } |
| 285 | 285 |
| 286 const CSSM_KEY* cssm_key = NULL; | 286 const CSSM_KEY* cssm_key = NULL; |
| 287 { | 287 { |
| 288 base::AutoLock locked(base::GetMacSecurityServicesLock()); | 288 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); |
| 289 err = SecKeyGetCSSMKey(key, &cssm_key); | 289 err = SecKeyGetCSSMKey(key, &cssm_key); |
| 290 } | 290 } |
| 291 if (err) { | 291 if (err) { |
| 292 base::LogCSSMError("SecKeyGetCSSMKey", err); | 292 crypto::LogCSSMError("SecKeyGetCSSMKey", err); |
| 293 return err; | 293 return err; |
| 294 } | 294 } |
| 295 | 295 |
| 296 err = CSSM_CSP_CreateSignatureContext(csp_handle, | 296 err = CSSM_CSP_CreateSignatureContext(csp_handle, |
| 297 algorithm, | 297 algorithm, |
| 298 credentials, | 298 credentials, |
| 299 cssm_key, | 299 cssm_key, |
| 300 out_cc_handle); | 300 out_cc_handle); |
| 301 if (err) | 301 if (err) |
| 302 base::LogCSSMError("CSSM_CSP_CreateSignatureContext", err); | 302 crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err); |
| 303 return err; | 303 return err; |
| 304 } | 304 } |
| 305 | 305 |
| 306 static OSStatus SignData(CSSM_DATA data, | 306 static OSStatus SignData(CSSM_DATA data, |
| 307 SecKeyRef private_key, | 307 SecKeyRef private_key, |
| 308 CSSM_DATA* signature) { | 308 CSSM_DATA* signature) { |
| 309 CSSM_CC_HANDLE cc_handle; | 309 CSSM_CC_HANDLE cc_handle; |
| 310 OSStatus err = CreateSignatureContext(private_key, | 310 OSStatus err = CreateSignatureContext(private_key, |
| 311 CSSM_ALGID_MD5WithRSA, | 311 CSSM_ALGID_MD5WithRSA, |
| 312 &cc_handle); | 312 &cc_handle); |
| 313 if (err) { | 313 if (err) { |
| 314 base::LogCSSMError("CreateSignatureContext", err); | 314 crypto::LogCSSMError("CreateSignatureContext", err); |
| 315 return err; | 315 return err; |
| 316 } | 316 } |
| 317 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature); | 317 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature); |
| 318 if (err) | 318 if (err) |
| 319 base::LogCSSMError("CSSM_SignData", err); | 319 crypto::LogCSSMError("CSSM_SignData", err); |
| 320 CSSM_DeleteContext(cc_handle); | 320 CSSM_DeleteContext(cc_handle); |
| 321 return err; | 321 return err; |
| 322 } | 322 } |
| 323 | 323 |
| 324 } // namespace net | 324 } // namespace net |
| OLD | NEW |