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