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