Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(913)

Side by Side Diff: net/base/keygen_handler_mac.cc

Issue 2536993002: Remove support for the keygen tag (Closed)
Patch Set: Rebased Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/keygen_handler.cc ('k') | net/base/keygen_handler_nss.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/base/keygen_handler.h"
6
7 #include <Security/SecAsn1Coder.h>
8 #include <Security/SecAsn1Templates.h>
9 #include <Security/Security.h>
10
11 #include "base/base64.h"
12 #include "base/logging.h"
13 #include "base/mac/mac_logging.h"
14 #include "base/mac/scoped_cftyperef.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "base/synchronization/lock.h"
18 #include "crypto/cssm_init.h"
19 #include "crypto/mac_security_services_lock.h"
20
21 // CSSM functions are deprecated as of OSX 10.7, but have no replacement.
22 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
25
26 // These are in Security.framework but not declared in a public header.
27 extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[];
28 extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[];
29
30 namespace net {
31
32 // Declarations of Netscape keygen cert structures for ASN.1 encoding:
33
34 struct PublicKeyAndChallenge {
35 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki;
36 CSSM_DATA challenge_string;
37 };
38
39 // This is a copy of the built-in kSecAsn1IA5StringTemplate, but without the
40 // 'streamable' flag, which was causing bogus data to be written.
41 const SecAsn1Template kIA5StringTemplate[] = {
42 { SEC_ASN1_IA5_STRING, 0, NULL, sizeof(CSSM_DATA) }
43 };
44
45 static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = {
46 {
47 SEC_ASN1_SEQUENCE,
48 0,
49 NULL,
50 sizeof(PublicKeyAndChallenge)
51 },
52 {
53 SEC_ASN1_INLINE,
54 offsetof(PublicKeyAndChallenge, spki),
55 kSecAsn1SubjectPublicKeyInfoTemplate
56 },
57 {
58 SEC_ASN1_INLINE,
59 offsetof(PublicKeyAndChallenge, challenge_string),
60 kIA5StringTemplate
61 },
62 {
63 0
64 }
65 };
66
67 struct SignedPublicKeyAndChallenge {
68 PublicKeyAndChallenge pkac;
69 CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm;
70 CSSM_DATA signature;
71 };
72
73 static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = {
74 {
75 SEC_ASN1_SEQUENCE,
76 0,
77 NULL,
78 sizeof(SignedPublicKeyAndChallenge)
79 },
80 {
81 SEC_ASN1_INLINE,
82 offsetof(SignedPublicKeyAndChallenge, pkac),
83 kPublicKeyAndChallengeTemplate
84 },
85 {
86 SEC_ASN1_INLINE,
87 offsetof(SignedPublicKeyAndChallenge, signature_algorithm),
88 kSecAsn1AlgorithmIDTemplate
89 },
90 {
91 SEC_ASN1_BIT_STRING,
92 offsetof(SignedPublicKeyAndChallenge, signature)
93 },
94 {
95 0
96 }
97 };
98
99
100 static OSStatus CreateRSAKeyPair(int size_in_bits,
101 SecAccessRef initial_access,
102 SecKeyRef* out_pub_key,
103 SecKeyRef* out_priv_key);
104 static OSStatus SignData(CSSM_DATA data,
105 SecKeyRef private_key,
106 CSSM_DATA* signature);
107
108 std::string KeygenHandler::GenKeyAndSignChallenge() {
109 std::string result;
110 OSStatus err;
111 SecAccessRef initial_access = NULL;
112 SecKeyRef public_key = NULL;
113 SecKeyRef private_key = NULL;
114 SecAsn1CoderRef coder = NULL;
115 CSSM_DATA signature = {0, NULL};
116
117 {
118 if (url_.has_host()) {
119 // TODO(davidben): Use something like "Key generated for
120 // example.com", but localize it.
121 base::ScopedCFTypeRef<CFStringRef> label(
122 base::SysUTF8ToCFStringRef(url_.host()));
123 // Create an initial access object to set the SecAccessRef. This
124 // sets a label on the Keychain dialogs. Pass NULL as the second
125 // argument to use the default trusted list; only allow the
126 // current application to access without user confirmation.
127 err = SecAccessCreate(label, NULL, &initial_access);
128 // If we fail, just continue without a label.
129 if (err)
130 crypto::LogCSSMError("SecAccessCreate", err);
131 }
132
133 // Create the key-pair.
134 err = CreateRSAKeyPair(key_size_in_bits_, initial_access,
135 &public_key, &private_key);
136 if (err)
137 goto failure;
138
139 // Get the public key data (DER sequence of modulus, exponent).
140 CFDataRef key_data = NULL;
141 err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL,
142 &key_data);
143 if (err) {
144 crypto::LogCSSMError("SecKeychainItemExpor", err);
145 goto failure;
146 }
147 base::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data);
148
149 // Create an ASN.1 encoder.
150 err = SecAsn1CoderCreate(&coder);
151 if (err) {
152 crypto::LogCSSMError("SecAsn1CoderCreate", err);
153 goto failure;
154 }
155
156 // The DER encoding of a NULL.
157 static const uint8_t kNullDer[] = {0x05, 0x00};
158
159 // Fill in and DER-encode the PublicKeyAndChallenge:
160 SignedPublicKeyAndChallenge spkac;
161 memset(&spkac, 0, sizeof(spkac));
162 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA;
163 spkac.pkac.spki.algorithm.parameters.Data = const_cast<uint8_t*>(kNullDer);
164 spkac.pkac.spki.algorithm.parameters.Length = sizeof(kNullDer);
165 spkac.pkac.spki.subjectPublicKey.Length =
166 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count
167 spkac.pkac.spki.subjectPublicKey.Data =
168 const_cast<uint8_t*>(CFDataGetBytePtr(key_data));
169 spkac.pkac.challenge_string.Length = challenge_.length();
170 spkac.pkac.challenge_string.Data =
171 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data()));
172
173 CSSM_DATA encoded;
174 err = SecAsn1EncodeItem(coder, &spkac.pkac,
175 kPublicKeyAndChallengeTemplate, &encoded);
176 if (err) {
177 crypto::LogCSSMError("SecAsn1EncodeItem", err);
178 goto failure;
179 }
180
181 // Compute a signature of the result:
182 err = SignData(encoded, private_key, &signature);
183 if (err)
184 goto failure;
185 spkac.signature.Data = signature.Data;
186 spkac.signature.Length = signature.Length * 8; // a _bit_ count
187 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA;
188 spkac.signature_algorithm.parameters.Data = const_cast<uint8_t*>(kNullDer);
189 spkac.signature_algorithm.parameters.Length = sizeof(kNullDer);
190 // TODO(snej): MD5 is weak. Can we use SHA1 instead?
191 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460>
192
193 // DER-encode the entire SignedPublicKeyAndChallenge:
194 err = SecAsn1EncodeItem(coder, &spkac,
195 kSignedPublicKeyAndChallengeTemplate, &encoded);
196 if (err) {
197 crypto::LogCSSMError("SecAsn1EncodeItem", err);
198 goto failure;
199 }
200
201 // Base64 encode the result.
202 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length);
203 base::Base64Encode(input, &result);
204 }
205
206 failure:
207 if (err)
208 OSSTATUS_LOG(ERROR, err) << "SSL Keygen failed!";
209 else
210 VLOG(1) << "SSL Keygen succeeded! Output is: " << result;
211
212 // Remove keys from keychain if asked to during unit testing:
213 if (!stores_key_) {
214 if (public_key)
215 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key));
216 if (private_key)
217 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key));
218 }
219
220 // Clean up:
221 free(signature.Data);
222 if (coder)
223 SecAsn1CoderRelease(coder);
224 if (initial_access)
225 CFRelease(initial_access);
226 if (public_key)
227 CFRelease(public_key);
228 if (private_key)
229 CFRelease(private_key);
230 return result;
231 }
232
233
234 // Create an RSA key pair with size |size_in_bits|. |initial_access|
235 // is passed as the initial access control list in Keychain. The
236 // public and private keys are placed in |out_pub_key| and
237 // |out_priv_key|, respectively.
238 static OSStatus CreateRSAKeyPair(int size_in_bits,
239 SecAccessRef initial_access,
240 SecKeyRef* out_pub_key,
241 SecKeyRef* out_priv_key) {
242 OSStatus err;
243 SecKeychainRef keychain;
244 err = SecKeychainCopyDefault(&keychain);
245 if (err) {
246 crypto::LogCSSMError("SecKeychainCopyDefault", err);
247 return err;
248 }
249 base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
250 {
251 base::AutoLock locked(crypto::GetMacSecurityServicesLock());
252 err = SecKeyCreatePair(
253 keychain,
254 CSSM_ALGID_RSA,
255 size_in_bits,
256 0LL,
257 // public key usage and attributes:
258 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP,
259 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
260 // private key usage and attributes:
261 CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP,
262 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT |
263 CSSM_KEYATTR_SENSITIVE,
264 initial_access,
265 out_pub_key, out_priv_key);
266 }
267 if (err)
268 crypto::LogCSSMError("SecKeyCreatePair", err);
269 return err;
270 }
271
272 static OSStatus CreateSignatureContext(SecKeyRef key,
273 CSSM_ALGORITHMS algorithm,
274 CSSM_CC_HANDLE* out_cc_handle) {
275 OSStatus err;
276 const CSSM_ACCESS_CREDENTIALS* credentials = NULL;
277 {
278 base::AutoLock locked(crypto::GetMacSecurityServicesLock());
279 err = SecKeyGetCredentials(key,
280 CSSM_ACL_AUTHORIZATION_SIGN,
281 kSecCredentialTypeDefault,
282 &credentials);
283 }
284 if (err) {
285 crypto::LogCSSMError("SecKeyGetCredentials", err);
286 return err;
287 }
288
289 CSSM_CSP_HANDLE csp_handle = 0;
290 {
291 base::AutoLock locked(crypto::GetMacSecurityServicesLock());
292 err = SecKeyGetCSPHandle(key, &csp_handle);
293 }
294 if (err) {
295 crypto::LogCSSMError("SecKeyGetCSPHandle", err);
296 return err;
297 }
298
299 const CSSM_KEY* cssm_key = NULL;
300 {
301 base::AutoLock locked(crypto::GetMacSecurityServicesLock());
302 err = SecKeyGetCSSMKey(key, &cssm_key);
303 }
304 if (err) {
305 crypto::LogCSSMError("SecKeyGetCSSMKey", err);
306 return err;
307 }
308
309 err = CSSM_CSP_CreateSignatureContext(csp_handle,
310 algorithm,
311 credentials,
312 cssm_key,
313 out_cc_handle);
314 if (err)
315 crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err);
316 return err;
317 }
318
319 static OSStatus SignData(CSSM_DATA data,
320 SecKeyRef private_key,
321 CSSM_DATA* signature) {
322 CSSM_CC_HANDLE cc_handle;
323 OSStatus err = CreateSignatureContext(private_key,
324 CSSM_ALGID_MD5WithRSA,
325 &cc_handle);
326 if (err) {
327 crypto::LogCSSMError("CreateSignatureContext", err);
328 return err;
329 }
330 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature);
331 if (err)
332 crypto::LogCSSMError("CSSM_SignData", err);
333 CSSM_DeleteContext(cc_handle);
334 return err;
335 }
336
337 } // namespace net
338
339 #pragma clang diagnostic pop // "-Wdeprecated-declarations"
OLDNEW
« no previous file with comments | « net/base/keygen_handler.cc ('k') | net/base/keygen_handler_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698