1/*
2 * Copyright (c) 2007-2009,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 <TargetConditionals.h>
26#include <CoreFoundation/CoreFoundation.h>
27#include <Security/Security.h>
28#include <Security/SecRandom.h>
29#include <CommonCrypto/CommonDigest.h>
30#include <Security/SecKeyPriv.h>
31#include <Security/SecItem.h>
32
33#if 0
34#include <Security/SecCertificate.h>
35#include <Security/SecCertificateInternal.h>
36#include <Security/SecKey.h>
37#include <Security/SecItem.h>
38#include <Security/SecAsn1Types.h>
39#include <Security/oidsalg.h>
40#include <libDER/libDER.h>
41#include <stdlib.h>
42#include <unistd.h>
43#endif
44
45#include "keychain_regressions.h"
46#include "utilities/SecCFRelease.h"
47
48#if TARGET_OS_IPHONE
49static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
50    uint8_t dataToDigest[256];
51    size_t dataToDigestLen = sizeof(dataToDigest);
52    size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
53    uint8_t sig[sigLen];
54
55    DERItem oid;
56    oid.length = algId->algorithm.Length;
57    oid.data = algId->algorithm.Data;
58
59    /* Get the oid in decimal for display purposes. */
60    CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
61	char oidBuf[40];
62    CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
63    CFRelease(oidStr);
64
65	SKIP: {
66        OSStatus status;
67
68        /* Time to sign. */
69        ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
70            sig, &sigLen), "digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
71
72        skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
73
74        /* Verify the signature we just made. */
75        ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
76            sig, sigLen), "digest and verify");
77        /* Invalidate the signature. */
78        sig[0] ^= 0xff;
79        is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
80            sig, sigLen), errSSLCrypto, "digest and verify bad sig");
81        sig[0] ^= 0xff;
82        dataToDigest[0] ^= 0xff;
83        is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
84            sig, sigLen), errSSLCrypto, "digest and verify bad digest");
85    }
86}
87
88static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
89    static const SecAsn1Oid *oids[] = {
90        &CSSMOID_SHA1WithRSA,
91        &CSSMOID_SHA224WithRSA,
92        &CSSMOID_SHA256WithRSA,
93        &CSSMOID_SHA384WithRSA,
94        &CSSMOID_SHA512WithRSA,
95#if 0
96        &CSSMOID_SHA1WithRSA_OIW,
97        &CSSMOID_SHA1WithDSA,		// BSAFE
98        &CSSMOID_SHA1WithDSA_CMS,	// X509/CMS
99        &CSSMOID_SHA1WithDSA_JDK,	// JDK 1.1
100#endif
101    };
102
103
104    uint32_t ix;
105    SecAsn1AlgId algId = {};
106    for (ix = 0; ix < sizeof(oids) / sizeof(*oids); ++ix) {
107        if (oids[ix]) {
108            algId.algorithm = *oids[ix];
109        } else {
110            algId.algorithm.Length = 0;
111            algId.algorithm.Data = NULL;
112        }
113
114        testdigestandsignalg(privKey, pubKey, &algId);
115    }
116}
117#endif
118
119#if 0
120static void dump_bytes(uint8_t* bytes, size_t amount)
121{
122    while (amount > 0) {
123        printf("0x%02x ", *bytes);
124        ++bytes;
125        --amount;
126    }
127}
128#endif
129
130
131#if !TARGET_OS_IPHONE
132#define kEncryptDecryptTestCount 0
133#else
134#define kEncryptDecryptTestCount 5
135static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t padding, size_t keySizeInBytes)
136{
137    SKIP: {
138        size_t max_len = keySizeInBytes;
139        switch (padding) {
140            case kSecPaddingNone: max_len = keySizeInBytes; break;
141            case kSecPaddingOAEP: max_len = keySizeInBytes - 2 - 2 * CC_SHA1_DIGEST_LENGTH; break;
142            case kSecPaddingPKCS1: max_len = keySizeInBytes - 11; break;
143            default: skip("what is the max_len for this padding?", 5, false);
144        }
145
146        uint8_t secret[max_len + 1], encrypted_secret[keySizeInBytes], decrypted_secret[keySizeInBytes];
147        uint8_t *secret_ptr = secret;
148        size_t secret_len = max_len;
149        size_t encrypted_secret_len = sizeof(encrypted_secret);
150        size_t decrypted_secret_len = sizeof(decrypted_secret);
151        memset(decrypted_secret, 0xff, decrypted_secret_len);
152        SecRandomCopyBytes(kSecRandomDefault, sizeof(secret), secret);
153
154        // zero pad, no accidental second zero byte
155        if (padding == kSecPaddingNone) {
156            secret[0] = 0;
157            secret[1] = 128;
158        }
159
160        is_status(SecKeyEncrypt(pubKey, padding,
161                                secret, sizeof(secret),
162                                encrypted_secret, &encrypted_secret_len), errSecParam, "encrypt secret (overflow)");
163        ok_status(SecKeyEncrypt(pubKey, padding,
164                                secret, secret_len,
165                                encrypted_secret, &encrypted_secret_len), "encrypt secret");
166
167        ok_status(SecKeyDecrypt(privKey, padding,
168                                encrypted_secret, encrypted_secret_len,
169                                decrypted_secret, &decrypted_secret_len), "decrypt secret");
170
171        // zero padding is removed on decode
172        if (padding == kSecPaddingNone) {
173            secret_len--;
174            secret_ptr++;
175        }
176
177        ok(decrypted_secret_len == secret_len, "correct length");
178        ok_status(memcmp(secret_ptr, decrypted_secret, secret_len), "verify secret");
179    }
180}
181#endif
182
183
184
185#if !TARGET_OS_IPHONE
186/* This is part of Security.framework on iOS */
187
188enum {
189    // kSecKeyKeySizeInBits        = 0, // already exists on osx
190    kSecKeySignatureSize        = 101,
191    kSecKeyEncryptedDataSize    = 102,
192    // More might belong here, but we aren't settled on how
193    // to take into account padding and/or digest types.
194};
195
196static
197size_t SecKeyGetSize(SecKeyRef key, int whichSize)
198{
199    size_t result = SecKeyGetBlockSize(key);
200
201    /* This is only RSA */
202    if (whichSize == kSecKeyKeySizeInBits)
203        result *= 8;
204
205    return result;
206}
207#endif
208
209#define kKeyGenTestCount (11 + (3*kEncryptDecryptTestCount))
210static void testkeygen(size_t keySizeInBits) {
211	SecKeyRef pubKey = NULL, privKey = NULL;
212	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
213	CFNumberRef kzib;
214
215	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
216	CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
217	CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
218	CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
219
220	OSStatus status;
221	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
222              "Generate %ld bit (%ld byte) RSA keypair", keySizeInBits,
223              keySizeInBytes);
224	CFRelease(kzib);
225	CFRelease(kgp);
226
227	SKIP: {
228        skip("keygen failed", 8, status == errSecSuccess);
229		ok(pubKey, "pubkey returned");
230		ok(privKey, "privKey returned");
231		is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
232		is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
233
234		/* Sign something. */
235		uint8_t something[keySizeInBytes];
236        size_t something_len = keySizeInBytes - 11;
237        SecRandomCopyBytes(kSecRandomDefault, sizeof(something), something);
238		uint8_t sig[keySizeInBytes];
239		size_t sigLen = sizeof(sig);
240#if TARGET_OS_IPHONE
241        /* TODO: This is returning another error on OS X */
242		is_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
243                                something, something_len + 1, sig, &sigLen),
244                                errSecParam, "sign overflow");
245#endif
246		ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
247			something, something_len, sig, &sigLen), "sign something");
248		ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
249			something, something_len, sig, sigLen), "verify sig on something");
250
251        // Torture test ASN.1 encoder by setting high bit to 1.
252        uint8_t digest[CC_SHA512_DIGEST_LENGTH] = {
253            0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
254            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
255            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
256            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
257            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
258            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
259            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
260            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
261        };
262#if TARGET_OS_IPHONE
263        /* Thoses tests are making sure that MD2 and MD5 are NOT supported,
264            but they still are on OS X */
265
266        //CC_MD2(something, sizeof(something), digest);
267		ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD2,
268			digest, CC_MD2_DIGEST_LENGTH, sig, &sigLen),
269                  "don't sign md2 digest");   //FAIL
270		ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD2,
271			digest, CC_MD2_DIGEST_LENGTH, sig, sigLen),
272                  "verify sig on md2 digest fails");  //FAIL
273
274        //CC_MD5(something, sizeof(something), digest);
275		sigLen = sizeof(sig);
276		ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD5,
277			digest, CC_MD5_DIGEST_LENGTH, sig, &sigLen),
278            "don't sign md5 digest"); //FAIL
279		ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD5,
280			digest, CC_MD5_DIGEST_LENGTH, sig, sigLen),
281            "verify sig on md5 digest fails"); //FAIL
282#endif
283
284        //CCDigest(kCCDigestSHA1, something, sizeof(something), digest);
285		sigLen = sizeof(sig);
286		ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA1,
287			digest, CC_SHA1_DIGEST_LENGTH, sig, &sigLen),
288            "sign sha1 digest");
289		ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA1,
290			digest, CC_SHA1_DIGEST_LENGTH, sig, sigLen),
291            "verify sig on sha1 digest");
292
293#if TARGET_OS_IPHONE
294        /* The assumptions in these tests are just wrong on OS X */
295		uint8_t signature[keySizeInBytes], *ptr = signature;
296		size_t signature_len = sizeof(signature);
297		ok_status(SecKeyEncrypt(pubKey, kSecPaddingNone, sig, sigLen, signature, &signature_len), "inspect signature");
298		is(signature_len, keySizeInBytes - 1, "got signature");  // FAIL for 2056
299		while(*ptr && ((size_t)(ptr - signature) < signature_len)) ptr++;
300		is(signature + signature_len - ptr, 16 /* length(\0 || OID_SHA1) */ + CC_SHA1_DIGEST_LENGTH, "successful decode");
301#endif
302
303#if TARGET_OS_IPHONE
304        /* Those are not supported on OS X */
305        /* PKCS1 padding is 00 01 PAD * 8 or more 00 data.
306           data is SEQ { SEQ { OID NULL } BIT STRING 00 DIGEST }
307           So min data + pad overhead is 11 + 9 + oidlen
308           oidlen = 11 for the sha2 family of oids, so we have 29 bytes; or
309           232 bits of minimum overhead.  */
310        const size_t pkcs1Overhead = 232;
311        if (keySizeInBits > 224 + pkcs1Overhead) {
312            //CC_SHA224(something, sizeof(something), digest);
313            sigLen = sizeof(sig);
314            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA224,
315                                    digest, CC_SHA224_DIGEST_LENGTH, sig, &sigLen),
316                      "sign sha224 digest");
317            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA224,
318                                      digest, CC_SHA224_DIGEST_LENGTH, sig, sigLen),
319                      "verify sig on sha224 digest");
320        }
321
322        if (keySizeInBits > 256 + pkcs1Overhead) {
323            //CC_SHA256(something, sizeof(something), digest);
324            sigLen = sizeof(sig);
325            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA256,
326                                    digest, CC_SHA256_DIGEST_LENGTH, sig, &sigLen),
327                      "sign sha256 digest");
328            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA256,
329                                      digest, CC_SHA256_DIGEST_LENGTH, sig, sigLen),
330                      "verify sig on sha256 digest");
331        }
332
333        if (keySizeInBits > 384 + pkcs1Overhead) {
334            //CC_SHA384(something, sizeof(something), digest);
335            sigLen = sizeof(sig);
336            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA384,
337                                    digest, CC_SHA384_DIGEST_LENGTH, sig, &sigLen),
338                      "sign sha384 digest");
339            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA384,
340                                      digest, CC_SHA384_DIGEST_LENGTH, sig, sigLen),
341                      "verify sig on sha384 digest");
342        }
343
344        if (keySizeInBits > 512 + pkcs1Overhead) {
345            //CC_SHA512(something, sizeof(something), digest);
346            sigLen = sizeof(sig);
347            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA512,
348                                    digest, CC_SHA512_DIGEST_LENGTH, sig, &sigLen),
349                      "sign sha512 digest");
350            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA512,
351                                      digest, CC_SHA512_DIGEST_LENGTH, sig, sigLen),
352                      "verify sig on sha512 digest");
353        }
354
355        test_encrypt_decrypt(pubKey, privKey, kSecPaddingNone, keySizeInBytes);
356        test_encrypt_decrypt(pubKey, privKey, kSecPaddingPKCS1, keySizeInBytes);
357        test_encrypt_decrypt(pubKey, privKey, kSecPaddingOAEP, keySizeInBytes);
358
359        testdigestandsign(privKey, pubKey);
360#endif
361
362		const void *privkeys[] = {
363			kSecValueRef
364		};
365		const void *privvalues[] = {
366			privKey
367		};
368		CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
369		sizeof(privkeys) / sizeof(*privkeys), NULL, NULL);
370#if TARGET_OS_IPHONE
371        /* OS X: keys are always added to the keychain when generated */
372		ok_status(SecItemAdd(privitem, NULL), "add private key"); //FAIL
373#endif
374        ok_status(SecItemDelete(privitem), "delete private key");
375		CFReleaseNull(privitem);
376
377		const void *pubkeys[] = {
378			kSecValueRef
379		};
380		const void *pubvalues[] = {
381			pubKey
382		};
383		CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues,
384		sizeof(pubkeys) / sizeof(*pubkeys), NULL, NULL);
385#if TARGET_OS_IPHONE
386        /* OS X: keys are always added to the keychain when generated */
387		ok_status(SecItemAdd(pubitem, NULL), "add public key"); //FAIL
388#endif
389        ok_status(SecItemDelete(pubitem), "delete public key");
390		CFReleaseNull(pubitem);
391
392		/* Cleanup. */
393		CFReleaseNull(pubKey);
394		CFReleaseNull(privKey);
395	}
396}
397
398#define kKeyGen2TestCount 11
399static void testkeygen2(size_t keySizeInBits) {
400	SecKeyRef pubKey = NULL, privKey = NULL;
401	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
402	CFNumberRef kzib;
403
404    CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
405    CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
406    CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
407    CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
408
409    CFReleaseNull(ourUUID);
410    CFReleaseNull(uuidString);
411
412    CFStringAppend(publicName, CFSTR("-Public-40"));
413    CFStringAppend(privateName, CFSTR("-Private-40"));
414	CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
415	CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
416
417	CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
418	CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
419
420	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keySizeInBits);
421	CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
422	CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
423	CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
424	CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
425	CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
426	CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
427
428	OSStatus status;
429	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
430              "Generate %ld bit (%ld byte) persistent RSA keypair",
431              keySizeInBits, keySizeInBytes);
432	CFRelease(kzib);
433	CFRelease(kgp);
434
435	SKIP: {
436        skip("keygen failed", 8, status == errSecSuccess);
437		ok(pubKey, "pubkey returned");
438		ok(privKey, "privKey returned");
439		is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
440		is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
441
442		SecKeyRef pubKey2, privKey2;
443		CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
444		CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
445		CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
446		CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
447        CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
448		ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
449			"retrieve pub key by label");
450		ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
451			"retrieve priv key by label and kSecAttrCanSign");
452
453		/* Sign something. */
454		uint8_t something[50] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
455		uint8_t sig[keySizeInBytes];
456		size_t sigLen = keySizeInBytes;
457		ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
458			something, sizeof(something), sig, &sigLen), "sign something");
459		ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
460			something, sizeof(something), sig, sigLen), "verify sig on something");
461
462#if TARGET_OS_IPHONE
463        /* SecKeyEncrypt does not return errSecParam on OS X in that case */
464        sigLen = keySizeInBytes;
465		is_status(SecKeyEncrypt(pubKey2, kSecPaddingPKCS1SHA1,
466			something, sizeof(something), sig, &sigLen), errSecParam,
467            "encrypt something with invalid padding");
468#endif
469
470		/* Cleanup. */
471		CFReleaseNull(pubKey2);
472		CFReleaseNull(privKey2);
473
474        /* delete from keychain - note: do it before releasing publicName and privateName
475         because pubd and privd have no retain/release callbacks */
476        ok_status(SecItemDelete(pubd), "delete generated pub key");
477        ok_status(SecItemDelete(privd), "delete generated priv key");
478	}
479
480	/* Cleanup. */
481	CFReleaseNull(pubKey);
482	CFReleaseNull(privKey);
483
484    CFReleaseNull(publicName);
485    CFReleaseNull(privateName);
486
487	CFRelease(pubd);
488	CFRelease(privd);
489}
490
491
492#if !TARGET_OS_IPHONE
493// Only exists currently in MacOSX
494typedef struct KDFVector_t {
495    char *password;
496    char *salt;
497    int rounds;
498    int alg;
499    int dklen;
500    char *expectedstr;
501    int expected_failure;
502} KDFVector;
503
504static KDFVector kdfv[] = {
505    // Test Case PBKDF2 - HMACSHA1 http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-00
506    { "password", "salt", 1, 1, 160, "0c60c80f961f0e71f3a9b524af6012062fe037a6", 0 },
507    { "password", "salt", 2, 1, 160, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957", 0 },
508    { "password", "salt", 4096, 1, 160, "4b007901b765489abead49d926f721d065a429c1", 0 },
509    { "password", "salt", 1, 0, 160, NULL, -1} // This crashed
510};
511
512static size_t kdfvLen = sizeof(kdfv) / sizeof(KDFVector);
513
514static int testSecKDF(CFStringRef password, CFDataRef salt, CFNumberRef rounds, CFDataRef alg, CFNumberRef dklen, CFDataRef expected, int expected_failure) {
515    CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
516    int retval = 0;
517
518    CFDictionaryAddValue(parameters, kSecAttrSalt, salt);
519    CFDictionaryAddValue(parameters, kSecAttrKeySizeInBits, dklen);
520    CFDictionaryAddValue(parameters, kSecAttrPRF, alg);
521    CFDictionaryAddValue(parameters, kSecAttrRounds, rounds);
522
523    SecKeyRef derivedKey = SecKeyDeriveFromPassword(password, parameters, NULL);
524    if(derivedKey == NULL && expected_failure) {
525        ok(1, "Correctly failed to produce a key");
526        goto errOut;
527    } else if(derivedKey == NULL) {
528        ok(0, "Could not generate a key when we should have");
529        goto errOut;
530    }
531    ok(1, "Made a new key");
532    retval = 1;
533    // NEEDS Fix -- ok(status = expectedEqualsComputed(expected, derivedKey), "Derived key is as expected");
534errOut:
535    if(parameters) CFRelease(parameters);
536    if(derivedKey) CFRelease(derivedKey);
537    return retval;
538}
539
540static CFDataRef CFDataCreateFromHexBytes(char *s) {
541    if(!s) return NULL;
542    size_t len = strlen(s);
543    if(len%2) return NULL;
544    len /= 2;
545    uint8_t buf[len];
546    for(size_t i=0; i<len; i++) {
547        buf[i] = s[i*2] * 16 + s[i*2+1];
548    }
549    CFDataRef retval = CFDataCreate(NULL, buf, len);
550    return retval;
551}
552
553
554static int
555PBKDF2Test(KDFVector *kdfvec)
556{
557    CFDataRef expectedBytes = CFDataCreateFromHexBytes(kdfvec->expectedstr);
558    CFStringRef password = CFStringCreateWithCString(NULL, kdfvec->password, kCFStringEncodingUTF8);
559    CFDataRef salt = CFDataCreate(NULL, (const UInt8 *)kdfvec->salt, strlen(kdfvec->salt));
560    CFNumberRef rounds = CFNumberCreate(NULL, kCFNumberIntType, &kdfvec->rounds);
561    CFNumberRef dklen = CFNumberCreate(NULL, kCFNumberIntType, &kdfvec->dklen);
562    int status = 1;
563
564    ok(testSecKDF(password, salt, rounds, kSecAttrPRFHmacAlgSHA1, dklen, expectedBytes, kdfvec->expected_failure), "Test SecKeyDeriveFromPassword PBKDF2");
565
566    if(expectedBytes) CFRelease(expectedBytes);
567    return status;
568}
569
570
571static void testkeyderivation() {
572    for(size_t testcase = 0; testcase < kdfvLen; testcase++) {
573        // diag("Test %lu\n", testcase + 1);
574        ok(PBKDF2Test(&kdfv[testcase]), "Successful full test of KDF Vector");
575    }
576}
577
578#else
579static size_t kdfvLen = 0; // no kdf functions in Sec for iphone
580#endif /* !TARGET_OS_IPHONE */
581
582
583/* Test basic add delete update copy matching stuff. */
584#define kTestCount ((2 * kKeyGenTestCount) + kKeyGen2TestCount + (int) (kdfvLen*3))
585static void tests(void)
586{
587	/* Comment out lines below for testing generating all common key sizes,
588	   disabled now for speed reasons. */
589	//testkeygen(512);
590	//testkeygen(768);
591	testkeygen(1024);
592	testkeygen(2056); // Stranged sized for edge cases in padding.
593	//testkeygen(2048);
594	//testkeygen(4096);
595
596    testkeygen2(1024); // lots of FAIL!
597#if !TARGET_OS_IPHONE
598    testkeyderivation();
599#endif
600}
601
602int kc_40_seckey(int argc, char *const *argv)
603{
604	plan_tests(kTestCount);
605
606	tests();
607
608	return 0;
609}
610