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