5 // Created by Richard Murphy on 6/1/15.
10 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
12 * @APPLE_LICENSE_HEADER_START@
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
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.
29 * @APPLE_LICENSE_HEADER_END@
34 #include <Security/SecBase.h>
35 #include <Security/SecItem.h>
36 #include <Security/SecKey.h>
37 #include <Security/SecKeyPriv.h>
39 #include "keychain/SecureObjectSync/SOSInternal.h"
40 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
42 #include <utilities/SecCFWrappers.h>
44 #include <CoreFoundation/CoreFoundation.h>
48 #include "SOSCircle_regressions.h"
50 #include "SOSRegressionUtilities.h"
51 #include <corecrypto/ccrng.h>
52 #include <corecrypto/ccrng_pbkdf2_prng.h>
53 #include <corecrypto/ccec.h>
54 #include <corecrypto/ccdigest.h>
55 #include <corecrypto/ccsha2.h>
56 #include <corecrypto/ccder.h>
57 #include <Security/oidsalg.h>
72 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
, const uint8_t *der
, const uint8_t *der_end
)
75 der
= ccder_decode_tl(CCDER_OBJECT_IDENTIFIER
, &len
,
78 if (secasn_oid
->Length
!= len
|| memcmp(secasn_oid
->Data
, der
, len
) != 0)
87 static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen
, const uint8_t **salt
,
88 unsigned long *iterationCount
,
89 unsigned long *keyLength
,
90 const uint8_t *der
, const uint8_t *der_end
)
92 const uint8_t * body_end
= NULL
;
93 der
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &body_end
, der
, der_end
);
95 if (body_end
!= der_end
)
99 const uint8_t *salt_bytes
= NULL
;
101 der
= ccder_decode_tl(CCDER_OCTET_STRING
, &salt_size
, der
, body_end
);
105 uint64_t iteration_count
= 0;
106 uint64_t key_len
= 0;
107 der
= ccder_decode_uint64(&iteration_count
, der
, body_end
);
108 if (iteration_count
> UINT32_MAX
)
111 der
= ccder_decode_uint64(&key_len
, der
, body_end
);
112 if (key_len
> UINT32_MAX
)
115 der
= der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1
, der
, body_end
);
121 *saltLen
= salt_size
;
123 *iterationCount
= (unsigned long)iteration_count
;
125 *keyLength
= (unsigned long) key_len
;
131 #define ITERATIONMIN 50000
133 static SecKeyRef
ccec2SecKey(ccec_full_ctx_t fk
)
135 size_t export_size
= ccec_x963_export_size(1, ccec_ctx_pub(fk
));
136 uint8_t export_keybytes
[export_size
];
137 ccec_x963_export(1, export_keybytes
, fk
);
138 CFDataRef exportedkey
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, export_keybytes
, export_size
, kCFAllocatorNull
);
140 CFDictionaryRef keyattributes
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
141 kSecValueData
, exportedkey
,
142 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
143 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
146 SecKeyRef retval
= SecKeyCreateFromAttributeDictionary(keyattributes
);
148 CFRelease(keyattributes
);
149 CFRelease(exportedkey
);
150 cc_clear(export_size
, export_keybytes
);
154 static SecKeyRef
SOSOldUserKeygen(CFDataRef password
, CFDataRef parameters
, CFErrorRef
*error
)
157 const uint8_t *salt
= NULL
;
159 size_t iterations
= 0;
162 const uint8_t *der
= CFDataGetBytePtr(parameters
);
163 const uint8_t *der_end
= der
+ CFDataGetLength(parameters
);
165 der
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
);
168 SOSCreateErrorWithFormat(kSOSErrorDecodeFailure
, NULL
, error
, NULL
,
169 CFSTR("Bad paramter encoding, got: %@"), parameters
);
172 if (keysize
!= 256) {
173 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
174 CFSTR("Key size not supported, requested %zd."), keysize
);
178 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
179 CFSTR("Salt length not supported, requested %zd."), saltlen
);
182 if (iterations
< ITERATIONMIN
) {
183 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
184 CFSTR("Too few iterations, params suggested %zd."), iterations
);
188 debugDumpUserParameters(CFSTR("params-keygen"), parameters
);
191 const uint8_t *password_bytes
= CFDataGetBytePtr(password
);
192 size_t password_length
= CFDataGetLength(password
);
194 const size_t maxbytes
= 128;
196 ccec_const_cp_t cp
= ccec_get_cp(keysize
);
197 struct ccrng_pbkdf2_prng_state pbkdf2_prng
;
199 ccec_full_ctx_decl_cp(cp
, tmpkey
);
201 secnotice("circleOps", "Generating key for: iterations %zd, keysize %zd: %@", iterations
, keysize
, parameters
);
203 if (ccrng_pbkdf2_prng_init(&pbkdf2_prng
, maxbytes
,
204 password_length
, password_bytes
,
207 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("prng init failed"), NULL
, error
);
211 if (ccec_generate_key_legacy(cp
, (struct ccrng_state
*)&pbkdf2_prng
, tmpkey
)) {
212 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("Keygen failed"), NULL
, error
);
216 return ccec2SecKey(tmpkey
);
220 static SecKeyRef
createOldTestKey(CFDataRef cfpassword
, CFDataRef parameters
, CFErrorRef
*error
) {
221 SecKeyRef user_privkey
= SOSOldUserKeygen(cfpassword
, parameters
, error
);
222 ok(user_privkey
, "No key!");
223 ok(*error
== NULL
, "Error: (%@)", *error
);
224 CFReleaseNull(*error
);
228 #endif /* TESTCOMPAT */
230 static SecKeyRef
createTestKey(CFDataRef cfpassword
, CFDataRef parameters
, CFErrorRef
*error
) {
231 SecKeyRef user_privkey
= SOSUserKeygen(cfpassword
, parameters
, error
);
232 ok(user_privkey
, "No key!");
233 ok(*error
== NULL
, "Error: (%@)", *error
);
234 CFReleaseNull(*error
);
238 static void tests(void) {
239 CFErrorRef error
= NULL
;
240 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
242 for(int j
=0; j
< NPARMS
; j
++) {
243 CFDataRef parameters
= SOSUserKeyCreateGenerateParameters(&error
);
244 ok(parameters
, "No parameters!");
245 ok(error
== NULL
, "Error: (%@)", error
);
246 CFReleaseNull(error
);
248 SecKeyRef baseline_privkey
= createTestKey(cfpassword
, parameters
, &error
);
249 ok(baseline_privkey
!= NULL
, "Failed to create baseline privkey");
250 if(baseline_privkey
) {
251 SecKeyRef baseline_pubkey
= SecKeyCreatePublicFromPrivate(baseline_privkey
);
253 for(int i
= 0; i
< NKEYS
; i
++) {
254 SecKeyRef user_privkey
= createTestKey(cfpassword
, parameters
, &error
);
255 SecKeyRef user_pubkey
= SecKeyCreatePublicFromPrivate(user_privkey
);
256 ok(CFEqualSafe(baseline_privkey
, user_privkey
), "Private Keys Don't Match");
257 ok(CFEqualSafe(baseline_pubkey
, user_pubkey
), "Public Keys Don't Match");
259 SecKeyRef old_privkey
= createOldTestKey(cfpassword
, parameters
, &error
);
260 SecKeyRef old_pubkey
= SecKeyCreatePublicFromPrivate(old_privkey
);
261 ok(CFEqualSafe(old_privkey
, user_privkey
), "Old/New Private Keys Don't Match");
262 ok(CFEqualSafe(old_pubkey
, user_pubkey
), "Old/New Public Keys Don't Match");
263 CFReleaseNull(old_privkey
);
264 CFReleaseNull(old_pubkey
);
265 #endif /* TESTCOMPAT */
266 CFReleaseNull(error
);
267 CFReleaseNull(user_privkey
);
268 CFReleaseNull(user_pubkey
);
270 CFReleaseNull(baseline_pubkey
);
272 CFReleaseNull(baseline_privkey
);
273 CFReleaseNull(parameters
);
275 CFReleaseNull(cfpassword
);
278 int sc_25_soskeygen(int argc
, char *const *argv
)
281 plan_tests(NKEYS
*(4+NPARMS
*4));