]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/Regressions/sc-25-soskeygen.c
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / SecureObjectSync / Regressions / sc-25-soskeygen.c
1 //
2 // sc-25-soskeygen.c
3 // sec
4 //
5 // Created by Richard Murphy on 6/1/15.
6 //
7 //
8
9 /*
10 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
11 *
12 * @APPLE_LICENSE_HEADER_START@
13 *
14 * This file contains Original Code and/or Modifications of Original Code
15 * as defined in and that are subject to the Apple Public Source License
16 * Version 2.0 (the 'License'). You may not use this file except in
17 * compliance with the License. Please obtain a copy of the License at
18 * http://www.opensource.apple.com/apsl/ and read it before using this
19 * file.
20 *
21 * The Original Code and all software distributed under the License are
22 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
23 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
24 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
26 * Please see the License for the specific language governing rights and
27 * limitations under the License.
28 *
29 * @APPLE_LICENSE_HEADER_END@
30 */
31
32
33
34 #include <Security/SecBase.h>
35 #include <Security/SecItem.h>
36 #include <Security/SecKey.h>
37 #include <Security/SecKeyPriv.h>
38
39 #include "keychain/SecureObjectSync/SOSInternal.h"
40 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
41
42 #include <utilities/SecCFWrappers.h>
43
44 #include <CoreFoundation/CoreFoundation.h>
45
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include "SOSCircle_regressions.h"
49
50 #include "SOSRegressionUtilities.h"
51
52 #if SOS_ENABLED
53
54 #include <corecrypto/ccrng.h>
55 #include <corecrypto/ccrng_pbkdf2_prng.h>
56 #include <corecrypto/ccec.h>
57 #include <corecrypto/ccdigest.h>
58 #include <corecrypto/ccsha2.h>
59 #include <corecrypto/ccder.h>
60 #include <Security/oidsalg.h>
61
62
63 #if TARGET_OS_WATCH
64 #define NPARMS 3
65 #define NKEYS 3
66 #else
67 #define NPARMS 10
68 #define NKEYS 10
69 #endif
70
71
72 #define TESTCOMPAT 1
73 #if TESTCOMPAT == 1
74
75 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, const uint8_t *der_end)
76 {
77 size_t len = 0;
78 der = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &len,
79 der, der_end);
80
81 if (secasn_oid->Length != len || memcmp(secasn_oid->Data, der, len) != 0)
82 der = NULL;
83 else
84 der += len;
85
86 return der;
87 }
88
89
90 static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen, const uint8_t **salt,
91 unsigned long *iterationCount,
92 unsigned long *keyLength,
93 const uint8_t *der, const uint8_t *der_end)
94 {
95 const uint8_t * body_end = NULL;
96 der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &body_end, der, der_end);
97
98 if (body_end != der_end)
99 der = NULL;
100
101 size_t salt_size = 0;
102 const uint8_t *salt_bytes = NULL;
103
104 der = ccder_decode_tl(CCDER_OCTET_STRING, &salt_size, der, body_end);
105 salt_bytes = der;
106 der += salt_size;
107
108 uint64_t iteration_count = 0;
109 uint64_t key_len = 0;
110 der = ccder_decode_uint64(&iteration_count, der, body_end);
111 if (iteration_count > UINT32_MAX)
112 der = NULL;
113
114 der = ccder_decode_uint64(&key_len, der, body_end);
115 if (key_len > UINT32_MAX)
116 der = NULL;
117
118 der = der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, body_end);
119
120 if (der) {
121 if (salt)
122 *salt = salt_bytes;
123 if (saltLen)
124 *saltLen = salt_size;
125 if (iterationCount)
126 *iterationCount = (unsigned long)iteration_count;
127 if (keyLength)
128 *keyLength = (unsigned long) key_len;
129 }
130
131 return der;
132 }
133 #define SALTMAX 16
134 #define ITERATIONMIN 50000
135
136 static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk)
137 {
138 size_t export_size = ccec_x963_export_size(1, ccec_ctx_pub(fk));
139 uint8_t export_keybytes[export_size];
140 ccec_x963_export(1, export_keybytes, fk);
141 CFDataRef exportedkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, export_keybytes, export_size, kCFAllocatorNull);
142
143 CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
144 kSecValueData, exportedkey,
145 kSecAttrKeyType, kSecAttrKeyTypeEC,
146 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
147 NULL);
148
149 SecKeyRef retval = SecKeyCreateFromAttributeDictionary(keyattributes);
150
151 CFRelease(keyattributes);
152 CFRelease(exportedkey);
153 cc_clear(export_size, export_keybytes);
154 return retval;
155 }
156
157 static SecKeyRef SOSOldUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *error)
158 {
159 size_t saltlen;
160 const uint8_t *salt = NULL;
161
162 size_t iterations = 0;
163 size_t keysize = 0;
164
165 const uint8_t *der = CFDataGetBytePtr(parameters);
166 const uint8_t *der_end = der + CFDataGetLength(parameters);
167
168 der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end);
169
170 if (der == NULL) {
171 SOSCreateErrorWithFormat(kSOSErrorDecodeFailure, NULL, error, NULL,
172 CFSTR("Bad paramter encoding, got: %@"), parameters);
173 return NULL;
174 }
175 if (keysize != 256) {
176 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
177 CFSTR("Key size not supported, requested %zd."), keysize);
178 return NULL;
179 }
180 if (saltlen < 4) {
181 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
182 CFSTR("Salt length not supported, requested %zd."), saltlen);
183 return NULL;
184 }
185 if (iterations < ITERATIONMIN) {
186 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
187 CFSTR("Too few iterations, params suggested %zd."), iterations);
188 return NULL;
189 }
190
191
192
193 const uint8_t *password_bytes = CFDataGetBytePtr(password);
194 size_t password_length = CFDataGetLength(password);
195
196 const size_t maxbytes = 128;
197
198 ccec_const_cp_t cp = ccec_get_cp(keysize);
199 struct ccrng_pbkdf2_prng_state pbkdf2_prng;
200
201 ccec_full_ctx_decl_cp(cp, tmpkey);
202
203 debugDumpUserParameters(CFSTR("sc_25_soskeygen: Generating key for:"), parameters);
204
205 if (ccrng_pbkdf2_prng_init(&pbkdf2_prng, maxbytes,
206 password_length, password_bytes,
207 saltlen, salt,
208 iterations)) {
209 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("prng init failed"), NULL, error);
210 return NULL;
211 }
212
213 if (ccec_generate_key_legacy(cp, (struct ccrng_state *)&pbkdf2_prng, tmpkey)) {
214 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error);
215 return NULL;
216 }
217
218 return ccec2SecKey(tmpkey);
219 }
220
221
222 static SecKeyRef createOldTestKey(CFDataRef cfpassword, CFDataRef parameters, CFErrorRef *error) {
223 SecKeyRef user_privkey = SOSOldUserKeygen(cfpassword, parameters, error);
224 ok(user_privkey, "No key!");
225 ok(*error == NULL, "Error: (%@)", *error);
226 CFReleaseNull(*error);
227 return user_privkey;
228 }
229
230 #endif /* TESTCOMPAT */
231
232 static SecKeyRef createTestKey(CFDataRef cfpassword, CFDataRef parameters, CFErrorRef *error) {
233 SecKeyRef user_privkey = SOSUserKeygen(cfpassword, parameters, error);
234 ok(user_privkey, "No key!");
235 ok(*error == NULL, "Error: (%@)", *error);
236 CFReleaseNull(*error);
237 return user_privkey;
238 }
239
240 static void tests(void) {
241 CFErrorRef error = NULL;
242 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
243
244 for(int j=0; j < NPARMS; j++) {
245 CFDataRef parameters = SOSUserKeyCreateGenerateParameters(&error);
246 ok(parameters, "No parameters!");
247 ok(error == NULL, "Error: (%@)", error);
248 CFReleaseNull(error);
249
250 SecKeyRef baseline_privkey = createTestKey(cfpassword, parameters, &error);
251 ok(baseline_privkey != NULL, "Failed to create baseline privkey");
252 if(baseline_privkey) {
253 SecKeyRef baseline_pubkey = SecKeyCreatePublicFromPrivate(baseline_privkey);
254
255 for(int i = 0; i < NKEYS; i++) {
256 SecKeyRef user_privkey = createTestKey(cfpassword, parameters, &error);
257 SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey);
258 ok(CFEqualSafe(baseline_privkey, user_privkey), "Private Keys Don't Match");
259 ok(CFEqualSafe(baseline_pubkey, user_pubkey), "Public Keys Don't Match");
260 #if TESTCOMPAT == 1
261 SecKeyRef old_privkey = createOldTestKey(cfpassword, parameters, &error);
262 SecKeyRef old_pubkey = SecKeyCreatePublicFromPrivate(old_privkey);
263 ok(CFEqualSafe(old_privkey, user_privkey), "Old/New Private Keys Don't Match");
264 ok(CFEqualSafe(old_pubkey, user_pubkey), "Old/New Public Keys Don't Match");
265 CFReleaseNull(old_privkey);
266 CFReleaseNull(old_pubkey);
267 #endif /* TESTCOMPAT */
268 CFReleaseNull(error);
269 CFReleaseNull(user_privkey);
270 CFReleaseNull(user_pubkey);
271 }
272 CFReleaseNull(baseline_pubkey);
273 }
274 CFReleaseNull(baseline_privkey);
275 CFReleaseNull(parameters);
276 }
277 CFReleaseNull(cfpassword);
278 }
279
280 #endif
281
282 int sc_25_soskeygen(int argc, char *const *argv)
283 {
284 #if SOS_ENABLED
285 plan_tests(850);
286 tests();
287 #else
288 plan_tests(0);
289 #endif
290 return 0;
291 }