]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-40-seckey.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-40-seckey.c
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
49 static 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
88 static 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
120 static 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
135 static 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
188 enum {
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
196 static
197 size_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))
210 static 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
399 static 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
494 typedef 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
504 static 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
512 static size_t kdfvLen = sizeof(kdfv) / sizeof(KDFVector);
513
514 static int testSecKDF(CFStringRef password, CFDataRef salt, CFNumberRef rounds, CFStringRef 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");
534 errOut:
535 if(parameters) CFRelease(parameters);
536 if(derivedKey) CFRelease(derivedKey);
537 return retval;
538 }
539
540 static 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
554 static int
555 PBKDF2Test(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
571 static 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
579 static 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))
585 static 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
602 int kc_40_seckey(int argc, char *const *argv)
603 {
604 plan_tests(kTestCount);
605
606 tests();
607
608 return 0;
609 }