Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 // Declarations of Netscape keygen cert structures for ASN.1 encoding: | 27 // Declarations of Netscape keygen cert structures for ASN.1 encoding: |
| 28 | 28 |
| 29 struct PublicKeyAndChallenge { | 29 struct PublicKeyAndChallenge { |
| 30 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki; | 30 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki; |
| 31 CSSM_DATA challenge_string; | 31 CSSM_DATA challenge_string; |
| 32 }; | 32 }; |
| 33 | 33 |
| 34 // This is a copy of the built-in kSecAsn1IA5StringTemplate, but without the | 34 // This is a copy of the built-in kSecAsn1IA5StringTemplate, but without the |
| 35 // 'streamable' flag, which was causing bogus data to be written. | 35 // 'streamable' flag, which was causing bogus data to be written. |
| 36 const SecAsn1Template kIA5StringTemplate[] = { | 36 const SecAsn1Template kIA5StringTemplate[] = { |
| 37 { SEC_ASN1_IA5_STRING, 0, NULL, sizeof(CSSM_DATA) } | 37 {SEC_ASN1_IA5_STRING, 0, NULL, sizeof(CSSM_DATA)}}; |
| 38 }; | |
| 39 | 38 |
| 40 static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = { | 39 static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = { |
| 41 { | 40 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PublicKeyAndChallenge)}, |
| 42 SEC_ASN1_SEQUENCE, | 41 {SEC_ASN1_INLINE, |
| 43 0, | 42 offsetof(PublicKeyAndChallenge, spki), |
| 44 NULL, | 43 kSecAsn1SubjectPublicKeyInfoTemplate}, |
| 45 sizeof(PublicKeyAndChallenge) | 44 {SEC_ASN1_INLINE, |
| 46 }, | 45 offsetof(PublicKeyAndChallenge, challenge_string), |
| 47 { | 46 kIA5StringTemplate}, |
| 48 SEC_ASN1_INLINE, | 47 {0}}; |
| 49 offsetof(PublicKeyAndChallenge, spki), | |
| 50 kSecAsn1SubjectPublicKeyInfoTemplate | |
| 51 }, | |
| 52 { | |
| 53 SEC_ASN1_INLINE, | |
| 54 offsetof(PublicKeyAndChallenge, challenge_string), | |
| 55 kIA5StringTemplate | |
| 56 }, | |
| 57 { | |
| 58 0 | |
| 59 } | |
| 60 }; | |
| 61 | 48 |
| 62 struct SignedPublicKeyAndChallenge { | 49 struct SignedPublicKeyAndChallenge { |
| 63 PublicKeyAndChallenge pkac; | 50 PublicKeyAndChallenge pkac; |
| 64 CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm; | 51 CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm; |
| 65 CSSM_DATA signature; | 52 CSSM_DATA signature; |
| 66 }; | 53 }; |
| 67 | 54 |
| 68 static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = { | 55 static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = { |
| 69 { | 56 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SignedPublicKeyAndChallenge)}, |
| 70 SEC_ASN1_SEQUENCE, | 57 {SEC_ASN1_INLINE, |
| 71 0, | 58 offsetof(SignedPublicKeyAndChallenge, pkac), |
| 72 NULL, | 59 kPublicKeyAndChallengeTemplate}, |
| 73 sizeof(SignedPublicKeyAndChallenge) | 60 {SEC_ASN1_INLINE, |
| 74 }, | 61 offsetof(SignedPublicKeyAndChallenge, signature_algorithm), |
| 75 { | 62 kSecAsn1AlgorithmIDTemplate}, |
| 76 SEC_ASN1_INLINE, | 63 {SEC_ASN1_BIT_STRING, offsetof(SignedPublicKeyAndChallenge, signature)}, |
| 77 offsetof(SignedPublicKeyAndChallenge, pkac), | 64 {0}}; |
| 78 kPublicKeyAndChallengeTemplate | |
| 79 }, | |
| 80 { | |
| 81 SEC_ASN1_INLINE, | |
| 82 offsetof(SignedPublicKeyAndChallenge, signature_algorithm), | |
| 83 kSecAsn1AlgorithmIDTemplate | |
| 84 }, | |
| 85 { | |
| 86 SEC_ASN1_BIT_STRING, | |
| 87 offsetof(SignedPublicKeyAndChallenge, signature) | |
| 88 }, | |
| 89 { | |
| 90 0 | |
| 91 } | |
| 92 }; | |
| 93 | |
| 94 | 65 |
| 95 static OSStatus CreateRSAKeyPair(int size_in_bits, | 66 static OSStatus CreateRSAKeyPair(int size_in_bits, |
| 96 SecAccessRef initial_access, | 67 SecAccessRef initial_access, |
| 97 SecKeyRef* out_pub_key, | 68 SecKeyRef* out_pub_key, |
| 98 SecKeyRef* out_priv_key); | 69 SecKeyRef* out_priv_key); |
| 99 static OSStatus SignData(CSSM_DATA data, | 70 static OSStatus SignData(CSSM_DATA data, |
| 100 SecKeyRef private_key, | 71 SecKeyRef private_key, |
| 101 CSSM_DATA* signature); | 72 CSSM_DATA* signature); |
| 102 | 73 |
| 103 std::string KeygenHandler::GenKeyAndSignChallenge() { | 74 std::string KeygenHandler::GenKeyAndSignChallenge() { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 119 // sets a label on the Keychain dialogs. Pass NULL as the second | 90 // sets a label on the Keychain dialogs. Pass NULL as the second |
| 120 // argument to use the default trusted list; only allow the | 91 // argument to use the default trusted list; only allow the |
| 121 // current application to access without user confirmation. | 92 // current application to access without user confirmation. |
| 122 err = SecAccessCreate(label, NULL, &initial_access); | 93 err = SecAccessCreate(label, NULL, &initial_access); |
| 123 // If we fail, just continue without a label. | 94 // If we fail, just continue without a label. |
| 124 if (err) | 95 if (err) |
| 125 crypto::LogCSSMError("SecAccessCreate", err); | 96 crypto::LogCSSMError("SecAccessCreate", err); |
| 126 } | 97 } |
| 127 | 98 |
| 128 // Create the key-pair. | 99 // Create the key-pair. |
| 129 err = CreateRSAKeyPair(key_size_in_bits_, initial_access, | 100 err = CreateRSAKeyPair( |
| 130 &public_key, &private_key); | 101 key_size_in_bits_, initial_access, &public_key, &private_key); |
| 131 if (err) | 102 if (err) |
| 132 goto failure; | 103 goto failure; |
| 133 | 104 |
| 134 // Get the public key data (DER sequence of modulus, exponent). | 105 // Get the public key data (DER sequence of modulus, exponent). |
| 135 CFDataRef key_data = NULL; | 106 CFDataRef key_data = NULL; |
| 136 err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL, | 107 err = |
| 137 &key_data); | 108 SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL, &key_data); |
| 138 if (err) { | 109 if (err) { |
| 139 crypto::LogCSSMError("SecKeychainItemExpor", err); | 110 crypto::LogCSSMError("SecKeychainItemExpor", err); |
| 140 goto failure; | 111 goto failure; |
| 141 } | 112 } |
| 142 base::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data); | 113 base::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data); |
| 143 | 114 |
| 144 // Create an ASN.1 encoder. | 115 // Create an ASN.1 encoder. |
| 145 err = SecAsn1CoderCreate(&coder); | 116 err = SecAsn1CoderCreate(&coder); |
| 146 if (err) { | 117 if (err) { |
| 147 crypto::LogCSSMError("SecAsn1CoderCreate", err); | 118 crypto::LogCSSMError("SecAsn1CoderCreate", err); |
| 148 goto failure; | 119 goto failure; |
| 149 } | 120 } |
| 150 | 121 |
| 151 // Fill in and DER-encode the PublicKeyAndChallenge: | 122 // Fill in and DER-encode the PublicKeyAndChallenge: |
| 152 SignedPublicKeyAndChallenge spkac; | 123 SignedPublicKeyAndChallenge spkac; |
| 153 memset(&spkac, 0, sizeof(spkac)); | 124 memset(&spkac, 0, sizeof(spkac)); |
| 154 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; | 125 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; |
| 155 spkac.pkac.spki.subjectPublicKey.Length = | 126 spkac.pkac.spki.subjectPublicKey.Length = |
| 156 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count | 127 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count |
| 157 spkac.pkac.spki.subjectPublicKey.Data = | 128 spkac.pkac.spki.subjectPublicKey.Data = |
| 158 const_cast<uint8_t*>(CFDataGetBytePtr(key_data)); | 129 const_cast<uint8_t*>(CFDataGetBytePtr(key_data)); |
| 159 spkac.pkac.challenge_string.Length = challenge_.length(); | 130 spkac.pkac.challenge_string.Length = challenge_.length(); |
| 160 spkac.pkac.challenge_string.Data = | 131 spkac.pkac.challenge_string.Data = |
| 161 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data())); | 132 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data())); |
| 162 | 133 |
| 163 CSSM_DATA encoded; | 134 CSSM_DATA encoded; |
| 164 err = SecAsn1EncodeItem(coder, &spkac.pkac, | 135 err = SecAsn1EncodeItem( |
| 165 kPublicKeyAndChallengeTemplate, &encoded); | 136 coder, &spkac.pkac, kPublicKeyAndChallengeTemplate, &encoded); |
| 166 if (err) { | 137 if (err) { |
| 167 crypto::LogCSSMError("SecAsn1EncodeItem", err); | 138 crypto::LogCSSMError("SecAsn1EncodeItem", err); |
| 168 goto failure; | 139 goto failure; |
| 169 } | 140 } |
| 170 | 141 |
| 171 // Compute a signature of the result: | 142 // Compute a signature of the result: |
| 172 err = SignData(encoded, private_key, &signature); | 143 err = SignData(encoded, private_key, &signature); |
| 173 if (err) | 144 if (err) |
| 174 goto failure; | 145 goto failure; |
| 175 spkac.signature.Data = signature.Data; | 146 spkac.signature.Data = signature.Data; |
| 176 spkac.signature.Length = signature.Length * 8; // a _bit_ count | 147 spkac.signature.Length = signature.Length * 8; // a _bit_ count |
| 177 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; | 148 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; |
| 178 // TODO(snej): MD5 is weak. Can we use SHA1 instead? | 149 // TODO(snej): MD5 is weak. Can we use SHA1 instead? |
| 179 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460> | 150 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460> |
| 180 | 151 |
| 181 // DER-encode the entire SignedPublicKeyAndChallenge: | 152 // DER-encode the entire SignedPublicKeyAndChallenge: |
| 182 err = SecAsn1EncodeItem(coder, &spkac, | 153 err = SecAsn1EncodeItem( |
| 183 kSignedPublicKeyAndChallengeTemplate, &encoded); | 154 coder, &spkac, kSignedPublicKeyAndChallengeTemplate, &encoded); |
| 184 if (err) { | 155 if (err) { |
| 185 crypto::LogCSSMError("SecAsn1EncodeItem", err); | 156 crypto::LogCSSMError("SecAsn1EncodeItem", err); |
| 186 goto failure; | 157 goto failure; |
| 187 } | 158 } |
| 188 | 159 |
| 189 // Base64 encode the result. | 160 // Base64 encode the result. |
| 190 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length); | 161 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length); |
| 191 base::Base64Encode(input, &result); | 162 base::Base64Encode(input, &result); |
| 192 } | 163 } |
| 193 | 164 |
| 194 failure: | 165 failure: |
| 195 if (err) | 166 if (err) |
| 196 OSSTATUS_LOG(ERROR, err) << "SSL Keygen failed!"; | 167 OSSTATUS_LOG(ERROR, err) << "SSL Keygen failed!"; |
| 197 else | 168 else |
| 198 VLOG(1) << "SSL Keygen succeeded! Output is: " << result; | 169 VLOG(1) << "SSL Keygen succeeded! Output is: " << result; |
| 199 | 170 |
| 200 // Remove keys from keychain if asked to during unit testing: | 171 // Remove keys from keychain if asked to during unit testing: |
| 201 if (!stores_key_) { | 172 if (!stores_key_) { |
| 202 if (public_key) | 173 if (public_key) |
| 203 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key)); | 174 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key)); |
| 204 if (private_key) | 175 if (private_key) |
| 205 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key)); | 176 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key)); |
| 206 } | 177 } |
| 207 | 178 |
| 208 // Clean up: | 179 // Clean up: |
| 209 free(signature.Data); | 180 free(signature.Data); |
| 210 if (coder) | 181 if (coder) |
| 211 SecAsn1CoderRelease(coder); | 182 SecAsn1CoderRelease(coder); |
| 212 if (initial_access) | 183 if (initial_access) |
| 213 CFRelease(initial_access); | 184 CFRelease(initial_access); |
| 214 if (public_key) | 185 if (public_key) |
| 215 CFRelease(public_key); | 186 CFRelease(public_key); |
| 216 if (private_key) | 187 if (private_key) |
| 217 CFRelease(private_key); | 188 CFRelease(private_key); |
| 218 return result; | 189 return result; |
| 219 } | 190 } |
| 220 | 191 |
| 221 | |
| 222 // Create an RSA key pair with size |size_in_bits|. |initial_access| | 192 // Create an RSA key pair with size |size_in_bits|. |initial_access| |
| 223 // is passed as the initial access control list in Keychain. The | 193 // is passed as the initial access control list in Keychain. The |
| 224 // public and private keys are placed in |out_pub_key| and | 194 // public and private keys are placed in |out_pub_key| and |
| 225 // |out_priv_key|, respectively. | 195 // |out_priv_key|, respectively. |
| 226 static OSStatus CreateRSAKeyPair(int size_in_bits, | 196 static OSStatus CreateRSAKeyPair(int size_in_bits, |
| 227 SecAccessRef initial_access, | 197 SecAccessRef initial_access, |
| 228 SecKeyRef* out_pub_key, | 198 SecKeyRef* out_pub_key, |
| 229 SecKeyRef* out_priv_key) { | 199 SecKeyRef* out_priv_key) { |
| 230 OSStatus err; | 200 OSStatus err; |
| 231 SecKeychainRef keychain; | 201 SecKeychainRef keychain; |
| 232 err = SecKeychainCopyDefault(&keychain); | 202 err = SecKeychainCopyDefault(&keychain); |
| 233 if (err) { | 203 if (err) { |
| 234 crypto::LogCSSMError("SecKeychainCopyDefault", err); | 204 crypto::LogCSSMError("SecKeychainCopyDefault", err); |
| 235 return err; | 205 return err; |
| 236 } | 206 } |
| 237 base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain); | 207 base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain); |
| 238 { | 208 { |
| 239 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); | 209 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); |
| 240 err = SecKeyCreatePair( | 210 err = SecKeyCreatePair(keychain, |
|
Ryan Sleevi
2014/10/11 02:04:47
Probably a clang-format bug here.
It should have
jkarlin
2014/11/11 19:01:44
Done.
| |
| 241 keychain, | 211 CSSM_ALGID_RSA, |
| 242 CSSM_ALGID_RSA, | 212 size_in_bits, |
| 243 size_in_bits, | 213 0LL, |
| 244 0LL, | 214 // public key usage and attributes: |
| 245 // public key usage and attributes: | 215 CSSM_KEYUSE_ENCRYPT | |
| 246 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, | 216 CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, |
| 247 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT, | 217 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT, |
| 248 // private key usage and attributes: | 218 // private key usage and attributes: |
| 249 CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP, | 219 CSSM_KEYUSE_DECRYPT | |
| 250 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | | 220 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP, |
| 251 CSSM_KEYATTR_SENSITIVE, | 221 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | |
| 252 initial_access, | 222 CSSM_KEYATTR_SENSITIVE, |
| 253 out_pub_key, out_priv_key); | 223 initial_access, |
| 224 out_pub_key, | |
| 225 out_priv_key); | |
| 254 } | 226 } |
| 255 if (err) | 227 if (err) |
| 256 crypto::LogCSSMError("SecKeyCreatePair", err); | 228 crypto::LogCSSMError("SecKeyCreatePair", err); |
| 257 return err; | 229 return err; |
| 258 } | 230 } |
| 259 | 231 |
| 260 static OSStatus CreateSignatureContext(SecKeyRef key, | 232 static OSStatus CreateSignatureContext(SecKeyRef key, |
| 261 CSSM_ALGORITHMS algorithm, | 233 CSSM_ALGORITHMS algorithm, |
| 262 CSSM_CC_HANDLE* out_cc_handle) { | 234 CSSM_CC_HANDLE* out_cc_handle) { |
| 263 OSStatus err; | 235 OSStatus err; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 287 const CSSM_KEY* cssm_key = NULL; | 259 const CSSM_KEY* cssm_key = NULL; |
| 288 { | 260 { |
| 289 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); | 261 base::AutoLock locked(crypto::GetMacSecurityServicesLock()); |
| 290 err = SecKeyGetCSSMKey(key, &cssm_key); | 262 err = SecKeyGetCSSMKey(key, &cssm_key); |
| 291 } | 263 } |
| 292 if (err) { | 264 if (err) { |
| 293 crypto::LogCSSMError("SecKeyGetCSSMKey", err); | 265 crypto::LogCSSMError("SecKeyGetCSSMKey", err); |
| 294 return err; | 266 return err; |
| 295 } | 267 } |
| 296 | 268 |
| 297 err = CSSM_CSP_CreateSignatureContext(csp_handle, | 269 err = CSSM_CSP_CreateSignatureContext( |
| 298 algorithm, | 270 csp_handle, algorithm, credentials, cssm_key, out_cc_handle); |
| 299 credentials, | |
| 300 cssm_key, | |
| 301 out_cc_handle); | |
| 302 if (err) | 271 if (err) |
| 303 crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err); | 272 crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err); |
| 304 return err; | 273 return err; |
| 305 } | 274 } |
| 306 | 275 |
| 307 static OSStatus SignData(CSSM_DATA data, | 276 static OSStatus SignData(CSSM_DATA data, |
| 308 SecKeyRef private_key, | 277 SecKeyRef private_key, |
| 309 CSSM_DATA* signature) { | 278 CSSM_DATA* signature) { |
| 310 CSSM_CC_HANDLE cc_handle; | 279 CSSM_CC_HANDLE cc_handle; |
| 311 OSStatus err = CreateSignatureContext(private_key, | 280 OSStatus err = |
| 312 CSSM_ALGID_MD5WithRSA, | 281 CreateSignatureContext(private_key, CSSM_ALGID_MD5WithRSA, &cc_handle); |
| 313 &cc_handle); | |
| 314 if (err) { | 282 if (err) { |
| 315 crypto::LogCSSMError("CreateSignatureContext", err); | 283 crypto::LogCSSMError("CreateSignatureContext", err); |
| 316 return err; | 284 return err; |
| 317 } | 285 } |
| 318 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature); | 286 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature); |
| 319 if (err) | 287 if (err) |
| 320 crypto::LogCSSMError("CSSM_SignData", err); | 288 crypto::LogCSSMError("CSSM_SignData", err); |
| 321 CSSM_DeleteContext(cc_handle); | 289 CSSM_DeleteContext(cc_handle); |
| 322 return err; | 290 return err; |
| 323 } | 291 } |
| 324 | 292 |
| 325 } // namespace net | 293 } // namespace net |
| OLD | NEW |