]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
427c49bc | 24 | |
5c19dc3a | 25 | #include <Security/SecureObjectSync/SOSUserKeygen.h> |
427c49bc A |
26 | #include <stdio.h> |
27 | #include <corecrypto/ccrng.h> | |
28 | #include <corecrypto/ccrng_pbkdf2_prng.h> | |
29 | #include <corecrypto/ccec.h> | |
30 | #include <corecrypto/ccdigest.h> | |
31 | #include <corecrypto/ccsha2.h> | |
32 | #include <CommonCrypto/CommonRandomSPI.h> | |
33 | #include <Security/SecKey.h> | |
34 | #include <Security/SecKeyPriv.h> | |
35 | #include <Security/SecFramework.h> | |
36 | #include <utilities/SecCFWrappers.h> | |
37 | #include <utilities/SecCFRelease.h> | |
38 | #include <utilities/debugging.h> | |
5c19dc3a A |
39 | #include <Security/SecureObjectSync/SOSCloudCircle.h> |
40 | #include <Security/SecureObjectSync/SOSInternal.h> | |
41 | #include <Security/SecureObjectSync/SOSAccount.h> | |
427c49bc A |
42 | #include <Security/SecFramework.h> |
43 | #include <Security/SecItem.h> | |
44 | #include <utilities/der_plist.h> | |
45 | #include <utilities/der_plist_internal.h> | |
46 | ||
47 | #include <corecrypto/ccder.h> | |
48 | #include <Security/oidsalg.h> | |
49 | ||
50 | // A.2 PBKDF2 | |
51 | // | |
52 | // The object identifier id-PBKDF2 identifies the PBKDF2 key derivation | |
53 | // function (Section 5.2). | |
54 | // | |
55 | // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} | |
56 | // | |
57 | // The parameters field associated with this OID in an | |
58 | // AlgorithmIdentifier shall have type PBKDF2-params: | |
59 | // | |
60 | // PBKDF2-params ::= SEQUENCE { | |
61 | // salt CHOICE { | |
62 | // specified OCTET STRING, | |
63 | // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} | |
64 | // }, | |
65 | // iterationCount INTEGER (1..MAX), | |
66 | // keyLength INTEGER (1..MAX) OPTIONAL, | |
67 | // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT | |
68 | // algid-hmacWithSHA1 } | |
69 | // | |
70 | // The fields of type PKDF2-params have the following meanings: | |
71 | ||
72 | ||
73 | static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid* secasn_oid) | |
74 | { | |
75 | return ccder_sizeof(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length); | |
76 | } | |
77 | ||
78 | static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, uint8_t *der_end) | |
79 | { | |
80 | return ccder_encode_tl(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length, der, | |
81 | ccder_encode_body(secasn_oid->Length, secasn_oid->Data, der, der_end)); | |
82 | } | |
83 | ||
84 | static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, const uint8_t *der_end) | |
85 | { | |
86 | size_t len = 0; | |
87 | der = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &len, | |
88 | der, der_end); | |
89 | ||
90 | if (secasn_oid->Length != len || memcmp(secasn_oid->Data, der, len) != 0) | |
91 | der = NULL; | |
92 | else | |
93 | der += len; | |
94 | ||
95 | return der; | |
96 | } | |
97 | ||
98 | static size_t der_sizeof_pbkdf2_params(size_t saltLen, const uint8_t *salt, | |
99 | unsigned long iterationCount, | |
100 | unsigned long keyLength) | |
101 | { | |
102 | size_t body_size = ccder_sizeof_raw_octet_string(saltLen) | |
103 | + ccder_sizeof_uint64(iterationCount) | |
104 | + ccder_sizeof_uint64(keyLength) | |
105 | + der_sizeof_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1); | |
106 | ||
107 | return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size); | |
108 | } | |
109 | ||
110 | static uint8_t *der_encode_pbkdf2_params(size_t saltLen, const uint8_t *salt, | |
111 | unsigned long iterationCount, | |
112 | unsigned long keyLength, | |
113 | const uint8_t *der, uint8_t *der_end) | |
114 | { | |
115 | uint8_t* original_der_end = der_end; | |
116 | ||
117 | return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, | |
118 | ccder_encode_raw_octet_string(saltLen, salt, der, | |
119 | ccder_encode_uint64(iterationCount, der, | |
120 | ccder_encode_uint64(keyLength, der, | |
121 | der_encode_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, der_end))))); | |
122 | } | |
123 | ||
124 | static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen, const uint8_t **salt, | |
125 | unsigned long *iterationCount, | |
126 | unsigned long *keyLength, | |
127 | const uint8_t *der, const uint8_t *der_end) | |
128 | { | |
129 | const uint8_t * body_end = NULL; | |
130 | der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &body_end, der, der_end); | |
131 | ||
132 | if (body_end != der_end) | |
133 | der = NULL; | |
134 | ||
135 | size_t salt_size = 0; | |
136 | const uint8_t *salt_bytes = NULL; | |
137 | ||
138 | der = ccder_decode_tl(CCDER_OCTET_STRING, &salt_size, der, body_end); | |
139 | salt_bytes = der; | |
140 | der += salt_size; | |
141 | ||
142 | uint64_t iteration_count = 0; | |
143 | uint64_t key_len = 0; | |
144 | der = ccder_decode_uint64(&iteration_count, der, body_end); | |
145 | if (iteration_count > UINT32_MAX) | |
146 | der = NULL; | |
147 | ||
148 | der = ccder_decode_uint64(&key_len, der, body_end); | |
149 | if (key_len > UINT32_MAX) | |
150 | der = NULL; | |
151 | ||
152 | der = der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, body_end); | |
153 | ||
154 | if (der) { | |
155 | if (salt) | |
156 | *salt = salt_bytes; | |
157 | if (saltLen) | |
158 | *saltLen = salt_size; | |
159 | if (iterationCount) | |
160 | *iterationCount = (unsigned long)iteration_count; | |
161 | if (keyLength) | |
162 | *keyLength = (unsigned long) key_len; | |
163 | } | |
164 | ||
165 | return der; | |
166 | } | |
167 | ||
168 | ||
169 | static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk) | |
170 | { | |
171 | size_t export_size = ccec_x963_export_size(1, fk); | |
172 | uint8_t export_keybytes[export_size]; | |
173 | ccec_x963_export(1, export_keybytes, fk); | |
174 | CFDataRef exportedkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, export_keybytes, export_size, kCFAllocatorNull); | |
175 | ||
176 | CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, | |
177 | kSecValueData, exportedkey, | |
178 | kSecAttrKeyType, kSecAttrKeyTypeEC, | |
179 | kSecAttrKeyClass, kSecAttrKeyClassPrivate, | |
180 | NULL); | |
181 | ||
182 | SecKeyRef retval = SecKeyCreateFromAttributeDictionary(keyattributes); | |
183 | ||
184 | CFRelease(keyattributes); | |
185 | CFRelease(exportedkey); | |
186 | bzero(export_keybytes, 0); | |
187 | return retval; | |
188 | } | |
189 | ||
190 | #define SALTMAX 16 | |
191 | #define ITERATIONMIN 50000 | |
192 | ||
193 | CFDataRef SOSUserKeyCreateGenerateParameters(CFErrorRef *error) { | |
194 | size_t saltlen = SALTMAX; | |
195 | uint8_t salt[saltlen]; | |
196 | ||
197 | size_t iterations = ITERATIONMIN; | |
198 | size_t keysize = 256; | |
199 | ||
200 | if(CCRandomCopyBytes(kCCRandomDefault, salt, sizeof(salt)) != kCCSuccess) { | |
201 | SOSCreateError(kSOSErrorProcessingFailure, CFSTR("CCRandomCopyBytes failed"), NULL, error); | |
202 | return NULL; | |
203 | } | |
204 | ||
205 | CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0); | |
206 | CFDataSetLength(result, der_sizeof_pbkdf2_params(saltlen, salt, iterations, keysize)); | |
207 | ||
208 | uint8_t * encode = der_encode_pbkdf2_params(saltlen, salt, iterations, keysize, | |
209 | CFDataGetBytePtr(result), | |
210 | CFDataGetMutableBytePtr(result) + CFDataGetLength(result)); | |
211 | ||
212 | if (!encode) | |
213 | CFReleaseNull(result); | |
214 | ||
215 | if (result) { | |
216 | secnotice("keygen", "Created new parameters: iterations %zd, keysize %zd: %@", iterations, keysize, result); | |
217 | } | |
218 | ||
219 | return result; | |
220 | } | |
221 | ||
222 | SecKeyRef SOSUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *error) | |
223 | { | |
224 | size_t saltlen; | |
225 | const uint8_t *salt = NULL; | |
226 | ||
227 | size_t iterations = 0; | |
228 | size_t keysize = 0; | |
229 | ||
230 | const uint8_t *der = CFDataGetBytePtr(parameters); | |
231 | const uint8_t *der_end = der + CFDataGetLength(parameters); | |
232 | ||
233 | der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); | |
234 | ||
235 | if (der == NULL) { | |
236 | SOSCreateErrorWithFormat(kSOSErrorDecodeFailure, NULL, error, NULL, | |
237 | CFSTR("Bad paramter encoding, got: %@"), parameters); | |
238 | return NULL; | |
239 | } | |
240 | if (keysize != 256) { | |
241 | SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, | |
242 | CFSTR("Key size not supported, requested %zd."), keysize); | |
243 | return NULL; | |
244 | } | |
245 | if (saltlen < 4) { | |
246 | SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, | |
247 | CFSTR("Salt length not supported, requested %zd."), saltlen); | |
248 | return NULL; | |
249 | } | |
250 | if (iterations < ITERATIONMIN) { | |
251 | SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, | |
252 | CFSTR("Too few iterations, params suggested %zd."), iterations); | |
253 | return NULL; | |
254 | } | |
5c19dc3a A |
255 | |
256 | debugDumpUserParameters(CFSTR("params-keygen"), parameters); | |
257 | ||
427c49bc A |
258 | |
259 | const uint8_t *password_bytes = CFDataGetBytePtr(password); | |
260 | size_t password_length = CFDataGetLength(password); | |
261 | ||
262 | const size_t maxbytes = 128; | |
263 | ||
264 | ccec_const_cp_t cp = ccec_get_cp(keysize); | |
265 | struct ccrng_pbkdf2_prng_state pbkdf2_prng; | |
266 | ||
267 | ccec_full_ctx_decl_cp(cp, tmpkey); | |
268 | ||
269 | secnotice("keygen", "Generating key for: iterations %zd, keysize %zd: %@", iterations, keysize, parameters); | |
270 | ||
271 | if (ccrng_pbkdf2_prng_init(&pbkdf2_prng, maxbytes, | |
272 | password_length, password_bytes, | |
273 | saltlen, salt, | |
274 | iterations)) { | |
275 | SOSCreateError(kSOSErrorProcessingFailure, CFSTR("prng init failed"), NULL, error); | |
276 | return NULL; | |
277 | } | |
278 | ||
5c19dc3a | 279 | if (ccec_generate_key_legacy(cp, (struct ccrng_state *)&pbkdf2_prng, tmpkey)) { |
427c49bc A |
280 | SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error); |
281 | return NULL; | |
282 | } | |
283 | ||
427c49bc A |
284 | return ccec2SecKey(tmpkey); |
285 | } | |
286 | ||
287 | void debugDumpUserParameters(CFStringRef message, CFDataRef parameters) | |
288 | { | |
289 | size_t saltlen = 0; | |
290 | const uint8_t *salt = NULL; | |
291 | ||
292 | size_t iterations = 0; | |
293 | size_t keysize = 0; | |
294 | ||
295 | const uint8_t *der = CFDataGetBytePtr(parameters); | |
296 | const uint8_t *der_end = der + CFDataGetLength(parameters); | |
297 | ||
298 | der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); | |
299 | if (der == NULL) { | |
300 | secnotice("keygen", "failed to decode pbkdf2 params"); | |
301 | return; | |
302 | } | |
303 | ||
304 | BufferPerformWithHexString(salt, saltlen, ^(CFStringRef saltHex) { | |
305 | CFDataPerformWithHexString(parameters, ^(CFStringRef parametersHex) { | |
306 | secnotice("keygen", "%@ <Params: count: %zd, keysize: %zd, salt: %@, raw: %@>]", message, iterations, keysize, saltHex, parametersHex); | |
307 | }); | |
308 | }); | |
309 | } | |
310 | ||
5c19dc3a A |
311 | CF_RETURNS_RETAINED CFStringRef UserParametersDescription(CFDataRef parameters){ |
312 | ||
313 | __block CFStringRef description = NULL; | |
314 | CFErrorRef error = NULL; | |
315 | CFDataRef newParameters = NULL; | |
316 | SecKeyRef newKey = NULL; | |
317 | ||
318 | const uint8_t *parse_end = der_decode_cloud_parameters(kCFAllocatorDefault, kSecECDSAAlgorithmID, | |
319 | &newKey, &newParameters, &error, | |
320 | CFDataGetBytePtr(parameters), CFDataGetPastEndPtr(parameters)); | |
321 | ||
fa7225c8 | 322 | |
5c19dc3a | 323 | if (parse_end != CFDataGetPastEndPtr(parameters)){ |
fa7225c8 | 324 | secdebug("keygen", "failed to decode cloud parameters"); |
5c19dc3a A |
325 | return NULL; |
326 | } | |
327 | ||
328 | size_t saltlen = 0; | |
329 | const uint8_t *salt = NULL; | |
330 | ||
331 | size_t iterations = 0; | |
332 | size_t keysize = 0; | |
333 | ||
334 | const uint8_t *der = CFDataGetBytePtr(newParameters); | |
335 | const uint8_t *der_end = der + CFDataGetLength(newParameters); | |
336 | ||
337 | der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); | |
338 | if (der == NULL) { | |
fa7225c8 | 339 | secdebug("keygen", "failed to decode pbkdf2 params"); |
5c19dc3a A |
340 | return NULL; |
341 | } | |
342 | ||
fa7225c8 A |
343 | CFStringRef userPubKeyID = SOSCopyIDOfKeyWithLength(newKey, 8, NULL); |
344 | ||
345 | BufferPerformWithHexString(salt, 4, ^(CFStringRef saltHex) { // Only dump 4 bytes worth of salthex | |
5c19dc3a | 346 | CFDataPerformWithHexString(newParameters, ^(CFStringRef parametersHex) { |
fa7225c8 | 347 | description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Params: iter: %zd, size: %zd, salt: %@> <keyid: %@>"), iterations, keysize, saltHex, userPubKeyID); |
5c19dc3a A |
348 | }); |
349 | }); | |
350 | ||
fa7225c8 A |
351 | CFReleaseNull(newParameters); |
352 | CFReleaseNull(newKey); | |
353 | CFReleaseNull(userPubKeyID); | |
354 | ||
5c19dc3a A |
355 | return description; |
356 | } | |
427c49bc | 357 |