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 |