OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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> | |
8 #include <Security/SecAsn1Templates.h> | |
9 #include <Security/Security.h> | |
10 | |
11 #include "base/base64.h" | |
7 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/scoped_cftyperef.h" | |
14 | |
15 // These are in Security.framework but not declared in a public header. | |
16 extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[]; | |
17 extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[]; | |
8 | 18 |
9 namespace net { | 19 namespace net { |
10 | 20 |
11 KeygenHandler::KeygenHandler(int key_size_index, | 21 // Declarations of Netscape keygen cert structures for ASN.1 encoding: |
12 const std::string& challenge) | 22 |
13 : key_size_index_(key_size_index), | 23 struct PublicKeyAndChallenge { |
14 challenge_(challenge) { | 24 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki; |
15 NOTIMPLEMENTED(); | 25 CSSM_DATA challenge_string; |
16 } | 26 }; |
27 | |
28 static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = { | |
29 { | |
30 SEC_ASN1_SEQUENCE, | |
31 0, | |
32 NULL, | |
33 sizeof(PublicKeyAndChallenge) | |
34 }, | |
35 { | |
36 SEC_ASN1_INLINE, | |
37 offsetof(PublicKeyAndChallenge, spki), | |
38 kSecAsn1SubjectPublicKeyInfoTemplate | |
39 }, | |
40 { | |
41 SEC_ASN1_INLINE, | |
42 offsetof(PublicKeyAndChallenge, challenge_string), | |
43 kSecAsn1IA5StringTemplate | |
44 }, | |
45 { | |
46 0 | |
47 } | |
48 }; | |
49 | |
50 struct SignedPublicKeyAndChallenge { | |
51 PublicKeyAndChallenge pkac; | |
52 CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm; | |
53 CSSM_DATA signature; | |
54 }; | |
55 | |
56 static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = { | |
57 { | |
58 SEC_ASN1_SEQUENCE, | |
59 0, | |
60 NULL, | |
61 sizeof(SignedPublicKeyAndChallenge) | |
62 }, | |
63 { | |
64 SEC_ASN1_INLINE, | |
65 offsetof(SignedPublicKeyAndChallenge, pkac), | |
66 kPublicKeyAndChallengeTemplate | |
67 }, | |
68 { | |
69 SEC_ASN1_INLINE, | |
70 offsetof(SignedPublicKeyAndChallenge, signature_algorithm), | |
71 kSecAsn1AlgorithmIDTemplate | |
72 }, | |
73 { | |
74 SEC_ASN1_BIT_STRING, | |
75 offsetof(SignedPublicKeyAndChallenge, signature) | |
76 }, | |
77 { | |
78 0 | |
79 } | |
80 }; | |
81 | |
82 | |
83 static OSStatus CreateRSAKeyPair(int size_in_bits, | |
84 SecKeyRef* out_pub_key, | |
85 SecKeyRef* out_priv_key); | |
86 static OSStatus SignData(CSSM_DATA data, | |
87 SecKeyRef private_key, | |
88 CSSM_DATA* signature); | |
89 | |
17 | 90 |
18 std::string KeygenHandler::GenKeyAndSignChallenge() { | 91 std::string KeygenHandler::GenKeyAndSignChallenge() { |
19 NOTIMPLEMENTED(); | 92 std::string result; |
20 return std::string(); | 93 OSStatus err; |
94 SecKeyRef public_key = NULL; | |
95 SecKeyRef private_key = NULL; | |
96 SecAsn1CoderRef coder = NULL; | |
97 CSSM_DATA signature = {0, NULL}; | |
98 | |
99 { | |
100 // Create the key-pair. | |
101 err = CreateRSAKeyPair(key_size_in_bits_, &public_key, &private_key); | |
102 if (err) | |
103 goto failure; | |
104 | |
105 // Get the public key data (DER sequence of modulus, exponent). | |
106 CFDataRef key_data = NULL; | |
107 err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL, | |
108 &key_data); | |
109 if (err) | |
110 goto failure; | |
111 scoped_cftyperef<CFDataRef> scoped_key_data(key_data); | |
112 | |
113 // Create an ASN.1 encoder. | |
114 err = SecAsn1CoderCreate(&coder); | |
115 if (err) | |
116 goto failure; | |
117 | |
118 // Fill in and DER-encode the PublicKeyAndChallenge: | |
119 SignedPublicKeyAndChallenge spkac; | |
120 memset(&spkac, 0, sizeof(spkac)); | |
121 spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; | |
122 spkac.pkac.spki.subjectPublicKey.Length = | |
123 CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count | |
124 spkac.pkac.spki.subjectPublicKey.Data = | |
125 const_cast<uint8_t*>(CFDataGetBytePtr(key_data)); | |
126 spkac.pkac.challenge_string.Length = challenge_.length(); | |
127 spkac.pkac.challenge_string.Data = | |
128 reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data())); | |
129 | |
130 CSSM_DATA encoded; | |
131 err = SecAsn1EncodeItem(coder, &spkac.pkac, | |
132 kPublicKeyAndChallengeTemplate, &encoded); | |
133 if (err) | |
134 goto failure; | |
135 | |
136 // Compute a signature of the result: | |
137 err = SignData(encoded, private_key, &signature); | |
138 if (err) | |
139 goto failure; | |
140 spkac.signature.Data = signature.Data; | |
141 spkac.signature.Length = signature.Length * 8; // a _bit_ count | |
142 spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; | |
wtc
2010/03/01 23:05:40
Can we use SHA1WithRSA instead of MD5WithRSA? (Th
| |
143 | |
144 // DER-encode the entire SignedPublicKeyAndChallenge: | |
145 err = SecAsn1EncodeItem(coder, &spkac, | |
146 kSignedPublicKeyAndChallengeTemplate, &encoded); | |
147 if (err) | |
148 goto failure; | |
149 | |
150 // Base64 encode the result. | |
151 std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length); | |
152 base::Base64Encode(input, &result); | |
153 } | |
154 | |
155 failure: | |
156 if (err) { | |
157 LOG(ERROR) << "SSL Keygen failed! OSStatus = " << err; | |
158 } else { | |
159 LOG(INFO) << "SSL Keygen succeeded! Output is: " << result; | |
160 } | |
161 | |
162 // Remove keys from keychain if asked to during unit testing: | |
163 if (!stores_key_) { | |
164 if (public_key) | |
165 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key)); | |
166 if (private_key) | |
167 SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key)); | |
168 } | |
169 | |
170 // Clean up: | |
171 free(signature.Data); | |
172 if (coder) | |
173 SecAsn1CoderRelease(coder); | |
174 if (public_key) | |
175 CFRelease(public_key); | |
176 if (private_key) | |
177 CFRelease(private_key); | |
178 return result; | |
179 } | |
180 | |
181 | |
182 static OSStatus CreateRSAKeyPair(int size_in_bits, | |
183 SecKeyRef* out_pub_key, | |
184 SecKeyRef* out_priv_key) { | |
185 OSStatus err; | |
186 SecKeychainRef keychain; | |
187 err = SecKeychainCopyDefault(&keychain); | |
188 if (err) | |
189 return err; | |
190 scoped_cftyperef<SecKeychainRef> scoped_keychain(keychain); | |
191 return SecKeyCreatePair( | |
192 keychain, | |
193 CSSM_ALGID_RSA, | |
194 size_in_bits, | |
195 0LL, | |
196 // public key usage and attributes: | |
197 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP, | |
198 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT, | |
199 // private key usage and attributes: | |
200 CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP, // private key | |
201 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT | | |
202 CSSM_KEYATTR_SENSITIVE, | |
203 NULL, | |
204 out_pub_key, out_priv_key); | |
205 } | |
206 | |
207 static OSStatus CreateSignatureContext(SecKeyRef key, | |
208 CSSM_ALGORITHMS algorithm, | |
209 CSSM_CC_HANDLE* out_cc_handle) { | |
210 OSStatus err; | |
211 const CSSM_ACCESS_CREDENTIALS* credentials = NULL; | |
212 err = SecKeyGetCredentials(key, | |
213 CSSM_ACL_AUTHORIZATION_SIGN, | |
214 kSecCredentialTypeDefault, | |
215 &credentials); | |
216 if (err) | |
217 return err; | |
218 | |
219 CSSM_CSP_HANDLE csp_handle = 0; | |
220 err = SecKeyGetCSPHandle(key, &csp_handle); | |
221 if (err) | |
222 return err; | |
223 | |
224 const CSSM_KEY* cssm_key = NULL; | |
225 err = SecKeyGetCSSMKey(key, &cssm_key); | |
226 if (err) | |
227 return err; | |
228 | |
229 return CSSM_CSP_CreateSignatureContext(csp_handle, | |
230 algorithm, | |
231 credentials, | |
232 cssm_key, | |
233 out_cc_handle); | |
234 } | |
235 | |
236 static OSStatus SignData(CSSM_DATA data, | |
237 SecKeyRef private_key, | |
238 CSSM_DATA* signature) { | |
239 CSSM_CC_HANDLE cc_handle; | |
240 OSStatus err = CreateSignatureContext(private_key, | |
241 CSSM_ALGID_MD5WithRSA, | |
242 &cc_handle); | |
243 if (err) | |
244 return err; | |
245 err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature); | |
246 CSSM_DeleteContext(cc_handle); | |
247 return err; | |
21 } | 248 } |
22 | 249 |
23 } // namespace net | 250 } // namespace net |
OLD | NEW |