2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <SecureObjectSync/SOSUserKeygen.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 <CommonCrypto/CommonRandomSPI.h>
33 #include <Security/SecKey.h>
34 #include <Security/SecKeyPriv.h>
35 #include <Security/SecFramework.h>
36 #include <utilities/SecCFWrappers.h>
37 #include <utilities/SecCFRelease.h>
38 #include <utilities/debugging.h>
39 #include <SecureObjectSync/SOSCloudCircle.h>
40 #include <SecureObjectSync/SOSInternal.h>
41 #include <Security/SecFramework.h>
42 #include <Security/SecItem.h>
43 #include <utilities/der_plist.h>
44 #include <utilities/der_plist_internal.h>
46 #include <corecrypto/ccder.h>
47 #include <Security/oidsalg.h>
51 // The object identifier id-PBKDF2 identifies the PBKDF2 key derivation
52 // function (Section 5.2).
54 // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
56 // The parameters field associated with this OID in an
57 // AlgorithmIdentifier shall have type PBKDF2-params:
59 // PBKDF2-params ::= SEQUENCE {
61 // specified OCTET STRING,
62 // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
64 // iterationCount INTEGER (1..MAX),
65 // keyLength INTEGER (1..MAX) OPTIONAL,
66 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
67 // algid-hmacWithSHA1 }
69 // The fields of type PKDF2-params have the following meanings:
72 static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
)
74 return ccder_sizeof(CCDER_OBJECT_IDENTIFIER
, secasn_oid
->Length
);
77 static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
, const uint8_t *der
, uint8_t *der_end
)
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
));
83 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
, const uint8_t *der
, const uint8_t *der_end
)
86 der
= ccder_decode_tl(CCDER_OBJECT_IDENTIFIER
, &len
,
89 if (secasn_oid
->Length
!= len
|| memcmp(secasn_oid
->Data
, der
, len
) != 0)
97 static size_t der_sizeof_pbkdf2_params(size_t saltLen
, const uint8_t *salt
,
98 unsigned long iterationCount
,
99 unsigned long keyLength
)
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
);
106 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, body_size
);
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
)
114 uint8_t* original_der_end
= der_end
;
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
)))));
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
)
128 const uint8_t * body_end
= NULL
;
129 der
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &body_end
, der
, der_end
);
131 if (body_end
!= der_end
)
134 size_t salt_size
= 0;
135 const uint8_t *salt_bytes
= NULL
;
137 der
= ccder_decode_tl(CCDER_OCTET_STRING
, &salt_size
, der
, body_end
);
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
)
147 der
= ccder_decode_uint64(&key_len
, der
, body_end
);
148 if (key_len
> UINT32_MAX
)
151 der
= der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1
, der
, body_end
);
157 *saltLen
= salt_size
;
159 *iterationCount
= (unsigned long)iteration_count
;
161 *keyLength
= (unsigned long) key_len
;
168 static SecKeyRef
ccec2SecKey(ccec_full_ctx_t fk
)
170 size_t export_size
= ccec_x963_export_size(1, 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
);
175 CFDictionaryRef keyattributes
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
176 kSecValueData
, exportedkey
,
177 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
178 kSecAttrKeyClass
, kSecAttrKeyClassPrivate
,
181 SecKeyRef retval
= SecKeyCreateFromAttributeDictionary(keyattributes
);
183 CFRelease(keyattributes
);
184 CFRelease(exportedkey
);
185 bzero(export_keybytes
, 0);
190 #define ITERATIONMIN 50000
192 CFDataRef
SOSUserKeyCreateGenerateParameters(CFErrorRef
*error
) {
193 size_t saltlen
= SALTMAX
;
194 uint8_t salt
[saltlen
];
196 size_t iterations
= ITERATIONMIN
;
197 size_t keysize
= 256;
199 if(CCRandomCopyBytes(kCCRandomDefault
, salt
, sizeof(salt
)) != kCCSuccess
) {
200 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("CCRandomCopyBytes failed"), NULL
, error
);
204 CFMutableDataRef result
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
205 CFDataSetLength(result
, der_sizeof_pbkdf2_params(saltlen
, salt
, iterations
, keysize
));
207 uint8_t * encode
= der_encode_pbkdf2_params(saltlen
, salt
, iterations
, keysize
,
208 CFDataGetBytePtr(result
),
209 CFDataGetMutableBytePtr(result
) + CFDataGetLength(result
));
212 CFReleaseNull(result
);
215 secnotice("keygen", "Created new parameters: iterations %zd, keysize %zd: %@", iterations
, keysize
, result
);
221 SecKeyRef
SOSUserKeygen(CFDataRef password
, CFDataRef parameters
, CFErrorRef
*error
)
224 const uint8_t *salt
= NULL
;
226 size_t iterations
= 0;
229 const uint8_t *der
= CFDataGetBytePtr(parameters
);
230 const uint8_t *der_end
= der
+ CFDataGetLength(parameters
);
232 der
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
);
235 SOSCreateErrorWithFormat(kSOSErrorDecodeFailure
, NULL
, error
, NULL
,
236 CFSTR("Bad paramter encoding, got: %@"), parameters
);
239 if (keysize
!= 256) {
240 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
241 CFSTR("Key size not supported, requested %zd."), keysize
);
245 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
246 CFSTR("Salt length not supported, requested %zd."), saltlen
);
249 if (iterations
< ITERATIONMIN
) {
250 SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
,
251 CFSTR("Too few iterations, params suggested %zd."), iterations
);
255 const uint8_t *password_bytes
= CFDataGetBytePtr(password
);
256 size_t password_length
= CFDataGetLength(password
);
258 const size_t maxbytes
= 128;
260 ccec_const_cp_t cp
= ccec_get_cp(keysize
);
261 struct ccrng_pbkdf2_prng_state pbkdf2_prng
;
263 ccec_full_ctx_decl_cp(cp
, tmpkey
);
265 secnotice("keygen", "Generating key for: iterations %zd, keysize %zd: %@", iterations
, keysize
, parameters
);
267 if (ccrng_pbkdf2_prng_init(&pbkdf2_prng
, maxbytes
,
268 password_length
, password_bytes
,
271 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("prng init failed"), NULL
, error
);
275 if (ccec_generate_key(cp
, (struct ccrng_state
*)&pbkdf2_prng
, tmpkey
)) {
276 SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("Keygen failed"), NULL
, error
);
281 return ccec2SecKey(tmpkey
);
284 void debugDumpUserParameters(CFStringRef message
, CFDataRef parameters
)
287 const uint8_t *salt
= NULL
;
289 size_t iterations
= 0;
292 const uint8_t *der
= CFDataGetBytePtr(parameters
);
293 const uint8_t *der_end
= der
+ CFDataGetLength(parameters
);
295 der
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
);
297 secnotice("keygen", "failed to decode pbkdf2 params");
301 BufferPerformWithHexString(salt
, saltlen
, ^(CFStringRef saltHex
) {
302 CFDataPerformWithHexString(parameters
, ^(CFStringRef parametersHex
) {
303 secnotice("keygen", "%@ <Params: count: %zd, keysize: %zd, salt: %@, raw: %@>]", message
, iterations
, keysize
, saltHex
, parametersHex
);