1/*
2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include <SecureObjectSync/SOSUserKeygen.h>
26#include <stdio.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>
45
46#include <corecrypto/ccder.h>
47#include <Security/oidsalg.h>
48
49// A.2   PBKDF2
50//
51// The object identifier id-PBKDF2 identifies the PBKDF2 key derivation
52// function (Section 5.2).
53//
54// id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
55//
56// The parameters field associated with this OID in an
57// AlgorithmIdentifier shall have type PBKDF2-params:
58//
59// PBKDF2-params ::= SEQUENCE {
60//    salt CHOICE {
61//        specified OCTET STRING,
62//        otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
63//    },
64//    iterationCount INTEGER (1..MAX),
65//    keyLength INTEGER (1..MAX) OPTIONAL,
66//    prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
67//    algid-hmacWithSHA1 }
68//
69// The fields of type PKDF2-params have the following meanings:
70
71
72static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid* secasn_oid)
73{
74    return ccder_sizeof(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length);
75}
76
77static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, uint8_t *der_end)
78{
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));
81}
82
83static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, const uint8_t *der_end)
84{
85    size_t len = 0;
86    der = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &len,
87                                          der, der_end);
88
89    if (secasn_oid->Length != len || memcmp(secasn_oid->Data, der, len) != 0)
90        der = NULL;
91    else
92        der += len;
93
94    return der;
95}
96
97static size_t der_sizeof_pbkdf2_params(size_t saltLen, const uint8_t *salt,
98                                       unsigned long iterationCount,
99                                       unsigned long keyLength)
100{
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);
105
106    return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size);
107}
108
109static 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)
113{
114    uint8_t* original_der_end = der_end;
115
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)))));
121}
122
123static 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)
127{
128    const uint8_t * body_end = NULL;
129    der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &body_end, der, der_end);
130
131    if (body_end != der_end)
132        der = NULL;
133
134    size_t salt_size = 0;
135    const uint8_t *salt_bytes = NULL;
136
137    der = ccder_decode_tl(CCDER_OCTET_STRING, &salt_size, der, body_end);
138    salt_bytes = der;
139    der += salt_size;
140
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)
145        der = NULL;
146
147    der = ccder_decode_uint64(&key_len, der, body_end);
148    if (key_len > UINT32_MAX)
149        der = NULL;
150
151    der = der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, body_end);
152
153    if (der) {
154        if (salt)
155            *salt = salt_bytes;
156        if (saltLen)
157            *saltLen = salt_size;
158        if (iterationCount)
159            *iterationCount = (unsigned long)iteration_count;
160        if (keyLength)
161            *keyLength = (unsigned long) key_len;
162    }
163
164    return der;
165}
166
167
168static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk)
169{
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);
174
175    CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
176                                                                 kSecValueData, exportedkey,
177                                                                 kSecAttrKeyType, kSecAttrKeyTypeEC,
178                                                                 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
179                                                                 NULL);
180
181    SecKeyRef retval = SecKeyCreateFromAttributeDictionary(keyattributes);
182
183    CFRelease(keyattributes);
184    CFRelease(exportedkey);
185    bzero(export_keybytes, 0);
186    return retval;
187}
188
189#define SALTMAX 16
190#define ITERATIONMIN 50000
191
192CFDataRef SOSUserKeyCreateGenerateParameters(CFErrorRef *error) {
193    size_t saltlen = SALTMAX;
194    uint8_t salt[saltlen];
195
196    size_t iterations = ITERATIONMIN;
197    size_t keysize = 256;
198
199    if(CCRandomCopyBytes(kCCRandomDefault, salt, sizeof(salt)) != kCCSuccess) {
200        SOSCreateError(kSOSErrorProcessingFailure, CFSTR("CCRandomCopyBytes failed"), NULL, error);
201        return NULL;
202    }
203
204    CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0);
205    CFDataSetLength(result, der_sizeof_pbkdf2_params(saltlen, salt, iterations, keysize));
206
207    uint8_t * encode = der_encode_pbkdf2_params(saltlen, salt, iterations, keysize,
208                                                CFDataGetBytePtr(result),
209                                                CFDataGetMutableBytePtr(result) + CFDataGetLength(result));
210
211    if (!encode)
212        CFReleaseNull(result);
213
214    if (result) {
215        secnotice("keygen", "Created new parameters: iterations %zd, keysize %zd: %@", iterations, keysize, result);
216    }
217
218    return result;
219}
220
221SecKeyRef SOSUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *error)
222{
223    size_t saltlen;
224    const uint8_t *salt = NULL;
225
226    size_t iterations = 0;
227    size_t keysize = 0;
228
229    const uint8_t *der = CFDataGetBytePtr(parameters);
230    const uint8_t *der_end = der + CFDataGetLength(parameters);
231
232    der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end);
233
234    if (der == NULL) {
235        SOSCreateErrorWithFormat(kSOSErrorDecodeFailure, NULL, error, NULL,
236                                 CFSTR("Bad paramter encoding, got: %@"), parameters);
237        return NULL;
238    }
239    if (keysize != 256) {
240        SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
241                                 CFSTR("Key size not supported, requested %zd."), keysize);
242        return NULL;
243    }
244    if (saltlen < 4) {
245        SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
246                                 CFSTR("Salt length not supported, requested %zd."), saltlen);
247        return NULL;
248    }
249    if (iterations < ITERATIONMIN) {
250        SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL,
251                                 CFSTR("Too few iterations, params suggested %zd."), iterations);
252        return NULL;
253    }
254
255    const uint8_t *password_bytes = CFDataGetBytePtr(password);
256    size_t password_length = CFDataGetLength(password);
257
258    const size_t maxbytes = 128;
259
260    ccec_const_cp_t cp = ccec_get_cp(keysize);
261    struct ccrng_pbkdf2_prng_state pbkdf2_prng;
262
263    ccec_full_ctx_decl_cp(cp, tmpkey);
264
265    secnotice("keygen", "Generating key for: iterations %zd, keysize %zd: %@", iterations, keysize, parameters);
266
267    if (ccrng_pbkdf2_prng_init(&pbkdf2_prng, maxbytes,
268                                password_length, password_bytes,
269                                saltlen, salt,
270                                iterations)) {
271        SOSCreateError(kSOSErrorProcessingFailure, CFSTR("prng init failed"), NULL, error);
272        return NULL;
273    }
274
275    if (ccec_generate_key(cp, (struct ccrng_state *)&pbkdf2_prng, tmpkey)) {
276        SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error);
277        return NULL;
278    }
279
280
281    return ccec2SecKey(tmpkey);
282}
283
284void debugDumpUserParameters(CFStringRef message, CFDataRef parameters)
285{
286    size_t saltlen = 0;
287    const uint8_t *salt = NULL;
288
289    size_t iterations = 0;
290    size_t keysize = 0;
291
292    const uint8_t *der = CFDataGetBytePtr(parameters);
293    const uint8_t *der_end = der + CFDataGetLength(parameters);
294
295    der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end);
296    if (der == NULL) {
297        secnotice("keygen", "failed to decode pbkdf2 params");
298        return;
299    }
300
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);
304        });
305    });
306}
307
308
309