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"
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>
75 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
, const uint8_t *der
, const uint8_t *der_end
)
78 der
= ccder_decode_tl(CCDER_OBJECT_IDENTIFIER
, &len
,
81 if (secasn_oid
->Length
!= len
|| memcmp(secasn_oid
->Data
, der
, len
) != 0)
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
)
95 const uint8_t * body_end
= NULL
;
96 der
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &body_end
, der
, der_end
);
98 if (body_end
!= der_end
)
101 size_t salt_size
= 0;
102 const uint8_t *salt_bytes
= NULL
;
104 der
= ccder_decode_tl(CCDER_OCTET_STRING
, &salt_size
, der
, body_end
);
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
)
114 der
= ccder_decode_uint64(&key_len
, der
, body_end
);
115 if (key_len
> UINT32_MAX
)
118 der
= der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1
, der
, body_end
);
124 *saltLen
= salt_size
;
126 *iterationCount
= (unsigned long)iteration_count
;
128 *keyLength
= (unsigned long) key_len
;
134 #define ITERATIONMIN 50000
136 static SecKeyRef
ccec2SecKey(ccec_full_ctx_t fk
)
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
);
143 CFDictionaryRef keyattributes
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
144 kSecValueData
, exportedkey
,
145 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
146 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
149 SecKeyRef retval
= SecKeyCreateFromAttributeDictionary(keyattributes
);
151 CFRelease(keyattributes
);
152 CFRelease(exportedkey
);
153 cc_clear(export_size
, export_keybytes
);
157 static SecKeyRef
SOSOldUserKeygen(CFDataRef password
, CFDataRef parameters
, CFErrorRef
*error
)
160 const uint8_t *salt
= NULL
;
162 size_t iterations
= 0;
165 const uint8_t *der
= CFDataGetBytePtr(parameters
);
166 const uint8_t *der_end
= der
+ CFDataGetLength(parameters
);
168 der
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
);
171 SOSCreateErrorWithFormat(kSOSErrorDecodeFailure
, NULL
, error
, NULL
,
172 CFSTR("Bad paramter encoding, got: %@"), parameters
);
175 if (keysize
!= 256) {
176 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
177 CFSTR("Key size not supported, requested %zd."), keysize
);
181 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
182 CFSTR("Salt length not supported, requested %zd."), saltlen
);
185 if (iterations
< ITERATIONMIN
) {
186 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
187 CFSTR("Too few iterations, params suggested %zd."), iterations
);
193 const uint8_t *password_bytes
= CFDataGetBytePtr(password
);
194 size_t password_length
= CFDataGetLength(password
);
196 const size_t maxbytes
= 128;
198 ccec_const_cp_t cp
= ccec_get_cp(keysize
);
199 struct ccrng_pbkdf2_prng_state pbkdf2_prng
;
201 ccec_full_ctx_decl_cp(cp
, tmpkey
);
203 debugDumpUserParameters(CFSTR("sc_25_soskeygen: Generating key for:"), parameters
);
205 if (ccrng_pbkdf2_prng_init(&pbkdf2_prng
, maxbytes
,
206 password_length
, password_bytes
,
209 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("prng init failed"), NULL
, error
);
213 if (ccec_generate_key_legacy(cp
, (struct ccrng_state
*)&pbkdf2_prng
, tmpkey
)) {
214 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("Keygen failed"), NULL
, error
);
218 return ccec2SecKey(tmpkey
);
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
);
230 #endif /* TESTCOMPAT */
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
);
240 static void tests(void) {
241 CFErrorRef error
= NULL
;
242 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
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
);
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
);
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");
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
);
272 CFReleaseNull(baseline_pubkey
);
274 CFReleaseNull(baseline_privkey
);
275 CFReleaseNull(parameters
);
277 CFReleaseNull(cfpassword
);
282 int sc_25_soskeygen(int argc
, char *const *argv
)