]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSUserKeygen.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSUserKeygen.m
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
24
25 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
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 <Security/SecKey.h>
33 #include <Security/SecKeyPriv.h>
34 #include <Security/SecFramework.h>
35 #include <utilities/SecCFWrappers.h>
36 #include <utilities/SecCFRelease.h>
37 #include <utilities/debugging.h>
38 #include <Security/SecureObjectSync/SOSCloudCircle.h>
39 #include "keychain/SecureObjectSync/SOSInternal.h"
40 #include "keychain/SecureObjectSync/SOSAccount.h"
41 #include <Security/SecFramework.h>
42 #include <Security/SecItem.h>
43 #include <utilities/der_plist.h>
44 #include <utilities/der_plist_internal.h>
45
46 #include <corecrypto/ccder.h>
47 #include <Security/oidsalg.h>
48
49 // A.2 PBKDF2
50 //
51 // The object identifier id-PBKDF2 identifies the PBKDF2 key derivation
52 // function (Section 5.2).
53 //
54 // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
55 //
56 // The parameters field associated with this OID in an
57 // AlgorithmIdentifier shall have type PBKDF2-params:
58 //
59 // PBKDF2-params ::= SEQUENCE {
60 // salt CHOICE {
61 // specified OCTET STRING,
62 // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
63 // },
64 // iterationCount INTEGER (1..MAX),
65 // keyLength INTEGER (1..MAX) OPTIONAL,
66 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
67 // algid-hmacWithSHA1 }
68 //
69 // The fields of type PKDF2-params have the following meanings:
70
71
72 static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid* secasn_oid)
73 {
74 return ccder_sizeof(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length);
75 }
76
77 static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, uint8_t *der_end)
78 {
79 return ccder_encode_tl(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length, der,
80 ccder_encode_body(secasn_oid->Length, secasn_oid->Data, der, der_end));
81 }
82
83 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, const uint8_t *der_end)
84 {
85 size_t len = 0;
86 der = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &len,
87 der, der_end);
88
89 if (secasn_oid->Length != len || memcmp(secasn_oid->Data, der, len) != 0)
90 der = NULL;
91 else
92 der += len;
93
94 return der;
95 }
96
97 static size_t der_sizeof_pbkdf2_params(size_t saltLen, const uint8_t *salt,
98 unsigned long iterationCount,
99 unsigned long keyLength)
100 {
101 size_t body_size = ccder_sizeof_raw_octet_string(saltLen)
102 + ccder_sizeof_uint64(iterationCount)
103 + ccder_sizeof_uint64(keyLength)
104 + der_sizeof_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1);
105
106 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size);
107 }
108
109 static uint8_t *der_encode_pbkdf2_params(size_t saltLen, const uint8_t *salt,
110 unsigned long iterationCount,
111 unsigned long keyLength,
112 const uint8_t *der, uint8_t *der_end)
113 {
114 uint8_t* original_der_end = der_end;
115
116 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der,
117 ccder_encode_raw_octet_string(saltLen, salt, der,
118 ccder_encode_uint64(iterationCount, der,
119 ccder_encode_uint64(keyLength, der,
120 der_encode_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, der_end)))));
121 }
122
123 static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen, const uint8_t **salt,
124 unsigned long *iterationCount,
125 unsigned long *keyLength,
126 const uint8_t *der, const uint8_t *der_end)
127 {
128 const uint8_t * body_end = NULL;
129 der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &body_end, der, der_end);
130
131 if (body_end != der_end)
132 der = NULL;
133
134 size_t salt_size = 0;
135 const uint8_t *salt_bytes = NULL;
136
137 der = ccder_decode_tl(CCDER_OCTET_STRING, &salt_size, der, body_end);
138 salt_bytes = der;
139 der += salt_size;
140
141 uint64_t iteration_count = 0;
142 uint64_t key_len = 0;
143 der = ccder_decode_uint64(&iteration_count, der, body_end);
144 if (iteration_count > UINT32_MAX)
145 der = NULL;
146
147 der = ccder_decode_uint64(&key_len, der, body_end);
148 if (key_len > UINT32_MAX)
149 der = NULL;
150
151 der = der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, body_end);
152
153 if (der) {
154 if (salt)
155 *salt = salt_bytes;
156 if (saltLen)
157 *saltLen = salt_size;
158 if (iterationCount)
159 *iterationCount = (unsigned long)iteration_count;
160 if (keyLength)
161 *keyLength = (unsigned long) key_len;
162 }
163
164 return der;
165 }
166
167
168 static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk)
169 {
170 size_t export_size = ccec_x963_export_size(1, ccec_ctx_pub(fk));
171 uint8_t export_keybytes[export_size];
172 ccec_x963_export(1, export_keybytes, fk);
173 CFDataRef exportedkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, export_keybytes, export_size, kCFAllocatorNull);
174
175 CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
176 kSecValueData, exportedkey,
177 kSecAttrKeyType, kSecAttrKeyTypeEC,
178 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
179 NULL);
180
181 SecKeyRef retval = SecKeyCreateFromAttributeDictionary(keyattributes);
182
183 CFRelease(keyattributes);
184 CFRelease(exportedkey);
185 cc_clear(export_size, export_keybytes);
186 return retval;
187 }
188
189 #define SALTMAX 16
190 #define ITERATIONMIN 50000
191
192 CFDataRef SOSUserKeyCreateGenerateParameters(CFErrorRef *error) {
193 size_t saltlen = SALTMAX;
194 uint8_t salt[saltlen];
195
196 size_t iterations = ITERATIONMIN;
197 size_t keysize = 256;
198
199 if (SecRandomCopyBytes(NULL, sizeof(salt), salt) != 0) {
200 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("SecRandomCopyBytes failed"), NULL, error);
201 return NULL;
202 }
203
204 CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0);
205 CFDataSetLength(result, der_sizeof_pbkdf2_params(saltlen, salt, iterations, keysize));
206
207 uint8_t * encode = der_encode_pbkdf2_params(saltlen, salt, iterations, keysize,
208 CFDataGetBytePtr(result),
209 CFDataGetMutableBytePtr(result) + CFDataGetLength(result));
210
211 if (!encode)
212 CFReleaseNull(result);
213
214 if (result) {
215 debugDumpUserParameters(CFSTR("SOSUserKeyCreateGenerateParameters created new parameters:"), result);
216 }
217
218 return result;
219 }
220
221 SecKeyRef SOSUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *error)
222 {
223 size_t saltlen;
224 const uint8_t *salt = NULL;
225
226 size_t iterations = 0;
227 size_t keysize = 0;
228
229 const uint8_t *der = CFDataGetBytePtr(parameters);
230 const uint8_t *der_end = der + CFDataGetLength(parameters);
231
232 der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end);
233
234 if (der == NULL) {
235 SOSCreateErrorWithFormat(kSOSErrorDecodeFailure, NULL, error, NULL,
236 CFSTR("Bad paramter encoding, got: %@"), parameters);
237 return NULL;
238 }
239 if (keysize != 256) {
240 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
241 CFSTR("Key size not supported, requested %zd."), keysize);
242 return NULL;
243 }
244 if (saltlen < 4) {
245 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
246 CFSTR("Salt length not supported, requested %zd."), saltlen);
247 return NULL;
248 }
249 if (iterations < ITERATIONMIN) {
250 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
251 CFSTR("Too few iterations, params suggested %zd."), iterations);
252 return NULL;
253 }
254
255 const uint8_t *password_bytes = CFDataGetBytePtr(password);
256 size_t password_length = CFDataGetLength(password);
257
258 ccec_const_cp_t cp = ccec_get_cp(keysize);
259 ccec_full_ctx_decl_cp(cp, tmpkey);
260
261 debugDumpUserParameters(CFSTR("SOSUserKeygen generating key for:"), parameters);
262
263 size_t drbg_output_size=128;
264 uint8_t drbg_output[drbg_output_size];
265 ccpbkdf2_hmac(ccsha256_di(), password_length, password_bytes,
266 saltlen, salt,
267 iterations,
268 drbg_output_size, drbg_output);
269
270 int rngError = 0;
271 int keyError = -1;
272 struct ccrng_state *rng = ccrng(&rngError);
273 if(rng) {
274 keyError=ccec_generate_key_deterministic(cp, drbg_output_size, drbg_output, rng, CCEC_GENKEY_DETERMINISTIC_LEGACY, tmpkey);
275 cc_clear(drbg_output_size, drbg_output);
276 }
277
278 if(!rng || keyError != 0) {
279 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error);
280 return NULL;
281 }
282
283 return ccec2SecKey(tmpkey);
284 }
285
286 void debugDumpUserParameters(CFStringRef message, CFDataRef parameters)
287 {
288 CFStringRef keyparm = UserParametersDescription(parameters);
289 if (keyparm == NULL) {
290 secnotice("circleOps", "failed to decode pbkdf2 params");
291 return;
292 }
293 secnotice("circleOps", "%@ %@]", message, keyparm);
294 CFReleaseNull(keyparm);
295 }
296
297 CF_RETURNS_RETAINED CFStringRef UserParametersDescription(CFDataRef parameters){
298
299 if(parameters == NULL) {
300 return NULL;
301 }
302 __block CFStringRef description = NULL;
303 size_t saltlen = 0;
304 const uint8_t *salt = NULL;
305 size_t iterations = 0;
306 size_t keysize = 0;
307
308 const uint8_t *der = CFDataGetBytePtr(parameters);
309 const uint8_t *der_end = der + CFDataGetLength(parameters);
310
311 der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end);
312 if (der != der_end) {
313 secdebug("circleOps", "failed to decode pbkdf2 params");
314 return NULL;
315 }
316
317 BufferPerformWithHexString(salt, 4, ^(CFStringRef saltHex) { // Only dump 4 bytes worth of salthex
318 description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Params: iter: %zd, size: %zd, salt: %@>"), iterations, keysize, saltHex);
319 });
320
321 return description;
322 }
323