1/* 2 * Copyright (c) 2010 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 26#import "SecTransform.h" 27#import "SecCustomTransform.h" 28#import "SecDigestTransform.h" 29#import "SecEncryptTransform.h" 30#import "SecEncodeTransform.h" 31#import "SecDecodeTransform.h" 32#import "SecSignVerifyTransform.h" 33#import "SecNullTransform.h" 34#import "SecExternalSourceTransform.h" 35#import <Security/SecItem.h> 36#import "misc.h" 37#import "Utilities.h" 38#import "SecNullTransform.h" 39#include "regex.h" 40#include <dispatch/dispatch.h> 41#import "SecMaskGenerationFunctionTransform.h" 42#import "SecTransformInternal.h" 43#import "custom.h" 44#include "SecTransformReadTransform.h" 45#import "SecTransformValidator.h" 46#include <sys/types.h> 47#include <sys/sysctl.h> 48#include <ctype.h> 49#include <string.h> 50#include <stdlib.h> 51#include <stdio.h> 52#include <CommonCrypto/CommonCryptor.h> 53#include <sys/stat.h> 54#import "NSData+HexString.h" 55#include <CoreFoundation/CFBase.h> 56#include <CoreFoundation/CFData.h> 57#include <CoreFoundation/CFRuntime.h> 58 59// compatibility layer 60struct SecTransformCreateBlockParameters { 61 CFTypeRef (^send)(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value); 62 CFTypeRef (^get)(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type); 63 CFTypeRef (^pushback)(SecTransformStringOrAttributeRef attribute, CFTypeRef value); 64 CFErrorRef (^overrideTransform)(CFStringRef action, SecTransformActionBlock newAction); 65 CFErrorRef (^overrideAttribute)(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock newAction); 66}; 67 68typedef void (^SecTransformCreateBlock)(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params); 69 70SecTransformCreateBlock global_create_block; 71 72static SecTransformInstanceBlock block_for_custom_transform(CFStringRef name, SecTransformRef tr, SecTransformImplementationRef ir) 73{ 74 SecTransformInstanceBlock b = ^{ 75 // XXX: leak, need to override Finalize and clean up… (and need to handle caller overriding finalize…) 76 SecTransformCreateBlockParameters *params = static_cast<SecTransformCreateBlockParameters *>(malloc(sizeof(SecTransformCreateBlockParameters))); 77 78 params->overrideAttribute = ^(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock newAction) { 79 // We don't need to special case ProcessData to call SecTransformSetDataAction as there are no longer any uses of it 80 return SecTransformSetAttributeAction(ir, action, attribute, newAction); 81 }; 82 83 params->overrideTransform = ^(CFStringRef action, SecTransformActionBlock newAction) { 84 return SecTransformSetTransformAction(ir, action, newAction); 85 }; 86 87 params->get = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type) { 88 return SecTranformCustomGetAttribute(ir, attribute, type); 89 }; 90 91 params->send = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value) { 92 return SecTransformCustomSetAttribute(ir, attribute, type, value); 93 }; 94 95 params->pushback = ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) { 96 return SecTransformPushbackAttribute(ir, attribute, value); 97 }; 98 99 params->overrideAttribute = Block_copy(params->overrideAttribute); 100 params->overrideTransform = Block_copy(params->overrideTransform); 101 params->get = Block_copy(params->get); 102 params->send = Block_copy(params->send); 103 params->pushback = Block_copy(params->pushback); 104 105 global_create_block(name, tr, params); 106 107 return (CFErrorRef)NULL; 108 }; 109 110 return Block_copy(b); 111} 112 113// Sort of a bridge from the old Custom SPI to the new API, but is also 114// useful when you REALLY need to access stack locals as __block variables, 115// but don't need multithreading, or generic internalizing. 116static SecTransformRef custom_transform(CFStringRef base_name, SecTransformCreateBlock cb) 117{ 118 static int ct_cnt = 0; 119 static dispatch_queue_t cnt_q = dispatch_queue_create("com.apple.security.custom_trasnform-cnt", 0); 120 __block CFStringRef name = NULL; 121 __block SecTransformRef ret = NULL; 122 123 dispatch_sync(cnt_q, ^{ 124 CFErrorRef err = NULL; 125 126 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.%d"), base_name, ct_cnt++); 127 global_create_block = cb; 128 if (SecTransformRegister(name, block_for_custom_transform, &err)) { 129 ret = SecTransformCreate(name, &err); 130 if (err) { 131 CFfprintf(stderr, "Error %@ creating %@\n", err, base_name); 132 CFRelease(err); 133 } 134 } else { 135 CFfprintf(stderr, "Error %@ registering %@\n", err, base_name); 136 CFRelease(err); 137 } 138 global_create_block = NULL; 139 CFRelease(name); 140 }); 141 142 return ret; 143} 144 145 146#define STAssertErrorHas(err, rx, msg...) STAssertTrue(ErrorHas(err, rx), ##msg); 147 148static BOOL ErrorHas(NSError *error, NSString *rx) { 149 if (!error) { 150 return NO; 151 } 152 if (![error isKindOfClass:[NSError class]]) { 153 return NO; 154 } 155 156 NSString *es = [error description]; 157 if (!es) { 158 return NO; 159 } 160 return [es rangeOfString:rx options:NSRegularExpressionSearch].location != NSNotFound; 161} 162 163 164static SecTransformInstanceBlock DelayTransformBlock(CFStringRef name, 165 SecTransformRef newTransform, 166 SecTransformImplementationRef ref) 167{ 168 SecTransformInstanceBlock instanceBlock = 169 ^{ 170 CFErrorRef result = NULL; 171 172 173 SecTransformSetDataAction(ref, kSecTransformActionProcessData, 174 ^(CFTypeRef value) 175 { 176 177 if (NULL != value && CFNumberGetTypeID() == CFGetTypeID(value)) 178 { 179 long long n; 180 CFNumberGetValue((CFNumberRef)value, kCFNumberLongLongType, &n); 181 usleep((useconds_t)(n / NSEC_PER_USEC)); 182 } 183 184 return value; 185 }); 186 return result; 187 }; 188 189 return Block_copy(instanceBlock); 190} 191 192static SecTransformRef delay_transform(long long nsec) { 193 CFStringRef name = CFSTR("com.apple.security.unit-test.delay"); 194 195 196 197 static dispatch_once_t once; 198 __block Boolean ok = TRUE; 199 200 dispatch_block_t aBlock = ^ 201 { 202 ok = SecTransformRegister(name, &DelayTransformBlock, NULL); 203 }; 204 205 dispatch_once(&once, aBlock); 206 207 if (!ok) 208 { 209 return NULL; 210 } 211 212 SecTransformRef ct = SecTransformCreate(name, NULL); 213 CFNumberRef nr = CFNumberCreate(NULL, kCFNumberLongLongType, &nsec); 214 SecTransformSetAttribute(ct, CFSTR("DELAY"), nr, NULL); 215 CFRelease(nr); 216 217 return ct; 218} 219 220@implementation custom 221 222class BufferStream 223{ 224protected: 225 const char* mBuffer; 226 size_t mLength; 227 size_t mStringLength; 228 size_t mPos; 229 230 char *mCurrentString; 231 232public: 233 BufferStream(const char* buffer, size_t length) : mBuffer(buffer), mLength(length), mStringLength(0), mPos(0), mCurrentString(NULL) {} 234 ~BufferStream(); 235 236 const char* GetNextString(); 237 void SplitString(const char*& stringA, const char*& stringB); 238}; 239 240 241 242BufferStream::~BufferStream() 243{ 244 if (NULL != mCurrentString) 245 { 246 free(mCurrentString); 247 } 248} 249 250 251 252const char* BufferStream::GetNextString() 253{ 254 size_t p = mPos; 255 if (p >= mLength) 256 { 257 return NULL; // eof 258 } 259 260 // run to either the end of the buffer or a return 261 while (p < mLength && mBuffer[p] != '\n') 262 { 263 p += 1; 264 } 265 266 if (p != mLength) 267 { 268 // handle the end of the buffer specially, since it doesn't point 269 // to valid space 270 p -= 1; 271 } 272 273 // p now points to the last character in the string 274 // allocate memory for our buffer 275 mStringLength = p - mPos + 1; 276 mCurrentString = (char*) realloc(mCurrentString, mStringLength + 1); 277 memmove(mCurrentString, mBuffer + mPos, mStringLength); 278 mCurrentString[mStringLength] = 0; 279 mPos = p + 2; 280 281 return mCurrentString; 282} 283 284 285 286void BufferStream::SplitString(const char*& a, const char*& b) 287{ 288 // scan the buffer, looking for a ':' 289 size_t p = 0; 290 while (mCurrentString[p] != 0 && mCurrentString[p] != ':') 291 { 292 p += 1; 293 } 294 295 // the first string is always our buffer pointer 296 a = mCurrentString; 297 298 if (mCurrentString[p] == ':') 299 { 300 mCurrentString[p] = 0; 301 302 // look for the beginning of the next string 303 p += 1; 304 while (p < mLength && isspace(mCurrentString[p])) 305 { 306 p += 1; 307 } 308 309 b = mCurrentString + p; 310 } 311 else 312 { 313 b = NULL; 314 } 315} 316 317 318 319-(void)disabledtestzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz 320{ 321 // open leaks and make a connection to it. 322 char* name; 323 324 const int kChunkSize = 16384; 325 char buffer[kChunkSize]; 326 pid_t thePid = getpid(); 327 asprintf(&name, "/tmp/leaks%d.txt", thePid); 328 sprintf(buffer, "/usr/bin/leaks %d >%s", thePid, name); 329 system(buffer); 330 331 struct stat st; 332 stat(name, &st); 333 334 char* rBuffer = (char*) malloc((size_t)st.st_size); 335 FILE* f = fopen(name, "r"); 336 fread(rBuffer, 1, (size_t)st.st_size, f); 337 fclose(f); 338 339 // set up our output parser 340 BufferStream bStream(rBuffer, (size_t)st.st_size); 341 const char* s = bStream.GetNextString(); 342 343 bool didError = true; 344 345 if (NULL != s) 346 { 347 // we have our string, split it and see what it means 348 const char* key; 349 const char* value; 350 351 bStream.SplitString(key, value); 352 if (strcmp(key, "leaks Report Version") != 0 || strcmp(value, "2.0") != 0) 353 { 354 didError = true; 355 } 356 else 357 { 358 didError = false; 359 } 360 } 361 362 if (!didError) 363 { 364 const char* key; 365 const char* value; 366 367 // figure out what our target line will look like 368 char* target; 369 asprintf(&target, "Process %d", thePid); 370 371 const char* nextString = bStream.GetNextString(); 372 while (nextString) 373 { 374 bStream.SplitString(key, value); 375 if (strcmp(key, target) == 0) // we found our target!!! 376 { 377 // do it again 378 bStream.GetNextString(); 379 bStream.SplitString(key, value); 380 381 if (value[0] != '0') // we have a non-zero result... :( 382 { 383 didError = true; 384 } 385 } 386 387 nextString = bStream.GetNextString(); 388 } 389 390 free(target); 391 } 392 393 STAssertFalse(didError, @"You have leaks!"); 394 395 if (didError) 396 { 397 // dump to our output file 398 // make a file name for the leaks output 399 FILE* f = fopen(name, "w"); 400 fwrite(rBuffer, 1, (size_t)st.st_size, f); 401 fclose(f); 402 } 403 else 404 { 405 unlink(name); 406 } 407 408 free(name); 409} 410 411 412 413static const char* gHMACText = "The judicial Power shall extend to all Cases, in " 414 "Law and Equity, arising under this Constitution, " 415 "the Laws of the United States, and Treaties made, " 416 "or which shall be made, under their Authority;--to " 417 "all Cases affecting Ambassadors, other public " 418 "Ministers and Consuls;--to all Cases of admiralty " 419 "and maritime Jurisdiction;--to Controversies to " 420 "which the United States shall be a Party;--to " 421 "Controversies between two or more States;-- " 422 "between a State and Citizens of another State, " 423 "--between Citizens of different States,-- " 424 "between Citizens of the same State claiming Lands " 425 "under Grants of different States, and between a " 426 "State, or the Citizens thereof, and foreign " 427 "States, Citizens or Subjects"; 428 429const NSString* gAbortTransformName = (NSString*) kSecTransformAbortAttributeName; 430 431static const char* gHMACKey = "No person shall be held to answer for a capital, or " 432 "otherwise infamous crime, unless on a presentment " 433 "or indictment of a Grand Jury, except in cases " 434 "arising in the land or naval forces, or in the " 435 "Militia, when in actual service in time of War or " 436 "public danger; nor shall any person be subject for " 437 "the same offence to be twice put in jeopardy of life " 438 "or limb; nor shall be compelled in any criminal case " 439 "to be a witness against himself, nor be deprived of " 440 "life, liberty, or property, without due process of " 441 "law; nor shall private property be taken for public " 442 "use, without just compensation."; 443 444static const u_int8_t gSHA1HMAC[] = {0x2f, 0x68, 0x4b, 0x6b, 0x4f, 445 0xf7, 0x41, 0xc3, 0x76, 0x3d, 446 0x0b, 0xc3, 0x25, 0x02, 0x99, 447 0x03, 0xfa, 0xa5, 0xe9, 0xde}; 448 449static const u_int8_t gSHA256HMAC[] = {0xc2, 0x5c, 0x9a, 0x65, 0x08, 0x9e, 0x61, 0xb5, 450 0x03, 0xfe, 0xcb, 0x57, 0xb7, 0x55, 0x4f, 0x69, 451 0xdb, 0xef, 0xdb, 0xe7, 0x0d, 0xe2, 0x78, 0x2e, 452 0xf9, 0x48, 0xbd, 0xf6, 0x4f, 0x4b, 0x94, 0x0c}; 453-(void)testPaddings 454{ 455 CFStringRef paddings[] = {kSecPaddingNoneKey, kSecPaddingPKCS7Key, kSecPaddingPKCS5Key, kSecPaddingPKCS1Key}; 456 457 for(int i = 0; i < sizeof(paddings) / sizeof(*paddings); i++) { 458 CFErrorRef error = NULL; 459 SecKeyRef cryptokey = NULL; 460 SecTransformRef encrypt = NULL, decrypt = NULL; 461 CFDataRef cfdatacryptokey = NULL, sourceData = NULL, encryptedData = NULL, decryptedData = NULL; 462 const uint8_t rawcryptokey[16] = { 63, 17, 27, 99, 185, 231, 1, 191, 217, 74, 141, 16, 12, 99, 253, 41 }; // 128-bit AES key. 463 const char *sourceCString = "All these worlds are yours except Europa."; // I'm not so sure about that Earth one either 464 465 CFMutableDictionaryRef parameters = CFDictionaryCreateMutable( 466 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, 467 &kCFTypeDictionaryValueCallBacks); 468 469 CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES); 470 471 cfdatacryptokey = CFDataCreate(kCFAllocatorDefault, rawcryptokey, 472 sizeof(rawcryptokey)); 473 cryptokey = SecKeyCreateFromData(parameters, 474 cfdatacryptokey, &error); 475 STAssertNil((id)error, @"Unexpected SecKeyCreateFromData error: %@", error); 476 477 size_t len = strlen(sourceCString) +1; 478 if (paddings[i] == kSecPaddingNoneKey) { 479 STAssertTrue(len >= kCCBlockSizeAES128, @"Had at least one block"); 480 // Get to an AES block multiple, discarding bytes wildly. 481 len -= len % kCCBlockSizeAES128; 482 } 483 sourceData = (CFDataRef)[NSData dataWithBytes:sourceCString length:len]; 484 485 encrypt = SecEncryptTransformCreate(cryptokey, &error); 486 STAssertNil((id)error, @"Unexpected error creating encrypt transform: %@", error); 487 decrypt = SecDecryptTransformCreate(cryptokey, &error); 488 STAssertNil((id)error, @"Unexpected error creating decrypt transform: %@", error); 489 490 /* Set the padding on the transforms */ 491 SecTransformSetAttribute(encrypt, kSecPaddingKey, paddings[i], &error); 492 STAssertNil((id)error, @"Couldn't set encrypt padding to %@: %@", paddings[i], error); 493 SecTransformSetAttribute(decrypt, kSecPaddingKey, paddings[i], &error); 494 STAssertNil((id)error, @"Couldn't set decrypt padding to %@: %@", paddings[i], error); 495 496 SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName, sourceData, &error); 497 STAssertNil((id)error, @"Couldn't set encrypt transform input: %@", error); 498 499 encryptedData = (CFDataRef)SecTransformExecute(encrypt, &error); 500 STAssertNil((id)error, @"Couldn't execute encrypt: %@ (padding %@)", paddings[i], error); 501 STAssertNotNil((id)encryptedData, @"Didn't get encrypted data"); 502 503 SecTransformSetAttribute(decrypt, kSecTransformInputAttributeName, encryptedData, &error); 504 STAssertNil((id)error, @"Couldn't set decrypt transform input: %@", error); 505 506 decryptedData = (CFDataRef)SecTransformExecute(decrypt, &error); 507 STAssertNil((id)error, @"Couldn't execute decrypt: %@", error); 508 STAssertNotNil((id)decryptedData, @"Didn't get decrypt data"); 509 510 STAssertEqualObjects((id)decryptedData, (id)sourceData, @"Decrypt output didn't match encrypt input for padding %@", paddings[i]); 511 } 512} 513 514static SecTransformInstanceBlock nopInstance(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref) 515{ 516 SecTransformInstanceBlock instanceBlock = ^{ 517 return (CFErrorRef)NULL; 518 }; 519 520 return Block_copy(instanceBlock); 521} 522 523 524-(void)test_manyregister 525{ 526 dispatch_apply(4000, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(size_t i) { 527 NSString *name = [NSString stringWithFormat:@"many%luregister", i]; 528 CFErrorRef err = NULL; 529 BOOL ok = SecTransformRegister((CFStringRef)name, nopInstance, &err); 530 STAssertTrue(ok, @"register not ok"); 531 STAssertNil((id)err, @"register error: %@", err); 532 }); 533} 534 535-(void)test_emptyOAEP 536{ 537 SecKeychainRef tmp_keychain = NULL; 538 char *kcfname; 539 asprintf(&kcfname, "%s-OAEP-XXXXXXXXXX", "/tmp/"); 540 const char *passwd = "sekret"; 541 // NOTE: "mktemp" isn't as safe as you might think...but this is test code and doesn't have to be, but 542 // if you copy it elsewhere you may well need to rewrite it. (use mkstemp) 543 mktemp(kcfname); 544 OSStatus status = SecKeychainCreate(kcfname, (UInt32)strlen(passwd), passwd, NO, NULL, &tmp_keychain); 545 STAssertTrue(status == 0, @"Expected to make keychain, but got error 0x%x", status); 546 547 const char *pem_key_bytes[] = { 548 // From the spec 549 "-----BEGIN PUBLIC KEY-----\nMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC7+C8JBoLOnCM4rCudqHH3No0H\n7tQQQ6RA1rbwdFT1H7jfuq8DXAKrYepIzutvzUh27VINYOHsRhlxnYpbi4B/r7jg\no9/HN3I+5rS32TolhO5qZJ0GCVN0iDSyRUWYOU7gqrEte2GlH1J6mkH2wWh/4lNy\nmMoqj1lG+OX9CR29ywIBEQ==\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQC7+C8JBoLOnCM4rCudqHH3No0H7tQQQ6RA1rbwdFT1H7jfuq8D\nXAKrYepIzutvzUh27VINYOHsRhlxnYpbi4B/r7jgo9/HN3I+5rS32TolhO5qZJ0G\nCVN0iDSyRUWYOU7gqrEte2GlH1J6mkH2wWh/4lNymMoqj1lG+OX9CR29ywIBEQKB\ngQCl2vxTQfryicS5iNswwc34PzElHgZotCeEgTgBV5ZBspQQs8eZjWvEZXReXDkm\nadaHDaLAgqk543/cuC7JPtrJf/OtWVCsz7wRHHbxqVKUROVqr2jFbAks043DvvXS\nCpOZJu1PdKE+3fvhoc7MSJSvlCjCt7iIP+RGOkvIWxyzwQJBAO7ProGxubPJCIEL\nEKG1YAGZ659ErvT9pJO4Gp49hPYyEk7wI25dHjt+KPrnqgQKLVslIXZFnR85dUG6\nKlj7ZZkCQQDJf7HwJ/RT9jQSM+qq0dk1P2xC0IhmsdBaDyA1AoudhphAtBZmtC6S\n6g2jtDIEtc/OM1JSTQQWpaRB5wCvRhUDAkBUSUymProDN+TiQCP81ppa6wfd3AGD\npNCsm1SwUfKxPtlJCXXqt3QU/1nB92kumi4gKzj8kQpHQXStyTwfZ8mBAkBHHgKQ\n/wrwdQNRt/h4hkypYa29Oop+mRxcBVapTDFGp/mAP49viuNC6TH9iuR6Ig0bmaSV\nhJgH/jn5JFqYNto9AkEAsGxP2rtjARmNJlvbrpQjs4Dycfc0U4hQkwd/zTniEZ/J\nhjIVT1iDsWepZ79AK06eLg+WVuaY6jZm7fsleYA59w==\n-----END RSA PRIVATE KEY-----\n", 550 NULL, 551 }; 552 struct key_pair { 553 SecKeyRef pubKey, privKey; 554 }; 555 key_pair keys[1]; 556 557 int i; 558 for(i = 0; i < sizeof(keys)/sizeof(key_pair); i++) { 559 NSAssert(pem_key_bytes[i] != NULL, @"Expected a key"); 560 NSLog(@"Importing: %s", pem_key_bytes[i]); 561 CFDataRef pem_data = CFDataCreate(NULL, (UInt8*)(pem_key_bytes[i]), strlen(pem_key_bytes[i])); 562 SecKeyImportExportParameters import_params; 563 bzero(&import_params, sizeof(import_params)); 564 565 import_params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; 566 import_params.keyUsage = CSSM_KEYUSE_ANY; 567 import_params.keyAttributes = CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_SENSITIVE; 568 import_params.accessRef = NULL; 569 import_params.passphrase = CFSTR(""); 570 import_params.alertPrompt = CFSTR(""); 571 572 CFArrayRef keypair = NULL; 573 SecExternalFormat key_format = kSecFormatOpenSSL; 574 SecExternalItemType itemType = kSecItemTypeUnknown; 575 status = SecKeychainItemImport(pem_data, CFSTR(".pem"), &key_format, &itemType, 0, &import_params, tmp_keychain, &keypair); 576 STAssertTrue(status == 0, @"Expected pubkey import to be ok, got err=0x%x", status); 577 NSAssert(keypair != NULL, @"Expected to get some keys back"); 578 STAssertNotNil((id)keypair, @"Expected to get some keys back"); 579 STAssertTrue(CFArrayGetCount(keypair) == 2, @"Expected 2 keys, got %@", keypair); 580 keys[i].pubKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 0); 581 keys[i].privKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 1); 582 } 583 STAssertNil((id)pem_key_bytes[i], @"Expected to convert all pem keys, but found at least: %s", pem_key_bytes[i]); 584 CFDataRef encoding_parameters = CFDataCreate(NULL, NULL, 0); 585 586 587 CFErrorRef err = NULL; 588 589 SecTransformRef encryptor = SecEncryptTransformCreate(keys[0].pubKey, &err); 590 591 CFReadStreamRef empty_stream = CFReadStreamCreateWithBytesNoCopy(NULL, (UInt8*)"", 0, kCFAllocatorNull); 592 SecTransformSetAttribute(encryptor, kSecTransformInputAttributeName, empty_stream, &err); 593 SecTransformSetAttribute(encryptor, kSecPaddingKey, kSecPaddingOAEPKey, &err); 594 SecTransformSetAttribute(encryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, &err); 595 596 CFTypeRef encryptedData = SecTransformExecute(encryptor, &err); 597 STAssertNotNil((id)encryptedData, @"Expected to get encrypted data"); 598 STAssertNil((NSError*)err, @"Expected no error, got err=%@", err); 599 // Can't support "seed" with commoncrypto, just check round trip. 600 //STAssertEqualObjects((id)encryptedData, (id)tests[i].encryptedMessage, @"encrypted data should have matched test vector (%@) data", tests[i].label); 601 CFRelease(encryptor); 602 603 SecTransformRef decryptor = SecDecryptTransformCreate(keys[0].privKey, NULL); 604 // XXX: totally round trip, not even partial KAT (KAT can't really be done on OAEP 605 // without supporitng settign the seed externally) 606 SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, encryptedData, NULL); 607 SecTransformSetAttribute(decryptor, kSecPaddingKey, kSecPaddingOAEPKey, NULL); 608 SecTransformSetAttribute(decryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, NULL); 609 CFTypeRef decryptedData = SecTransformExecute(decryptor, &err); 610 STAssertNil((id)err, @"Expected no error, got: %@", err); 611 STAssertNotNil((id)decryptedData, @"Expected to get decrypted data"); 612 // What do we expect an empty enc/dec to look like? Mostly "not a crash" 613 CFDataRef empty_data = CFDataCreate(NULL, (UInt8*)"", 0); 614 STAssertEqualObjects((id)decryptedData, (id)empty_data, @"Expected decrypted data to match original message"); 615 CFRelease(decryptor); 616 sleep(5); 617 618 return; 619} 620 621-(void)testzzzzZZZZ 622{ 623 // Give xcode a little time to parse all the output before the unit tests exit 624 sleep(2); 625} 626 627-(void)test_multiOAEP 628{ 629 SecKeychainRef tmp_keychain = NULL; 630 char *kcfname; 631 asprintf(&kcfname, "%s-OAEP-XXXXXXXXXX", "/tmp/"); 632 const char *passwd = "sekret"; 633 // NOTE: "mktemp" isn't as safe as you might think...but this is test code and doesn't have to be, but 634 // if you copy it elsewhere you may well need to rewrite it. (use mkstemp) 635 mktemp(kcfname); 636 OSStatus status = SecKeychainCreate(kcfname, (UInt32)strlen(passwd), passwd, NO, NULL, &tmp_keychain); 637 STAssertTrue(status == 0, @"Expected to make keychain, but got error 0x%x", status); 638 639 const char *pem_key_bytes[] = { 640 // From the spec 641 "-----BEGIN PUBLIC KEY-----\nMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC7+C8JBoLOnCM4rCudqHH3No0H\n7tQQQ6RA1rbwdFT1H7jfuq8DXAKrYepIzutvzUh27VINYOHsRhlxnYpbi4B/r7jg\no9/HN3I+5rS32TolhO5qZJ0GCVN0iDSyRUWYOU7gqrEte2GlH1J6mkH2wWh/4lNy\nmMoqj1lG+OX9CR29ywIBEQ==\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQC7+C8JBoLOnCM4rCudqHH3No0H7tQQQ6RA1rbwdFT1H7jfuq8D\nXAKrYepIzutvzUh27VINYOHsRhlxnYpbi4B/r7jgo9/HN3I+5rS32TolhO5qZJ0G\nCVN0iDSyRUWYOU7gqrEte2GlH1J6mkH2wWh/4lNymMoqj1lG+OX9CR29ywIBEQKB\ngQCl2vxTQfryicS5iNswwc34PzElHgZotCeEgTgBV5ZBspQQs8eZjWvEZXReXDkm\nadaHDaLAgqk543/cuC7JPtrJf/OtWVCsz7wRHHbxqVKUROVqr2jFbAks043DvvXS\nCpOZJu1PdKE+3fvhoc7MSJSvlCjCt7iIP+RGOkvIWxyzwQJBAO7ProGxubPJCIEL\nEKG1YAGZ659ErvT9pJO4Gp49hPYyEk7wI25dHjt+KPrnqgQKLVslIXZFnR85dUG6\nKlj7ZZkCQQDJf7HwJ/RT9jQSM+qq0dk1P2xC0IhmsdBaDyA1AoudhphAtBZmtC6S\n6g2jtDIEtc/OM1JSTQQWpaRB5wCvRhUDAkBUSUymProDN+TiQCP81ppa6wfd3AGD\npNCsm1SwUfKxPtlJCXXqt3QU/1nB92kumi4gKzj8kQpHQXStyTwfZ8mBAkBHHgKQ\n/wrwdQNRt/h4hkypYa29Oop+mRxcBVapTDFGp/mAP49viuNC6TH9iuR6Ig0bmaSV\nhJgH/jn5JFqYNto9AkEAsGxP2rtjARmNJlvbrpQjs4Dycfc0U4hQkwd/zTniEZ/J\nhjIVT1iDsWepZ79AK06eLg+WVuaY6jZm7fsleYA59w==\n-----END RSA PRIVATE KEY-----\n", 642 // The next 10 are from oaep-vect.txt (via a lot of OpenSSL higgerdy-jiggerdey) 643 "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCos7KEr461CzhwNKhg8UbEkZ8x\nh2PNbFWYyK5IEaHgq8TH4LCC1pOl5/ztZ1z0ZoUSdywMvGSnQsbGMPUzyMxy9iro\nM8QL8lhC6YS7eL2/l8AQfVW9tmL1xOD6uYRctRSO9zkt06r/k64ea2Z7s9QkdhbU\n9boQ1M/SJt6I058W+wIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQCos7KEr461CzhwNKhg8UbEkZ8xh2PNbFWYyK5IEaHgq8TH4LCC\n1pOl5/ztZ1z0ZoUSdywMvGSnQsbGMPUzyMxy9iroM8QL8lhC6YS7eL2/l8AQfVW9\ntmL1xOD6uYRctRSO9zkt06r/k64ea2Z7s9QkdhbU9boQ1M/SJt6I058W+wIDAQAB\nAoGAUzOc/befyEZqZVxzFqyoXFX9j23YmP2vEZUX709S6P2OJY35P+4YD6Dkqylp\nPNg7FSpVPUrE0YEri5+lrw5/Vf5zBN9BVwkm8zEfFcTWWnMsSDEW7j09LQrzVJrZ\nv3y/t4rYhPhNW+sEck3HNpsx3vN9DPU56c/N095lNynq1dECQQDTJzfnJn/+E0Gy\n1cDRUKgbWG+zEyvtL41SYoZKnLnzCvOL5EhZjUE6Fy77gCwhrPHBHFIMLyakcdyt\nIS6sfKOdAkEAzIhT0dVNpjD6wAT0cfKBx7iYLYIkpJDtvrM9Pj1cyTxHZXA9HdeR\nZC8fEWoN2FK+JBmyr3K/6aAw6GCwKItddwJADhK/FxjpzvVZm6HDiC/oBGqQh07v\nzo8szCDk8nQfsKM6OEiuyckwX77L0tdoGZZ9RnGsxkMeQDeWjbN4eOaVwQJBAJUp\new+Vovpn0AcH1gnf1PwFyJ2vwu9tbqVb7HceozNzTZJR55CC7NqGbv7xPEWeGmMT\nhrfjVMiZ9fESyoXXFYMCQE9FbFAkk73A7Sq3VqOm7U1nNSppfUIW6TISsSemPVQR\nzm+pjV2+/XMmPjcoFCdDgYFm7X3WNofdKoyh0vT72OE=\n-----END RSA PRIVATE KEY-----\n", 644 "RSA key ok\n-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQGUfH/OkEJfRyeecIUfJdXmIxb+\nih3xk3Hj5ijiYFQ+SQHvYIH2jAuBQRkNKujaun0SUOxttjbpROw3Iod8fB0KZ/FL\nFpTF8DeUUaQ+SaMt3oNnC3PakaHJm8I7Q2pgBVxhDwuvmcGgeVZblaPxUmYy0dTa\nYPIO2iXmU8TwAnZvRQIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQGUfH/OkEJfRyeecIUfJdXmIxb+ih3xk3Hj5ijiYFQ+SQHvYIH2\njAuBQRkNKujaun0SUOxttjbpROw3Iod8fB0KZ/FLFpTF8DeUUaQ+SaMt3oNnC3Pa\nkaHJm8I7Q2pgBVxhDwuvmcGgeVZblaPxUmYy0dTaYPIO2iXmU8TwAnZvRQIDAQAB\nAoGAaHJZomJX8Thzf5M4nNltSXcIKgRKRSY4w4ucRRBw0ICTslduV9bD5cWEjYTm\nCg0b3M3ur0ndFhFJGdedusRlzrJ3phMQcCvg8AygYOPN4gqYbIqz7xshfRxwQoGT\nGwFbOc4FQzlmlGna+VJDZ8sxykucXXKZh+wfN0vR7xXmj6UCQQFZ294Eoz7wb7YI\nuAsZD00+IrzBOsjkoIEDOr+kFu2wsziqCLVzCepaUkDn3G5UN4xpQUwx2X3bH0Bt\ns3acxBpDAkEBK2UvMEA7OLQJlf1v9BoazIracDcyNrcgLTmy7jDPtG2wlRH28wfM\nYcwhYGwYp1uKYvgi3wMboN8Nr9VQb1aL1wJAQ271CN5zZRnC2kxYDZjILLdFKj+1\n763Ducd4mhvGWE95Wt270yQ5x0aGVS7LbCwwek069/U57sFXJIx7MfGiVQJBASsV\nqJ89+ys5Bz5z8CvdDBp7N53UNfBc3eLv+eRilIt87GLukFDV4IFuB4WoVrSRCNy3\nXzaDh00cpjKaGQEwZv8CQAJw2xfVkUsBjXYRiyQ4mnNQ7INrAGOiFyEjb9jtttib\nUefuuHthG3Eyy36nNWwjFRwed1FQfHhtnuF5QXCoyOg=\n-----END RSA PRIVATE KEY-----\n", 645 "RSA key ok\n-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQK1j+wDmoYHAKTXtkYvk+bN1JEW\nHd109OgQtA48FlIAalwneyd0wRMFpMurWnjvpX4XqG33o/o2/EsdIknyLsfC3WpG\nMjKszqkG1m6+gLVwSxBynab4MyNKu1791KKSy/rTO00z+noUuMOXtW46zSEgNCi3\nfN+jOm2nBrPYsPxD6QIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQK1j+wDmoYHAKTXtkYvk+bN1JEWHd109OgQtA48FlIAalwneyd0\nwRMFpMurWnjvpX4XqG33o/o2/EsdIknyLsfC3WpGMjKszqkG1m6+gLVwSxBynab4\nMyNKu1791KKSy/rTO00z+noUuMOXtW46zSEgNCi3fN+jOm2nBrPYsPxD6QIDAQAB\nAoGAFbSKW1aDqUZw4jtXGPgU+g4T+FA49QcRGCy6YVEFgfPSLH4jLvk34i5VHWi4\nbi+MsarYvi5Ij13379J54/Vo1Orzb4DPcUGs5g/MkRP7bEqEH9ULvHxRL/y+/yFI\neqgR6zyoxiAFNGqG3oa/odipSP0/NIwi6q3zM8PObOEyCP0CQQG/AdIW1zWVzwJw\nwr63jUCg2ER9MdqRmpg/fup4G3fYX+Nxs+k3PntpIX0xUKAtiVjef62dVVFglYtE\nVBJ+Dn6vAkEBjTOZZYFm2zgpgW17KVQWdZ6ckZh/Wy2K7NY7BLSL17L88im7f4pt\nyIuhPdLjmtVbbRoGFgcI+XAL6AuP03RM5wJABsCiSdIKby7nXIi0lNU/aq6ZqkJ8\niMKLFjp2lEXl85DPQMJ0/W6mMppc58fOA6IVg5buKnhFeG4J4ohalyjk5QJBANHS\nfCn+3ZLYbDSO3QzL+sFPdG4FHOHRgR3zXWHy7hyX1L8oBIAvZCcYe6jpCor0QkO0\nB5sDRF5gLin6UZPmT+kCQQCMsvdWvYlBsdO3cOWtMe43Oyis2mn/m29A/leLnxr7\nhYNvlifTes/3PCd55jS7JgEcLI9/M2GuKp6mXtaJ42Oa\n-----END RSA PRIVATE KEY-----\n", 646 "RSA key ok\n-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQUSQLbMAAT6SNATRnHAeMfI3sOz\n4vJbwlZEZzOds4hT0GuF7qWy3jU7/0KsLka8l/rmrJYY2pU3pcj1U8HjV2JZkdYQ\njc14hfs6JUE/U+/K2UjLNc2bmunBxnYm0RPVfd5MW+p2u1u33pbADQc3LpaFptdc\n+dI5+hSNcJMbXz+wOQIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQUSQLbMAAT6SNATRnHAeMfI3sOz4vJbwlZEZzOds4hT0GuF7qWy\n3jU7/0KsLka8l/rmrJYY2pU3pcj1U8HjV2JZkdYQjc14hfs6JUE/U+/K2UjLNc2b\nmunBxnYm0RPVfd5MW+p2u1u33pbADQc3LpaFptdc+dI5+hSNcJMbXz+wOQIDAQAB\nAoGBAQs6yuW+80dZiYsOKwgFVIpiYEI86so8fGlkHNnPRLaL5jYRY4Yn+yk4Z87t\nT54uYnTs/ZBsHd7wfycQcI6NRC5hgVY5sbQKDJDJIHgDPvxewvmE+mgbRFo7v4RH\nGGacGivrZVhXdDMpOm3KyxRfToWUJIq6IhT0AeURYrezGJABAkECdFjBnsFjaRnn\nNsmvJdYJpRuPVh0Zxr9pQ90e4auKSj8jIQC9QLiN7Ma6I1VItu95KhHJ3oI9Cnki\nxwlbbrpXAQJBAhDumzOrYXFuJ9JRvUZfSzWhojLi2gCQHClL8iNQzkkNCZ9kK1N1\nYS22O6HyA4ZJK/BNNLPCK865CdE0QbU7UTkCQDn6AouCbojBEht1CoskL6mjXFtm\nvf0fpjfTzEioSk9FehlOdyfkn3vMblpaQSZX/EcMcyLrw3QW70WMMHqMCQECQQFd\nmahBlZQ5efqeG+LDwbafQy9G/QPkfVvvu7/WsdE3HYPvszCj4CCUKy/tEV5dAr4k\n/ZLJAZ0c7NbdTPHlTMiZAkEB8LcBUXCz9eQiI7owMBxBpth8u3DjDLfTxn0lRz2x\n9svwPj+RJuPpeWgnmoZbLCtCZSTPxSpoPTHtMOuYS+QSug==\n-----END RSA PRIVATE KEY-----\n", 647 "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQqt8/nBJeXYkfMaxEjpk97+WA+A\nK0X51/IrpQIenEdXa1oeaAMbqdtObavk2Wodbz0mcmjP9AgAXxGO/K25mIjRwjRG\ncWayorhJoFqInAYKwNoMX66LVfMJumLnA3QvoDJvLRCwEQIUif9Jd3AZDYlf059S\nKTw579c6aYvaufEO2QIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXwIBAAKBgQqt8/nBJeXYkfMaxEjpk97+WA+AK0X51/IrpQIenEdXa1oeaAMb\nqdtObavk2Wodbz0mcmjP9AgAXxGO/K25mIjRwjRGcWayorhJoFqInAYKwNoMX66L\nVfMJumLnA3QvoDJvLRCwEQIUif9Jd3AZDYlf059SKTw579c6aYvaufEO2QIDAQAB\nAoGBAlbrTLpwZ/LSvlQNzf9FgqNrfTHRyQmbshS3mEhGaiaPgPWKSawEwONkiTSg\nIGwEU3wZsjZkOmCCcyFE33X6IXWI95RoK+iRaCdtxybFwMvbhNMbvybQpDr0lXF/\nfVKKz+40FWH2/zyuBcV4+EcNloL5wNBy+fYGi1bViA9oK+LFAkEDsNOWL20XVJy/\nyhEpQ0jc8Ofjn4wrxoJPIWS2BtaHhg2uHmMjk8/t9RMigikGni9g5KzX5jOkNgY/\ngjhfSJk3BwJBAuTDLi9Rcmm3ByMJ8AwOMTZffOKLI2uCkS3yOavzlXLPDtYEsCmC\n5TVkxS1qBTl95cBSov3cFB73GJg2NGrrMx8CQQHoSxGdJRYfpnsAJWpb2bZF0rIy\n7LBbAVGAApqIYircPwmzrqzeYWGrfN4iwq0m53l99U4HLL07JnOACz5DONvVAkEA\n65CqGkATW0zqBxl87ciBm+Hny/8lR2YhFvRlpKn0h6sS87pP7xOCImWmUpfZi3ve\n2TcuP/6Bo4s+lgD+0FV1TwJBAS9/gTj5QEBi64WkKSRSCzj1u4hqAZb0i7jc6mD9\nkswCfxjngVijSlxdX4YKD2wEBxp9ATEsBlBi8etIt50cg8s=\n-----END RSA PRIVATE KEY-----\n", 648 "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgRKxf22tLs0Z/0bcE/eGDwng4M+2\nd7OKUlkjBc6vAiwWbbkNBKwp4z990S2fr2bggWu2Pq0mfMfUbBfDe+IUvKKiLXI6\nZOREB0Nrb8llcprvwlVPN2zV3OpoKTeApivznQApSFoWC7ueXcCXLSGlBPUuXuAo\nqkFjMvUQsunP9fcirwIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXwIBAAKBgRKxf22tLs0Z/0bcE/eGDwng4M+2d7OKUlkjBc6vAiwWbbkNBKwp\n4z990S2fr2bggWu2Pq0mfMfUbBfDe+IUvKKiLXI6ZOREB0Nrb8llcprvwlVPN2zV\n3OpoKTeApivznQApSFoWC7ueXcCXLSGlBPUuXuAoqkFjMvUQsunP9fcirwIDAQAB\nAoGBApXso1YGGDaVWc7NMDqpz9r8HZ8GlZ33X/75KaqJaWG80ZDcaZftp/WWPnJN\nB7TcEfMGXlrpfZaDURIoC5CEuxTyoh69ToidQbnEEy7BlW/KuLsv7QV1iEk2Uixf\n99MyYZBIJOfK3uTguzctJFfPeOK9EoYij/g/EHMc5jyQz/P5AkEEps6Lc1jfppvc\n90JhcAWvtThfXzpYok73SiKowFy3zDjr1Mydmp14mmLND2Dwy5QdNCPJaS76T+Ot\n/ykMR0mjiwJBBATJqAM3H+20xb4588ALAJ5eCKY74eQANc2spQEcxwHPfuvLmfD/\n4Xz9Ckv3vv0t1TaslG23l/28Sr6PKTSbke0CQQOWHI92CqK9UVTHqv13Ils7rNAT\nmue1lI6jMR/M2G+5XHWvp2coS5st5VlXLxXY0ETH64Ohvl+t8sw3fA2EdSlLAkEC\nIZfgZnQhlqq8A/ov7rTnCxXLeH1hes0xu3XHvCNK1wb3xI0hgtHw/5wijc9Blnts\nC6bSwK0RChuFeDHsJF4ssQJBBAHEwMU9RdvbXp2W0P7PQnXfCXS8Sgc2tKdMMmkF\nPvtoas4kBuIsngWN20rlQGJ64v2wgmHo5+S8vJlNqvowXEU=\n-----END RSA PRIVATE KEY-----\n", 649 "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgTERefC8/JudPKMV0A7zDXvdOiz6\n6ZEb/ty5SLOkeC0HMrarRKpL8DdBpkTcAb7D5psBoDPmddis18SSXGsa7DEZBR39\niXYtIV1FR1/8tZ+QgUhiPzcXcVb2robdenxfQ9weH5CCVAWKKEpfBsACF5OofxrF\n/v99yu5pxeUaN4njcwIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgTERefC8/JudPKMV0A7zDXvdOiz66ZEb/ty5SLOkeC0HMrarRKpL\n8DdBpkTcAb7D5psBoDPmddis18SSXGsa7DEZBR39iXYtIV1FR1/8tZ+QgUhiPzcX\ncVb2robdenxfQ9weH5CCVAWKKEpfBsACF5OofxrF/v99yu5pxeUaN4njcwIDAQAB\nAoGBDzqRUfoVnGZsj2ERtdIReUPr7lHhc7vwmaiXu8lr0u3M+4ykPwZag4vIgs6V\nbBN42triUblREfJy9PtH26X7cC0twt93fImTyuAcrKSNXKQIizI0XrhyB/9ewQv8\nkuI8dQugKhVIO+A1Ii2HPT7q9BC1DS9aYZ/PUzUQ68WM7b2BAkEHSSYsERzUcOwl\nZuazcy/AkylGmqGQcdO5wBkGUUxvHSa6oUvqsJcci35hGk95AJ1v6ndpKMolKFsN\n42Q9Gj+McQJBBrweUOlsAr9jbp7qi4mbvr92Ud533UdMPpvCO62BgrYZBMfZffvr\n+x4AEIh4tuZ+QVOR1nlCwrK/m0Q1+IsMsCMCQQO8fqfwqrFDq8bOi5cRhjajAXLk\nz+Asj6Ddo7e6r5D4CSmCmFUl9Ii9/LS9cm4iY5rGSjCSq3/8vx1TNM+lC1vxAkEC\nYqaqKcKjxn3FNGwGOBr9mHqjzJPPv+z1T92fnXh9f1mlI9OYl52hN6L2OB/pSAH3\nyU2iFRjcNMtAhwxGl5lK2QJAZJ1MF7buFyHnctA4mlWcPTzflVDUV8RrA3t0ZBsd\nUhZq+KITyDliBs37pEIvGNb2Hby10hTJcb9IKuuXanNwwg==\n-----END RSA PRIVATE KEY-----\n", 650 "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgVvfDjDTId2lFH+IJAj6aRlUgN+P\ngNP26L9YGFBPNkJ8qbH1VAucZaj2l0z4RHokTZKAIBu0n8u+Y3jRlEzSJ+Iw+W49\nEPgZ3O8nbGSgCypLZwHn0B3l+r3jsemg34L0YxNZzSJmlkf7sXFyRhNO17SXz/+9\nxCtZxzqW7ZAWYhLf9wIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIICXwIBAAKBgVvfDjDTId2lFH+IJAj6aRlUgN+PgNP26L9YGFBPNkJ8qbH1VAuc\nZaj2l0z4RHokTZKAIBu0n8u+Y3jRlEzSJ+Iw+W49EPgZ3O8nbGSgCypLZwHn0B3l\n+r3jsemg34L0YxNZzSJmlkf7sXFyRhNO17SXz/+9xCtZxzqW7ZAWYhLf9wIDAQAB\nAoGBD30enlqqJf0T5KBmOuFE4NFfXNGLzbCd8sx+ZOPF6RWtYmRTBBYdCYxxW7er\ni9AdB+rz/tfH7QivKopi70SrFrMg4Ur3Kkj5av4mKgrkz2XmNekQeQzU7lzqdopL\nJjn35vZ3s/C7a+MrdXR9iQkDbwJk9Y1AHNuhMXFhV6dez2MxAkEKAu+ESNn62LvQ\n0ATIwqqXUe+XIcGw0DI2pUsN+UfLrtWiVe6ejiDUkeoXI/4JRwSpdi6Ir9Fuu1mU\nQSypZtxPnwJBCS02Ln7ToL/Z6f0ObAMBtt8pFZz1DMg7mwz01u6nGmHgArRuCuny\n3mLSW110UtSYuByaxvxYWT1MP7T11y37sKkCQQfHFBCvEDli2zZ0BON66FC6pOnC\nndkhRYFSlKZ8fRxt7SY6oDCptjOuUDA+FANdGvAUEj66aHggMI2OvIW2lX19AkEA\nrix1OAwCwBatBYkbMwHeiB8orhFxGCtrLIO+p8UV7KnKKYx7HKtYF6WXBo/IUGDe\nTaigFjeKrkPH+We8w3kEuQJBBZjRBZ462k9jIHUsCdgF/30fGuDQF67u6c76DX3X\n/3deRLV4Mi9kBdYhHaGVGWZqqH/cTNjIj2tuPWfpYdy7o9A=\n-----END RSA PRIVATE KEY-----\n", 651 "-----BEGIN PUBLIC KEY-----\nMIHfMA0GCSqGSIb3DQEBAQUAA4HNADCByQKBwQDPLNQeNMo6co6ly4r/ZMNtJ73v\nU2TjNv1o0xI8WhlqjChwE+hT1RVtWNFRlUUg+09texertoF3ZZCcV2EZZZ2QKxkG\n7YorEMFVwk0SRSjaue6uN5vqxm5KQReG3Lj9AGLrwDDeEhmgTCqMG33TEx5Na2yu\n4uMaXtQawVCbLvHuKrGDZL5WjKlBwl7MhP+dZDtewaquECog1z9Hm3gP1tqRB1IS\n2erAOgZ02JnrouQx9MRLYVtroiMr1LM7rtc9Yl0CAwEAAQ==\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIIDfgIBAAKBwQDPLNQeNMo6co6ly4r/ZMNtJ73vU2TjNv1o0xI8WhlqjChwE+hT\n1RVtWNFRlUUg+09texertoF3ZZCcV2EZZZ2QKxkG7YorEMFVwk0SRSjaue6uN5vq\nxm5KQReG3Lj9AGLrwDDeEhmgTCqMG33TEx5Na2yu4uMaXtQawVCbLvHuKrGDZL5W\njKlBwl7MhP+dZDtewaquECog1z9Hm3gP1tqRB1IS2erAOgZ02JnrouQx9MRLYVtr\noiMr1LM7rtc9Yl0CAwEAAQKBwQCBIn4tPdZ3zAQiT9caDiLKHSWE0cRm5FXcSwRo\n3fhNs4NZKO99oaozeFMwuQxX3I3LvhgpDh9w3rve15BMlkw6GsME0Hd5FH6OCAim\nRLmMbKzbpwnmszz3x870Xwxnlx7xZblxuoKHiq4tjuoOK2FETNi979bB1jGO0xrA\nd8Oap2AMKBju4OmNpRdzjTKaMVyFavjn7HKHZ2Pp2Y45K/X+hIv0Kx8xx7kkaix7\nyxQLIVKMPjoanViwHTxWls9mUQECYQD8jWwEvsTrmoGSynkAy+U24ui1Gd7PM7JF\nl5jGkJ308XbbfSMZD8criGWnGK+JXxvNkUUpgCdCO2BecKR89YOQqMPoj8jEjosy\n49ohDfvj6IHqVnS2o0jCHpP55V6mXv0CYQDSANReeIqs6mBqQB0EYPh91cECfhLc\nGg11huiTnZz3ibQPUawEQpYd59Icwh4FyDFVwfKqkZM4fP35VstI0VO6JwQG+bu6\nU31Jh9ni+ZQtehTL//6nT+zdqSjSPiWfXuECYQDbFoAveaLw1F81jWn9M+RLgfro\nKGIuk6VCU+mX0BsHQ3WdoOgStKpObIvqsjKNVDGVWkGKZ/8mqMXIB6XaNU4F7zHM\njPdY9GNzKVCwPiZXJvuU451qVyomJEqwjbdXUq0CYQCgoxfP598UI/h6be6EUfTi\ntKZ+VJfym08eToMLn63ZQBFnAm9VluWjnJeBfg9fFuJ+GeyZAuAdfqb7mqPHYK/u\nHjgbad5qycB1haBq2cS6AL91yK0vqJikeegK4pT+0qECYAsh8zXDUzQutEw6okRF\neAwtZVuUAXTK44x8ik5kk8C6n9MDdIJnsIO5p6bLYeQts2K4yYlttwZOAq1a5hWH\n2hW0ZJyQWUkJ/rN9vLZUvrcmjsgB5ai0qjkRvr2IVC8Fvg==\n-----END RSA PRIVATE KEY-----\n", 652 "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArkXtVgHOxrjMBfgDk1xn\nTdvg11xMCf15UfxrDK7DE6jfOZcMUYv/ul7Wjz8NfyKkAp1BPxrgfk6+nkF3ziPn\n9UBLVp5O4b3PPB+wPvETgC1PhV65tRNLWnyAha3K5vovoUF+w3Y74XGwxit2Dt4j\nwSrZK5gIhMZB9aj6wmva1KAzgaIv4bdUiFCUyCUG1AGaU1ooav6ycbubpZLeGNz2\nAMKu6uVuAvfPefwUzzvcfNhP67v5UMqQMEsiGaeqBjrvosPBmA5WDNZK/neVhbYQ\ndle5V4V+/eYBCYirfeQX/IjY84TE5ucsP5Q+DDHAxKXMNvh52KOsnX1Zhg6q2muD\nuwIDAQAB\n-----END PUBLIC KEY-----\n-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEArkXtVgHOxrjMBfgDk1xnTdvg11xMCf15UfxrDK7DE6jfOZcM\nUYv/ul7Wjz8NfyKkAp1BPxrgfk6+nkF3ziPn9UBLVp5O4b3PPB+wPvETgC1PhV65\ntRNLWnyAha3K5vovoUF+w3Y74XGwxit2Dt4jwSrZK5gIhMZB9aj6wmva1KAzgaIv\n4bdUiFCUyCUG1AGaU1ooav6ycbubpZLeGNz2AMKu6uVuAvfPefwUzzvcfNhP67v5\nUMqQMEsiGaeqBjrvosPBmA5WDNZK/neVhbYQdle5V4V+/eYBCYirfeQX/IjY84TE\n5ucsP5Q+DDHAxKXMNvh52KOsnX1Zhg6q2muDuwIDAQABAoIBAFyN+sxwzVaxEnoh\nDBUZQCwTmMgH1sJ/gg1O17O2pRgt2dAGLp6okbpzX9RYElzxEtXompxfM9chDw+R\niYVLgIe6C8kG7rHpUsSFt97VvhuW9OLKOiq3ApAeC0vzzwz41o7379DzXD4RWWcF\n8f9XbvnKPehvKCcL/D/x7KuRCHlfcePoXxNqn5d8sTvh6/sn+8FRT63/A5FYxhQX\nMt8loVGw8ezKX5U98U/gvoSWCK6lJ4YEcBgdlIewIj0ueWehA7cLMzzPpVxtqp1J\nFEw1ruWhwGiIIPHEgj8tnyAq17lDs6I/Drx0MGJ9eWQNpn0RVRDluALBIuf5RjU1\ntCRJU+ECgYEA7PWuzR5VFf/6y9daKBbG6/SQGM37RjjhhdZqc5a2+AkPgBjH/ZXM\nNLhX3BfwzGUWuxNGq01YLK2te0EDNSOHtwM40IQEfJ2VObZJYgSz3W6kQkmSB77A\nH5ZCh/9jNsOYRlgzaEb1bkaGGIHBAjPSF2vxWl6W3ceAvIaKp30852kCgYEAvEbE\nZPxqxMp4Ow6wijyEG3cvfpsvKLq9WIroheGgxh5IWKD7JawpmZDzW+hRZMJZuhF1\nzdcZJwcTUYSZK2wpt0bdDSyr4UKDX30UjMFhUktKCZRtSLgoRz8c52tstohsNFwD\n4F9B1RtcOpCj8kBzx9dKT+JdnPIcdZYPP8OGMYMCgYEAxzVkVx0A+xXQij3plXpQ\nkV1xJulELaz0K8guhi5Wc/9qAI7U0uN0YX34nxehYLQ7f9qctra3QhhgmBX31Fyi\nY8FZqjLSctEn+vS8jKLXc3jorrGbCtfaPLPeCucxSYD2K21LCoddHfA8G645zNgz\n72zX4tlSi/CE0flp55Tp9sECgYAmWLN/bfnBAwvh22gRf6nYfjnqK2k7fm06L3CU\ndBPuxhQuGPuN/LasVF18hqCtSPhFcXDw77JrxIEmxT79HRaSAZjcKhEH3CgttqgM\n0wYjYLo/oT9w5DEv8abNa4/EzZxcPbF8bWpXIS9zrin2GTJ7rVmxU4WFhbpOKLYK\nYqReSQKBgG84Ums5JQhVNO8+QVqDbt6LhhWKLHy/7MsL2DQwT+xoO6jU9HnEM9Q0\nFuYyaWI86hAHdtha/0AdP/9hDuZUEc47E2PWOpcJ7t5CZHzqVhST1UVwqHnBhoLN\nl3ELliBewxEX1ztfNiI/rdboupDdfA7mHUThYyUeIMf2brMFEXy4\n-----END RSA PRIVATE KEY-----\n", 653 NULL, 654 }; 655 struct key_pair { 656 SecKeyRef pubKey, privKey; 657 }; 658 key_pair keys[11]; 659 660 int i; 661 for(i = 0; i < sizeof(keys)/sizeof(key_pair); i++) { 662 NSAssert(pem_key_bytes[i] != NULL, @"Expected a key"); 663 NSLog(@"Importing: %s", pem_key_bytes[i]); 664 CFDataRef pem_data = CFDataCreate(NULL, (UInt8*)(pem_key_bytes[i]), strlen(pem_key_bytes[i])); 665 SecKeyImportExportParameters import_params; 666 bzero(&import_params, sizeof(import_params)); 667 668 import_params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; 669 import_params.keyUsage = CSSM_KEYUSE_ANY; 670 import_params.keyAttributes = CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_SENSITIVE; 671 import_params.accessRef = NULL; 672 import_params.passphrase = CFSTR(""); 673 import_params.alertPrompt = CFSTR(""); 674 675 CFArrayRef keypair = NULL; 676 SecExternalFormat key_format = kSecFormatOpenSSL; 677 SecExternalItemType itemType = kSecItemTypeUnknown; 678 status = SecKeychainItemImport(pem_data, CFSTR(".pem"), &key_format, &itemType, 0, &import_params, tmp_keychain, &keypair); 679 STAssertTrue(status == 0, @"Expected pubkey import to be ok, got err=0x%x", status); 680 NSAssert(keypair != NULL, @"Expected to get some keys back"); 681 STAssertNotNil((id)keypair, @"Expected to get some keys back"); 682 STAssertTrue(CFArrayGetCount(keypair) == 2, @"Expected 2 keys, got %@", keypair); 683 keys[i].pubKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 0); 684 keys[i].privKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 1); 685 } 686 STAssertNil((id)pem_key_bytes[i], @"Expected to convert all pem keys, but found at least: %s", pem_key_bytes[i]); 687 CFDataRef encoding_parameters = CFDataCreate(NULL, NULL, 0); 688 689 struct KAT { 690 NSData *message, *seed, *encryptedMessage; 691 NSString *label; 692 key_pair keys; 693 }; 694 KAT tests[] = { 695 // This first one is from the spec 696 { 697 .message = [NSData dataWithHexString:@"d436e99569fd32a7c8a05bbc90d32c49"], 698 .seed = [NSData dataWithHexString:@"aafd12f659cae63489b479e5076ddec2f06cb58f"], 699 .encryptedMessage = [NSData dataWithHexString:@"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955"], 700 .keys = keys[0], 701 .label = @"From spec", 702 }, 703 // The next 60 are from oaep-vect.txt 704 { 705 .message = [NSData dataWithHexString:@"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"], 706 .seed = [NSData dataWithHexString:@"18b776ea21069d69776a33e96bad48e1dda0a5ef"], 707 .encryptedMessage = [NSData dataWithHexString:@"354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"], 708 .keys = keys[1], 709 .label = @"1-1", 710 }, 711 { 712 .message = [NSData dataWithHexString:@"750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"], 713 .seed = [NSData dataWithHexString:@"0cc742ce4a9b7f32f951bcb251efd925fe4fe35f"], 714 .encryptedMessage = [NSData dataWithHexString:@"640db1acc58e0568fe5407e5f9b701dff8c3c91e716c536fc7fcec6cb5b71c1165988d4a279e1577d730fc7a29932e3f00c81515236d8d8e31017a7a09df4352d904cdeb79aa583adcc31ea698a4c05283daba9089be5491f67c1a4ee48dc74bbbe6643aef846679b4cb395a352d5ed115912df696ffe0702932946d71492b44"], 715 .keys = keys[1], 716 .label = @"1-2", 717 }, 718 { 719 .message = [NSData dataWithHexString:@"d94ae0832e6445ce42331cb06d531a82b1db4baad30f746dc916df24d4e3c2451fff59a6423eb0e1d02d4fe646cf699dfd818c6e97b051"], 720 .seed = [NSData dataWithHexString:@"2514df4695755a67b288eaf4905c36eec66fd2fd"], 721 .encryptedMessage = [NSData dataWithHexString:@"423736ed035f6026af276c35c0b3741b365e5f76ca091b4e8c29e2f0befee603595aa8322d602d2e625e95eb81b2f1c9724e822eca76db8618cf09c5343503a4360835b5903bc637e3879fb05e0ef32685d5aec5067cd7cc96fe4b2670b6eac3066b1fcf5686b68589aafb7d629b02d8f8625ca3833624d4800fb081b1cf94eb"], 722 .keys = keys[1], 723 .label = @"1-3", 724 }, 725 { 726 .message = [NSData dataWithHexString:@"52e650d98e7f2a048b4f86852153b97e01dd316f346a19f67a85"], 727 .seed = [NSData dataWithHexString:@"c4435a3e1a18a68b6820436290a37cefb85db3fb"], 728 .encryptedMessage = [NSData dataWithHexString:@"45ead4ca551e662c9800f1aca8283b0525e6abae30be4b4aba762fa40fd3d38e22abefc69794f6ebbbc05ddbb11216247d2f412fd0fba87c6e3acd888813646fd0e48e785204f9c3f73d6d8239562722dddd8771fec48b83a31ee6f592c4cfd4bc88174f3b13a112aae3b9f7b80e0fc6f7255ba880dc7d8021e22ad6a85f0755"], 729 .keys = keys[1], 730 .label = @"1-4", 731 }, 732 { 733 .message = [NSData dataWithHexString:@"8da89fd9e5f974a29feffb462b49180f6cf9e802"], 734 .seed = [NSData dataWithHexString:@"b318c42df3be0f83fea823f5a7b47ed5e425a3b5"], 735 .encryptedMessage = [NSData dataWithHexString:@"36f6e34d94a8d34daacba33a2139d00ad85a9345a86051e73071620056b920e219005855a213a0f23897cdcd731b45257c777fe908202befdd0b58386b1244ea0cf539a05d5d10329da44e13030fd760dcd644cfef2094d1910d3f433e1c7c6dd18bc1f2df7f643d662fb9dd37ead9059190f4fa66ca39e869c4eb449cbdc439"], 736 .keys = keys[1], 737 .label = @"1-5", 738 }, 739 { 740 .message = [NSData dataWithHexString:@"26521050844271"], 741 .seed = [NSData dataWithHexString:@"e4ec0982c2336f3a677f6a356174eb0ce887abc2"], 742 .encryptedMessage = [NSData dataWithHexString:@"42cee2617b1ecea4db3f4829386fbd61dafbf038e180d837c96366df24c097b4ab0fac6bdf590d821c9f10642e681ad05b8d78b378c0f46ce2fad63f74e0ad3df06b075d7eb5f5636f8d403b9059ca761b5c62bb52aa45002ea70baace08ded243b9d8cbd62a68ade265832b56564e43a6fa42ed199a099769742df1539e8255"], 743 .keys = keys[1], 744 .label = @"1-6", 745 }, 746 747 { 748 .message = [NSData dataWithHexString:@"8ff00caa605c702830634d9a6c3d42c652b58cf1d92fec570beee7"], 749 .seed = [NSData dataWithHexString:@"8c407b5ec2899e5099c53e8ce793bf94e71b1782"], 750 .encryptedMessage = [NSData dataWithHexString:@"0181af8922b9fcb4d79d92ebe19815992fc0c1439d8bcd491398a0f4ad3a329a5bd9385560db532683c8b7da04e4b12aed6aacdf471c34c9cda891addcc2df3456653aa6382e9ae59b54455257eb099d562bbe10453f2b6d13c59c02e10f1f8abb5da0d0570932dacf2d0901db729d0fefcc054e70968ea540c81b04bcaefe720e"], 751 .keys = keys[2], 752 .label = @"2-1", 753 }, 754 { 755 .message = [NSData dataWithHexString:@"2d"], 756 .seed = [NSData dataWithHexString:@"b600cf3c2e506d7f16778c910d3a8b003eee61d5"], 757 .encryptedMessage = [NSData dataWithHexString:@"018759ff1df63b2792410562314416a8aeaf2ac634b46f940ab82d64dbf165eee33011da749d4bab6e2fcd18129c9e49277d8453112b429a222a8471b070993998e758861c4d3f6d749d91c4290d332c7a4ab3f7ea35ff3a07d497c955ff0ffc95006b62c6d296810d9bfab024196c7934012c2df978ef299aba239940cba10245"], 758 .keys = keys[2], 759 .label = @"2-2", 760 }, 761 { 762 .message = [NSData dataWithHexString:@"74fc88c51bc90f77af9d5e9a4a70133d4b4e0b34da3c37c7ef8e"], 763 .seed = [NSData dataWithHexString:@"a73768aeeaa91f9d8c1ed6f9d2b63467f07ccae3"], 764 .encryptedMessage = [NSData dataWithHexString:@"018802bab04c60325e81c4962311f2be7c2adce93041a00719c88f957575f2c79f1b7bc8ced115c706b311c08a2d986ca3b6a9336b147c29c6f229409ddec651bd1fdd5a0b7f610c9937fdb4a3a762364b8b3206b4ea485fd098d08f63d4aa8bb2697d027b750c32d7f74eaf5180d2e9b66b17cb2fa55523bc280da10d14be2053"], 765 .keys = keys[2], 766 .label = @"2-3", 767 }, 768 { 769 .message = [NSData dataWithHexString:@"a7eb2a5036931d27d4e891326d99692ffadda9bf7efd3e34e622c4adc085f721dfe885072c78a203b151739be540fa8c153a10f00a"], 770 .seed = [NSData dataWithHexString:@"9a7b3b0e708bd96f8190ecab4fb9b2b3805a8156"], 771 .encryptedMessage = [NSData dataWithHexString:@"00a4578cbc176318a638fba7d01df15746af44d4f6cd96d7e7c495cbf425b09c649d32bf886da48fbaf989a2117187cafb1fb580317690e3ccd446920b7af82b31db5804d87d01514acbfa9156e782f867f6bed9449e0e9a2c09bcecc6aa087636965e34b3ec766f2fe2e43018a2fddeb140616a0e9d82e5331024ee0652fc7641"], 772 .keys = keys[2], 773 .label = @"2-4", 774 }, 775 { 776 .message = [NSData dataWithHexString:@"2ef2b066f854c33f3bdcbb5994a435e73d6c6c"], 777 .seed = [NSData dataWithHexString:@"eb3cebbc4adc16bb48e88c8aec0e34af7f427fd3"], 778 .encryptedMessage = [NSData dataWithHexString:@"00ebc5f5fda77cfdad3c83641a9025e77d72d8a6fb33a810f5950f8d74c73e8d931e8634d86ab1246256ae07b6005b71b7f2fb98351218331ce69b8ffbdc9da08bbc9c704f876deb9df9fc2ec065cad87f9090b07acc17aa7f997b27aca48806e897f771d95141fe4526d8a5301b678627efab707fd40fbebd6e792a25613e7aec"], 779 .keys = keys[2], 780 .label = @"2-5", 781 }, 782 { 783 .message = [NSData dataWithHexString:@"8a7fb344c8b6cb2cf2ef1f643f9a3218f6e19bba89c0"], 784 .seed = [NSData dataWithHexString:@"4c45cf4d57c98e3d6d2095adc51c489eb50dff84"], 785 .encryptedMessage = [NSData dataWithHexString:@"010839ec20c27b9052e55befb9b77e6fc26e9075d7a54378c646abdf51e445bd5715de81789f56f1803d9170764a9e93cb78798694023ee7393ce04bc5d8f8c5a52c171d43837e3aca62f609eb0aa5ffb0960ef04198dd754f57f7fbe6abf765cf118b4ca443b23b5aab266f952326ac4581100644325f8b721acd5d04ff14ef3a"], 786 .keys = keys[2], 787 .label = @"2-6", 788 }, 789 790 { 791 .message = [NSData dataWithHexString:@"087820b569e8fa8d"], 792 .seed = [NSData dataWithHexString:@"8ced6b196290805790e909074015e6a20b0c4894"], 793 .encryptedMessage = [NSData dataWithHexString:@"026a0485d96aebd96b4382085099b962e6a2bdec3d90c8db625e14372de85e2d5b7baab65c8faf91bb5504fb495afce5c988b3f6a52e20e1d6cbd3566c5cd1f2b8318bb542cc0ea25c4aab9932afa20760eaddec784396a07ea0ef24d4e6f4d37e5052a7a31e146aa480a111bbe926401307e00f410033842b6d82fe5ce4dfae80"], 794 .keys = keys[3], 795 .label = @"3-1", 796 }, 797 { 798 .message = [NSData dataWithHexString:@"4653acaf171960b01f52a7be63a3ab21dc368ec43b50d82ec3781e04"], 799 .seed = [NSData dataWithHexString:@"b4291d6567550848cc156967c809baab6ca507f0"], 800 .encryptedMessage = [NSData dataWithHexString:@"024db89c7802989be0783847863084941bf209d761987e38f97cb5f6f1bc88da72a50b73ebaf11c879c4f95df37b850b8f65d7622e25b1b889e80fe80baca2069d6e0e1d829953fc459069de98ea9798b451e557e99abf8fe3d9ccf9096ebbf3e5255d3b4e1c6d2ecadf067a359eea86405acd47d5e165517ccafd47d6dbee4bf5"], 801 .keys = keys[3], 802 .label = @"3-2", 803 }, 804 { 805 .message = [NSData dataWithHexString:@"d94cd0e08fa404ed89"], 806 .seed = [NSData dataWithHexString:@"ce8928f6059558254008badd9794fadcd2fd1f65"], 807 .encryptedMessage = [NSData dataWithHexString:@"0239bce681032441528877d6d1c8bb28aa3bc97f1df584563618995797683844ca86664732f4bed7a0aab083aaabfb7238f582e30958c2024e44e57043b97950fd543da977c90cdde5337d618442f99e60d7783ab59ce6dd9d69c47ad1e962bec22d05895cff8d3f64ed5261d92b2678510393484990ba3f7f06818ae6ffce8a3a"], 808 .keys = keys[3], 809 .label = @"3-3", 810 }, 811 { 812 .message = [NSData dataWithHexString:@"6cc641b6b61e6f963974dad23a9013284ef1"], 813 .seed = [NSData dataWithHexString:@"6e2979f52d6814a57d83b090054888f119a5b9a3"], 814 .encryptedMessage = [NSData dataWithHexString:@"02994c62afd76f498ba1fd2cf642857fca81f4373cb08f1cbaee6f025c3b512b42c3e8779113476648039dbe0493f9246292fac28950600e7c0f32edf9c81b9dec45c3bde0cc8d8847590169907b7dc5991ceb29bb0714d613d96df0f12ec5d8d3507c8ee7ae78dd83f216fa61de100363aca48a7e914ae9f42ddfbe943b09d9a0"], 815 .keys = keys[3], 816 .label = @"3-4", 817 }, 818 { 819 .message = [NSData dataWithHexString:@"df5151832b61f4f25891fb4172f328d2eddf8371ffcfdbe997939295f30eca6918017cfda1153bf7a6af87593223"], 820 .seed = [NSData dataWithHexString:@"2d760bfe38c59de34cdc8b8c78a38e66284a2d27"], 821 .encryptedMessage = [NSData dataWithHexString:@"0162042ff6969592a6167031811a239834ce638abf54fec8b99478122afe2ee67f8c5b18b0339805bfdbc5a4e6720b37c59cfba942464c597ff532a119821545fd2e59b114e61daf71820529f5029cf524954327c34ec5e6f5ba7efcc4de943ab8ad4ed787b1454329f70db798a3a8f4d92f8274e2b2948ade627ce8ee33e43c60"], 822 .keys = keys[3], 823 .label = @"3-5", 824 }, 825 { 826 .message = [NSData dataWithHexString:@"3c3bad893c544a6d520ab022319188c8d504b7a788b850903b85972eaa18552e1134a7ad6098826254ff7ab672b3d8eb3158fac6d4cbaef1"], 827 .seed = [NSData dataWithHexString:@"f174779c5fd3cfe007badcb7a36c9b55bfcfbf0e"], 828 .encryptedMessage = [NSData dataWithHexString:@"00112051e75d064943bc4478075e43482fd59cee0679de6893eec3a943daa490b9691c93dfc0464b6623b9f3dbd3e70083264f034b374f74164e1a00763725e574744ba0b9db83434f31df96f6e2a26f6d8eba348bd4686c2238ac07c37aac3785d1c7eea2f819fd91491798ed8e9cef5e43b781b0e0276e37c43ff9492d005730"], 829 .label = @"3-6", 830 .keys = keys[3], 831 }, 832 833 { 834 .message = [NSData dataWithHexString:@"4a86609534ee434a6cbca3f7e962e76d455e3264c19f605f6e5ff6137c65c56d7fb344cd52bc93374f3d166c9f0c6f9c506bad19330972d2"], 835 .seed = [NSData dataWithHexString:@"1cac19ce993def55f98203f6852896c95ccca1f3"], 836 .encryptedMessage = [NSData dataWithHexString:@"04cce19614845e094152a3fe18e54e3330c44e5efbc64ae16886cb1869014cc5781b1f8f9e045384d0112a135ca0d12e9c88a8e4063416deaae3844f60d6e96fe155145f4525b9a34431ca3766180f70e15a5e5d8e8b1a516ff870609f13f896935ced188279a58ed13d07114277d75c6568607e0ab092fd803a223e4a8ee0b1a8"], 837 .keys = keys[4], 838 .label = @"4-1", 839 }, 840 { 841 .message = [NSData dataWithHexString:@"b0adc4f3fe11da59ce992773d9059943c03046497ee9d9f9a06df1166db46d98f58d27ec074c02eee6cbe2449c8b9fc5080c5c3f4433092512ec46aa793743c8"], 842 .seed = [NSData dataWithHexString:@"f545d5897585e3db71aa0cb8da76c51d032ae963"], 843 .encryptedMessage = [NSData dataWithHexString:@"0097b698c6165645b303486fbf5a2a4479c0ee85889b541a6f0b858d6b6597b13b854eb4f839af03399a80d79bda6578c841f90d645715b280d37143992dd186c80b949b775cae97370e4ec97443136c6da484e970ffdb1323a20847821d3b18381de13bb49aaea66530c4a4b8271f3eae172cd366e07e6636f1019d2a28aed15e"], 844 .keys = keys[4], 845 .label = @"4-2", 846 }, 847 { 848 .message = [NSData dataWithHexString:@"bf6d42e701707b1d0206b0c8b45a1c72641ff12889219a82bdea965b5e79a96b0d0163ed9d578ec9ada20f2fbcf1ea3c4089d83419ba81b0c60f3606da99"], 849 .seed = [NSData dataWithHexString:@"ad997feef730d6ea7be60d0dc52e72eacbfdd275"], 850 .encryptedMessage = [NSData dataWithHexString:@"0301f935e9c47abcb48acbbe09895d9f5971af14839da4ff95417ee453d1fd77319072bb7297e1b55d7561cd9d1bb24c1a9a37c619864308242804879d86ebd001dce5183975e1506989b70e5a83434154d5cbfd6a24787e60eb0c658d2ac193302d1192c6e622d4a12ad4b53923bca246df31c6395e37702c6a78ae081fb9d065"], 851 .keys = keys[4], 852 .label = @"4-3", 853 }, 854 { 855 .message = [NSData dataWithHexString:@"fb2ef112f5e766eb94019297934794f7be2f6fc1c58e"], 856 .seed = [NSData dataWithHexString:@"136454df5730f73c807a7e40d8c1a312ac5b9dd3"], 857 .encryptedMessage = [NSData dataWithHexString:@"02d110ad30afb727beb691dd0cf17d0af1a1e7fa0cc040ec1a4ba26a42c59d0a796a2e22c8f357ccc98b6519aceb682e945e62cb734614a529407cd452bee3e44fece8423cc19e55548b8b994b849c7ecde4933e76037e1d0ce44275b08710c68e430130b929730ed77e09b015642c5593f04e4ffb9410798102a8e96ffdfe11e4"], 858 .keys = keys[4], 859 .label = @"4-4", 860 }, 861 { 862 .message = [NSData dataWithHexString:@"28ccd447bb9e85166dabb9e5b7d1adadc4b9d39f204e96d5e440ce9ad928bc1c2284"], 863 .seed = [NSData dataWithHexString:@"bca8057f824b2ea257f2861407eef63d33208681"], 864 .encryptedMessage = [NSData dataWithHexString:@"00dbb8a7439d90efd919a377c54fae8fe11ec58c3b858362e23ad1b8a44310799066b99347aa525691d2adc58d9b06e34f288c170390c5f0e11c0aa3645959f18ee79e8f2be8d7ac5c23d061f18dd74b8c5f2a58fcb5eb0c54f99f01a83247568292536583340948d7a8c97c4acd1e98d1e29dc320e97a260532a8aa7a758a1ec2"], 865 .keys = keys[4], 866 .label = @"4-5", 867 }, 868 { 869 .message = [NSData dataWithHexString:@"f22242751ec6b1"], 870 .seed = [NSData dataWithHexString:@"2e7e1e17f647b5ddd033e15472f90f6812f3ac4e"], 871 .encryptedMessage = [NSData dataWithHexString:@"00a5ffa4768c8bbecaee2db77e8f2eec99595933545520835e5ba7db9493d3e17cddefe6a5f567624471908db4e2d83a0fbee60608fc84049503b2234a07dc83b27b22847ad8920ff42f674ef79b76280b00233d2b51b8cb2703a9d42bfbc8250c96ec32c051e57f1b4ba528db89c37e4c54e27e6e64ac69635ae887d9541619a9"], 872 .keys = keys[4], 873 .label = @"4-6", 874 }, 875 876 { 877 .message = [NSData dataWithHexString:@"af71a901e3a61d3132f0fc1fdb474f9ea6579257ffc24d164170145b3dbde8"], 878 .seed = [NSData dataWithHexString:@"44c92e283f77b9499c603d963660c87d2f939461"], 879 .encryptedMessage = [NSData dataWithHexString:@"036046a4a47d9ed3ba9a89139c105038eb7492b05a5d68bfd53accff4597f7a68651b47b4a4627d927e485eed7b4566420e8b409879e5d606eae251d22a5df799f7920bfc117b992572a53b1263146bcea03385cc5e853c9a101c8c3e1bda31a519807496c6cb5e5efb408823a352b8fa0661fb664efadd593deb99fff5ed000e5"], 880 .keys = keys[5], 881 .label = @"5-1", 882 }, 883 { 884 .message = [NSData dataWithHexString:@"a3b844a08239a8ac41605af17a6cfda4d350136585903a417a79268760519a4b4ac3303ec73f0f87cfb32399"], 885 .seed = [NSData dataWithHexString:@"cb28f5860659fceee49c3eeafce625a70803bd32"], 886 .encryptedMessage = [NSData dataWithHexString:@"03d6eb654edce615bc59f455265ed4e5a18223cbb9be4e4069b473804d5de96f54dcaaa603d049c5d94aa1470dfcd2254066b7c7b61ff1f6f6770e3215c51399fd4e34ec5082bc48f089840ad04354ae66dc0f1bd18e461a33cc1258b443a2837a6df26759aa2302334986f87380c9cc9d53be9f99605d2c9a97da7b0915a4a7ad"], 887 .keys = keys[5], 888 .label = @"5-2", 889 }, 890 { 891 .message = [NSData dataWithHexString:@"308b0ecbd2c76cb77fc6f70c5edd233fd2f20929d629f026953bb62a8f4a3a314bde195de85b5f816da2aab074d26cb6acddf323ae3b9c678ac3cf12fbdde7"], 892 .seed = [NSData dataWithHexString:@"2285f40d770482f9a9efa2c72cb3ac55716dc0ca"], 893 .encryptedMessage = [NSData dataWithHexString:@"0770952181649f9f9f07ff626ff3a22c35c462443d905d456a9fd0bff43cac2ca7a9f554e9478b9acc3ac838b02040ffd3e1847de2e4253929f9dd9ee4044325a9b05cabb808b2ee840d34e15d105a3f1f7b27695a1a07a2d73fe08ecaaa3c9c9d4d5a89ff890d54727d7ae40c0ec1a8dd86165d8ee2c6368141016a48b55b6967"], 894 .keys = keys[5], 895 .label = @"5-3", 896 }, 897 { 898 .message = [NSData dataWithHexString:@"15c5b9ee1185"], 899 .seed = [NSData dataWithHexString:@"49fa45d3a78dd10dfd577399d1eb00af7eed5513"], 900 .encryptedMessage = [NSData dataWithHexString:@"0812b76768ebcb642d040258e5f4441a018521bd96687e6c5e899fcd6c17588ff59a82cc8ae03a4b45b31299af1788c329f7dcd285f8cf4ced82606b97612671a45bedca133442144d1617d114f802857f0f9d739751c57a3f9ee400912c61e2e6992be031a43dd48fa6ba14eef7c422b5edc4e7afa04fdd38f402d1c8bb719abf"], 901 .keys = keys[5], 902 .label = @"5-4", 903 }, 904 { 905 .message = [NSData dataWithHexString:@"21026e6800c7fa728fcaaba0d196ae28d7a2ac4ffd8abce794f0985f60c8a6737277365d3fea11db8923a2029a"], 906 .seed = [NSData dataWithHexString:@"f0287413234cc5034724a094c4586b87aff133fc"], 907 .encryptedMessage = [NSData dataWithHexString:@"07b60e14ec954bfd29e60d0047e789f51d57186c63589903306793ced3f68241c743529aba6a6374f92e19e0163efa33697e196f7661dfaaa47aac6bde5e51deb507c72c589a2ca1693d96b1460381249b2cdb9eac44769f2489c5d3d2f99f0ee3c7ee5bf64a5ac79c42bd433f149be8cb59548361640595513c97af7bc2509723"], 908 .keys = keys[5], 909 .label = @"5-5", 910 }, 911 { 912 .message = [NSData dataWithHexString:@"541e37b68b6c8872b84c02"], 913 .seed = [NSData dataWithHexString:@"d9fba45c96f21e6e26d29eb2cdcb6585be9cb341"], 914 .encryptedMessage = [NSData dataWithHexString:@"08c36d4dda33423b2ed6830d85f6411ba1dcf470a1fae0ebefee7c089f256cef74cb96ea69c38f60f39abee44129bcb4c92de7f797623b20074e3d9c2899701ed9071e1efa0bdd84d4c3e5130302d8f0240baba4b84a71cc032f2235a5ff0fae277c3e8f9112bef44c9ae20d175fc9a4058bfc930ba31b02e2e4f444483710f24a"], 915 .keys = keys[5], 916 .label = @"5-6", 917 }, 918 { 919 .label = @"6-1", 920 .keys = keys[6], 921 .message = [NSData dataWithHexString:@"4046ca8baa3347ca27f49e0d81f9cc1d71be9ba517d4"], 922 .seed = [NSData dataWithHexString:@"dd0f6cfe415e88e5a469a51fbba6dfd40adb4384"], 923 .encryptedMessage = [NSData dataWithHexString:@"0630eebcd2856c24f798806e41f9e67345eda9ceda386acc9facaea1eeed06ace583709718d9d169fadf414d5c76f92996833ef305b75b1e4b95f662a20faedc3bae0c4827a8bf8a88edbd57ec203a27a841f02e43a615bab1a8cac0701de34debdef62a088089b55ec36ea7522fd3ec8d06b6a073e6df833153bc0aefd93bd1a3"], 924 }, 925 { 926 .label = @"6-2", 927 .keys = keys[6], 928 .message = [NSData dataWithHexString:@"5cc72c60231df03b3d40f9b57931bc31109f972527f28b19e7480c7288cb3c92b22512214e4be6c914792ddabdf57faa8aa7"], 929 .seed = [NSData dataWithHexString:@"8d14bd946a1351148f5cae2ed9a0c653e85ebd85"], 930 .encryptedMessage = [NSData dataWithHexString:@"0ebc37376173a4fd2f89cc55c2ca62b26b11d51c3c7ce49e8845f74e7607317c436bc8d23b9667dfeb9d087234b47bc6837175ae5c0559f6b81d7d22416d3e50f4ac533d8f0812f2db9e791fe9c775ac8b6ad0f535ad9ceb23a4a02014c58ab3f8d3161499a260f39348e714ae2a1d3443208fd8b722ccfdfb393e98011f99e63f"], 931 }, 932 { 933 .label = @"6-3", 934 .keys = keys[6], 935 .message = [NSData dataWithHexString:@"b20e651303092f4bccb43070c0f86d23049362ed96642fc5632c27db4a52e3d831f2ab068b23b149879c002f6bf3feee97591112562c"], 936 .seed = [NSData dataWithHexString:@"6c075bc45520f165c0bf5ea4c5df191bc9ef0e44"], 937 .encryptedMessage = [NSData dataWithHexString:@"0a98bf1093619394436cf68d8f38e2f158fde8ea54f3435f239b8d06b8321844202476aeed96009492480ce3a8d705498c4c8c68f01501dc81db608f60087350c8c3b0bd2e9ef6a81458b7c801b89f2e4fe99d4900ba6a4b5e5a96d865dc676c7755928794130d6280a8160a190f2df3ea7cf9aa0271d88e9e6905ecf1c5152d65"], 938 }, 939 { 940 .label = @"6-4", 941 .keys = keys[6], 942 .message = [NSData dataWithHexString:@"684e3038c5c041f7"], 943 .seed = [NSData dataWithHexString:@"3bbc3bd6637dfe12846901029bf5b0c07103439c"], 944 .encryptedMessage = [NSData dataWithHexString:@"008e7a67cacfb5c4e24bec7dee149117f19598ce8c45808fef88c608ff9cd6e695263b9a3c0ad4b8ba4c95238e96a8422b8535629c8d5382374479ad13fa39974b242f9a759eeaf9c83ad5a8ca18940a0162ba755876df263f4bd50c6525c56090267c1f0e09ce0899a0cf359e88120abd9bf893445b3cae77d3607359ae9a52f8"], 945 }, 946 { 947 .label = @"6-5", 948 .keys = keys[6], 949 .message = [NSData dataWithHexString:@"32488cb262d041d6e4dd35f987bf3ca696db1f06ac29a44693"], 950 .seed = [NSData dataWithHexString:@"b46b41893e8bef326f6759383a83071dae7fcabc"], 951 .encryptedMessage = [NSData dataWithHexString:@"00003474416c7b68bdf961c385737944d7f1f40cb395343c693cc0b4fe63b31fedf1eaeeac9ccc0678b31dc32e0977489514c4f09085f6298a9653f01aea4045ff582ee887be26ae575b73eef7f3774921e375a3d19adda0ca31aa1849887c1f42cac9677f7a2f4e923f6e5a868b38c084ef187594dc9f7f048fea2e02955384ab"], 952 }, 953 { 954 .label = @"6-6", 955 .keys = keys[6], 956 .message = [NSData dataWithHexString:@"50ba14be8462720279c306ba"], 957 .seed = [NSData dataWithHexString:@"0a2403312a41e3d52f060fbc13a67de5cf7609a7"], 958 .encryptedMessage = [NSData dataWithHexString:@"0a026dda5fc8785f7bd9bf75327b63e85e2c0fdee5dadb65ebdcac9ae1de95c92c672ab433aa7a8e69ce6a6d8897fac4ac4a54de841ae5e5bbce7687879d79634cea7a30684065c714d52409b928256bbf53eabcd5231eb7259504537399bd29164b726d33a46da701360a4168a091ccab72d44a62fed246c0ffea5b1348ab5470"], 959 }, 960 { 961 .label = @"7-1", 962 .keys = keys[7], 963 .message = [NSData dataWithHexString:@"47aae909"], 964 .seed = [NSData dataWithHexString:@"43dd09a07ff4cac71caa4632ee5e1c1daee4cd8f"], 965 .encryptedMessage = [NSData dataWithHexString:@"1688e4ce7794bba6cb7014169ecd559cede2a30b56a52b68d9fe18cf1973ef97b2a03153951c755f6294aa49adbdb55845ab6875fb3986c93ecf927962840d282f9e54ce8b690f7c0cb8bbd73440d9571d1b16cd9260f9eab4783cc482e5223dc60973871783ec27b0ae0fd47732cbc286a173fc92b00fb4ba6824647cd93c85c1"], 966 }, 967 { 968 .label = @"7-2", 969 .keys = keys[7], 970 .message = [NSData dataWithHexString:@"1d9b2e2223d9bc13bfb9f162ce735db48ba7c68f6822a0a1a7b6ae165834e7"], 971 .seed = [NSData dataWithHexString:@"3a9c3cec7b84f9bd3adecbc673ec99d54b22bc9b"], 972 .encryptedMessage = [NSData dataWithHexString:@"1052ed397b2e01e1d0ee1c50bf24363f95e504f4a03434a08fd822574ed6b9736edbb5f390db10321479a8a139350e2bd4977c3778ef331f3e78ae118b268451f20a2f01d471f5d53c566937171b2dbc2d4bde459a5799f0372d6574239b2323d245d0bb81c286b63c89a361017337e4902f88a467f4c7f244bfd5ab46437ff3b6"], 973 }, 974 { 975 .label = @"7-3", 976 .keys = keys[7], 977 .message = [NSData dataWithHexString:@"d976fc"], 978 .seed = [NSData dataWithHexString:@"76a75e5b6157a556cf8884bb2e45c293dd545cf5"], 979 .encryptedMessage = [NSData dataWithHexString:@"2155cd843ff24a4ee8badb7694260028a490813ba8b369a4cbf106ec148e5298707f5965be7d101c1049ea8584c24cd63455ad9c104d686282d3fb803a4c11c1c2e9b91c7178801d1b6640f003f5728df007b8a4ccc92bce05e41a27278d7c85018c52414313a5077789001d4f01910b72aad05d220aa14a58733a7489bc54556b"], 980 }, 981 { 982 .label = @"7-4", 983 .keys = keys[7], 984 .message = [NSData dataWithHexString:@"d4738623df223aa43843df8467534c41d013e0c803c624e263666b239bde40a5f29aeb8de79e3daa61dd0370f49bd4b013834b98212aef6b1c5ee373b3cb"], 985 .seed = [NSData dataWithHexString:@"7866314a6ad6f2b250a35941db28f5864b585859"], 986 .encryptedMessage = [NSData dataWithHexString:@"0ab14c373aeb7d4328d0aaad8c094d88b9eb098b95f21054a29082522be7c27a312878b637917e3d819e6c3c568db5d843802b06d51d9e98a2be0bf40c031423b00edfbff8320efb9171bd2044653a4cb9c5122f6c65e83cda2ec3c126027a9c1a56ba874d0fea23f380b82cf240b8cf540004758c4c77d934157a74f3fc12bfac"], 987 }, 988 { 989 .label = @"7-5", 990 .keys = keys[7], 991 .message = [NSData dataWithHexString:@"bb47231ca5ea1d3ad46c99345d9a8a61"], 992 .seed = [NSData dataWithHexString:@"b2166ed472d58db10cab2c6b000cccf10a7dc509"], 993 .encryptedMessage = [NSData dataWithHexString:@"028387a318277434798b4d97f460068df5298faba5041ba11761a1cb7316b24184114ec500257e2589ed3b607a1ebbe97a6cc2e02bf1b681f42312a33b7a77d8e7855c4a6de03e3c04643f786b91a264a0d6805e2cea91e68177eb7a64d9255e4f27e713b7ccec00dc200ebd21c2ea2bb890feae4942df941dc3f97890ed347478"], 994 }, 995 { 996 .label = @"7-6", 997 .keys = keys[7], 998 .message = [NSData dataWithHexString:@"2184827095d35c3f86f600e8e59754013296"], 999 .seed = [NSData dataWithHexString:@"52673bde2ca166c2aa46131ac1dc808d67d7d3b1"], 1000 .encryptedMessage = [NSData dataWithHexString:@"14c678a94ad60525ef39e959b2f3ba5c097a94ff912b67dbace80535c187abd47d075420b1872152bba08f7fc31f313bbf9273c912fc4c0149a9b0cfb79807e346eb332069611bec0ff9bcd168f1f7c33e77313cea454b94e2549eecf002e2acf7f6f2d2845d4fe0aab2e5a92ddf68c480ae11247935d1f62574842216ae674115"], 1001 }, 1002 { 1003 .label = @"8-1", 1004 .keys = keys[8], 1005 .message = [NSData dataWithHexString:@"050b755e5e6880f7b9e9d692a74c37aae449b31bfea6deff83747a897f6c2c825bb1adbf850a3c96994b5de5b33cbc7d4a17913a7967"], 1006 .seed = [NSData dataWithHexString:@"7706ffca1ecfb1ebee2a55e5c6e24cd2797a4125"], 1007 .encryptedMessage = [NSData dataWithHexString:@"09b3683d8a2eb0fb295b62ed1fb9290b714457b7825319f4647872af889b30409472020ad12912bf19b11d4819f49614824ffd84d09c0a17e7d17309d12919790410aa2995699f6a86dbe3242b5acc23af45691080d6b1ae810fb3e3057087f0970092ce00be9562ff4053b6262ce0caa93e13723d2e3a5ba075d45f0d61b54b61"], 1008 }, 1009 { 1010 .label = @"8-2", 1011 .keys = keys[8], 1012 .message = [NSData dataWithHexString:@"4eb68dcd93ca9b19df111bd43608f557026fe4aa1d5cfac227a3eb5ab9548c18a06dded23f81825986b2fcd71109ecef7eff88873f075c2aa0c469f69c92bc"], 1013 .seed = [NSData dataWithHexString:@"a3717da143b4dcffbc742665a8fa950585548343"], 1014 .encryptedMessage = [NSData dataWithHexString:@"2ecf15c97c5a15b1476ae986b371b57a24284f4a162a8d0c8182e7905e792256f1812ba5f83f1f7a130e42dcc02232844edc14a31a68ee97ae564a383a3411656424c5f62ddb646093c367be1fcda426cf00a06d8acb7e57776fbbd855ac3df506fc16b1d7c3f2110f3d8068e91e186363831c8409680d8da9ecd8cf1fa20ee39d"], 1015 }, 1016 { 1017 .label = @"8-3", 1018 .keys = keys[8], 1019 .message = [NSData dataWithHexString:@"8604ac56328c1ab5ad917861"], 1020 .seed = [NSData dataWithHexString:@"ee06209073cca026bb264e5185bf8c68b7739f86"], 1021 .encryptedMessage = [NSData dataWithHexString:@"4bc89130a5b2dabb7c2fcf90eb5d0eaf9e681b7146a38f3173a3d9cfec52ea9e0a41932e648a9d69344c50da763f51a03c95762131e8052254dcd2248cba40fd31667786ce05a2b7b531ac9dac9ed584a59b677c1a8aed8c5d15d68c05569e2be780bf7db638fd2bfd2a85ab276860f3777338fca989ffd743d13ee08e0ca9893f"], 1022 }, 1023 { 1024 .label = @"8-4", 1025 .keys = keys[8], 1026 .message = [NSData dataWithHexString:@"fdda5fbf6ec361a9d9a4ac68af216a0686f438b1e0e5c36b955f74e107f39c0dddcc"], 1027 .seed = [NSData dataWithHexString:@"990ad573dc48a973235b6d82543618f2e955105d"], 1028 .encryptedMessage = [NSData dataWithHexString:@"2e456847d8fc36ff0147d6993594b9397227d577752c79d0f904fcb039d4d812fea605a7b574dd82ca786f93752348438ee9f5b5454985d5f0e1699e3e7ad175a32e15f03deb042ab9fe1dd9db1bb86f8c089ccb45e7ef0c5ee7ca9b7290ca6b15bed47039788a8a93ff83e0e8d6244c71006362deef69b6f416fb3c684383fbd0"], 1029 }, 1030 { 1031 .label = @"8-5", 1032 .keys = keys[8], 1033 .message = [NSData dataWithHexString:@"4a5f4914bee25de3c69341de07"], 1034 .seed = [NSData dataWithHexString:@"ecc63b28f0756f22f52ac8e6ec1251a6ec304718"], 1035 .encryptedMessage = [NSData dataWithHexString:@"1fb9356fd5c4b1796db2ebf7d0d393cc810adf6145defc2fce714f79d93800d5e2ac211ea8bbecca4b654b94c3b18b30dd576ce34dc95436ef57a09415645923359a5d7b4171ef22c24670f1b229d3603e91f76671b7df97e7317c97734476d5f3d17d21cf82b5ba9f83df2e588d36984fd1b584468bd23b2e875f32f68953f7b2"], 1036 }, 1037 { 1038 .label = @"8-6", 1039 .keys = keys[8], 1040 .message = [NSData dataWithHexString:@"8e07d66f7b880a72563abcd3f35092bc33409fb7f88f2472be"], 1041 .seed = [NSData dataWithHexString:@"3925c71b362d40a0a6de42145579ba1e7dd459fc"], 1042 .encryptedMessage = [NSData dataWithHexString:@"3afd9c6600147b21798d818c655a0f4c9212db26d0b0dfdc2a7594ccb3d22f5bf1d7c3e112cd73fc7d509c7a8bafdd3c274d1399009f9609ec4be6477e453f075aa33db382870c1c3409aef392d7386ae3a696b99a94b4da0589447e955d16c98b17602a59bd736279fcd8fb280c4462d590bfa9bf13fed570eafde97330a2c210"], 1043 }, 1044 { 1045 .label = @"9-1", 1046 .keys = keys[9], 1047 .message = [NSData dataWithHexString:@"f735fd55ba92592c3b52b8f9c4f69aaa1cbef8fe88add095595412467f9cf4ec0b896c59eda16210e7549c8abb10cdbc21a12ec9b6b5b8fd2f10399eb6"], 1048 .seed = [NSData dataWithHexString:@"8ec965f134a3ec9931e92a1ca0dc8169d5ea705c"], 1049 .encryptedMessage = [NSData dataWithHexString:@"267bcd118acab1fc8ba81c85d73003cb8610fa55c1d97da8d48a7c7f06896a4db751aa284255b9d36ad65f37653d829f1b37f97b8001942545b2fc2c55a7376ca7a1be4b1760c8e05a33e5aa2526b8d98e317088e7834c755b2a59b12631a182c05d5d43ab1779264f8456f515ce57dfdf512d5493dab7b7338dc4b7d78db9c091ac3baf537a69fc7f549d979f0eff9a94fda4169bd4d1d19a69c99e33c3b55490d501b39b1edae118ff6793a153261584d3a5f39f6e682e3d17c8cd1261fa72"], 1050 }, 1051 { 1052 .label = @"9-2", 1053 .keys = keys[9], 1054 .message = [NSData dataWithHexString:@"81b906605015a63aabe42ddf11e1978912f5404c7474b26dce3ed482bf961ecc818bf420c54659"], 1055 .seed = [NSData dataWithHexString:@"ecb1b8b25fa50cdab08e56042867f4af5826d16c"], 1056 .encryptedMessage = [NSData dataWithHexString:@"93ac9f0671ec29acbb444effc1a5741351d60fdb0e393fbf754acf0de49761a14841df7772e9bc82773966a1584c4d72baea00118f83f35cca6e537cbd4d811f5583b29783d8a6d94cd31be70d6f526c10ff09c6fa7ce069795a3fcd0511fd5fcb564bcc80ea9c78f38b80012539d8a4ddf6fe81e9cddb7f50dbbbbcc7e5d86097ccf4ec49189fb8bf318be6d5a0715d516b49af191258cd32dc833ce6eb4673c03a19bbace88cc54895f636cc0c1ec89096d11ce235a265ca1764232a689ae8"], 1057 }, 1058 { 1059 .label = @"9-3", 1060 .keys = keys[9], 1061 .message = [NSData dataWithHexString:@"fd326429df9b890e09b54b18b8f34f1e24"], 1062 .seed = [NSData dataWithHexString:@"e89bb032c6ce622cbdb53bc9466014ea77f777c0"], 1063 .encryptedMessage = [NSData dataWithHexString:@"81ebdd95054b0c822ef9ad7693f5a87adfb4b4c4ce70df2df84ed49c04da58ba5fc20a19e1a6e8b7a3900b22796dc4e869ee6b42792d15a8eceb56c09c69914e813cea8f6931e4b8ed6f421af298d595c97f4789c7caa612c7ef360984c21b93edc5401068b5af4c78a8771b984d53b8ea8adf2f6a7d4a0ba76c75e1dd9f658f20ded4a46071d46d7791b56803d8fea7f0b0f8e41ae3f09383a6f9585fe7753eaaffd2bf94563108beecc207bbb535f5fcc705f0dde9f708c62f49a9c90371d3"], 1064 }, 1065 { 1066 .label = @"9-4", 1067 .keys = keys[9], 1068 .message = [NSData dataWithHexString:@"f1459b5f0c92f01a0f723a2e5662484d8f8c0a20fc29dad6acd43bb5f3effdf4e1b63e07fdfe6628d0d74ca19bf2d69e4a0abf86d293925a796772f8088e"], 1069 .seed = [NSData dataWithHexString:@"606f3b99c0b9ccd771eaa29ea0e4c884f3189ccc"], 1070 .encryptedMessage = [NSData dataWithHexString:@"bcc35f94cde66cb1136625d625b94432a35b22f3d2fa11a613ff0fca5bd57f87b902ccdc1cd0aebcb0715ee869d1d1fe395f6793003f5eca465059c88660d446ff5f0818552022557e38c08a67ead991262254f10682975ec56397768537f4977af6d5f6aaceb7fb25dec5937230231fd8978af49119a29f29e424ab8272b47562792d5c94f774b8829d0b0d9f1a8c9eddf37574d5fa248eefa9c5271fc5ec2579c81bdd61b410fa61fe36e424221c113addb275664c801d34ca8c6351e4a858"], 1071 }, 1072 { 1073 .label = @"9-5", 1074 .keys = keys[9], 1075 .message = [NSData dataWithHexString:@"53e6e8c729d6f9c319dd317e74b0db8e4ccca25f3c8305746e137ac63a63ef3739e7b595abb96e8d55e54f7bd41ab433378ffb911d"], 1076 .seed = [NSData dataWithHexString:@"fcbc421402e9ecabc6082afa40ba5f26522c840e"], 1077 .encryptedMessage = [NSData dataWithHexString:@"232afbc927fa08c2f6a27b87d4a5cb09c07dc26fae73d73a90558839f4fd66d281b87ec734bce237ba166698ed829106a7de6942cd6cdce78fed8d2e4d81428e66490d036264cef92af941d3e35055fe3981e14d29cbb9a4f67473063baec79a1179f5a17c9c1832f2838fd7d5e59bb9659d56dce8a019edef1bb3accc697cc6cc7a778f60a064c7f6f5d529c6210262e003de583e81e3167b89971fb8c0e15d44fffef89b53d8d64dd797d159b56d2b08ea5307ea12c241bd58d4ee278a1f2e"], 1078 }, 1079 { 1080 .label = @"9-6", 1081 .keys = keys[9], 1082 .message = [NSData dataWithHexString:@"b6b28ea2198d0c1008bc64"], 1083 .seed = [NSData dataWithHexString:@"23aade0e1e08bb9b9a78d2302a52f9c21b2e1ba2"], 1084 .encryptedMessage = [NSData dataWithHexString:@"438cc7dc08a68da249e42505f8573ba60e2c2773d5b290f4cf9dff718e842081c383e67024a0f29594ea987b9d25e4b738f285970d195abb3a8c8054e3d79d6b9c9a8327ba596f1259e27126674766907d8d582ff3a8476154929adb1e6d1235b2ccb4ec8f663ba9cc670a92bebd853c8dbf69c6436d016f61add836e94732450434207f9fd4c43dec2a12a958efa01efe2669899b5e604c255c55fb7166de5589e369597bb09168c06dd5db177e06a1740eb2d5c82faeca6d92fcee9931ba9f"], 1085 }, 1086 { 1087 .label = @"10-1", 1088 .keys = keys[10], 1089 .message = [NSData dataWithHexString:@"8bba6bf82a6c0f86d5f1756e97956870b08953b06b4eb205bc1694ee"], 1090 .seed = [NSData dataWithHexString:@"47e1ab7119fee56c95ee5eaad86f40d0aa63bd33"], 1091 .encryptedMessage = [NSData dataWithHexString:@"53ea5dc08cd260fb3b858567287fa91552c30b2febfba213f0ae87702d068d19bab07fe574523dfb42139d68c3c5afeee0bfe4cb7969cbf382b804d6e61396144e2d0e60741f8993c3014b58b9b1957a8babcd23af854f4c356fb1662aa72bfcc7e586559dc4280d160c126785a723ebeebeff71f11594440aaef87d10793a8774a239d4a04c87fe1467b9daf85208ec6c7255794a96cc29142f9a8bd418e3c1fd67344b0cd0829df3b2bec60253196293c6b34d3f75d32f213dd45c6273d505adf4cced1057cb758fc26aeefa441255ed4e64c199ee075e7f16646182fdb464739b68ab5daff0e63e9552016824f054bf4d3c8c90a97bb6b6553284eb429fcc"], 1092 }, 1093 { 1094 .label = @"10-2", 1095 .keys = keys[10], 1096 .message = [NSData dataWithHexString:@"e6ad181f053b58a904f2457510373e57"], 1097 .seed = [NSData dataWithHexString:@"6d17f5b4c1ffac351d195bf7b09d09f09a4079cf"], 1098 .encryptedMessage = [NSData dataWithHexString:@"a2b1a430a9d657e2fa1c2bb5ed43ffb25c05a308fe9093c01031795f5874400110828ae58fb9b581ce9dddd3e549ae04a0985459bde6c626594e7b05dc4278b2a1465c1368408823c85e96dc66c3a30983c639664fc4569a37fe21e5a195b5776eed2df8d8d361af686e750229bbd663f161868a50615e0c337bec0ca35fec0bb19c36eb2e0bbcc0582fa1d93aacdb061063f59f2ce1ee43605e5d89eca183d2acdfe9f81011022ad3b43a3dd417dac94b4e11ea81b192966e966b182082e71964607b4f8002f36299844a11f2ae0faeac2eae70f8f4f98088acdcd0ac556e9fccc511521908fad26f04c64201450305778758b0538bf8b5bb144a828e629795"], 1099 }, 1100 { 1101 .label = @"10-3", 1102 .keys = keys[10], 1103 .message = [NSData dataWithHexString:@"510a2cf60e866fa2340553c94ea39fbc256311e83e94454b4124"], 1104 .seed = [NSData dataWithHexString:@"385387514deccc7c740dd8cdf9daee49a1cbfd54"], 1105 .encryptedMessage = [NSData dataWithHexString:@"9886c3e6764a8b9a84e84148ebd8c3b1aa8050381a78f668714c16d9cfd2a6edc56979c535d9dee3b44b85c18be8928992371711472216d95dda98d2ee8347c9b14dffdff84aa48d25ac06f7d7e65398ac967b1ce90925f67dce049b7f812db0742997a74d44fe81dbe0e7a3feaf2e5c40af888d550ddbbe3bc20657a29543f8fc2913b9bd1a61b2ab2256ec409bbd7dc0d17717ea25c43f42ed27df8738bf4afc6766ff7aff0859555ee283920f4c8a63c4a7340cbafddc339ecdb4b0515002f96c932b5b79167af699c0ad3fccfdf0f44e85a70262bf2e18fe34b850589975e867ff969d48eabf212271546cdc05a69ecb526e52870c836f307bd798780ede"], 1106 }, 1107 { 1108 .label = @"10-4", 1109 .keys = keys[10], 1110 .message = [NSData dataWithHexString:@"bcdd190da3b7d300df9a06e22caae2a75f10c91ff667b7c16bde8b53064a2649a94045c9"], 1111 .seed = [NSData dataWithHexString:@"5caca6a0f764161a9684f85d92b6e0ef37ca8b65"], 1112 .encryptedMessage = [NSData dataWithHexString:@"6318e9fb5c0d05e5307e1683436e903293ac4642358aaa223d7163013aba87e2dfda8e60c6860e29a1e92686163ea0b9175f329ca3b131a1edd3a77759a8b97bad6a4f8f4396f28cf6f39ca58112e48160d6e203daa5856f3aca5ffed577af499408e3dfd233e3e604dbe34a9c4c9082de65527cac6331d29dc80e0508a0fa7122e7f329f6cca5cfa34d4d1da417805457e008bec549e478ff9e12a763c477d15bbb78f5b69bd57830fc2c4ed686d79bc72a95d85f88134c6b0afe56a8ccfbc855828bb339bd17909cf1d70de3335ae07039093e606d655365de6550b872cd6de1d440ee031b61945f629ad8a353b0d40939e96a3c450d2a8d5eee9f678093c8"], 1113 }, 1114 { 1115 .label = @"10-5", 1116 .keys = keys[10], 1117 .message = [NSData dataWithHexString:@"a7dd6c7dc24b46f9dd5f1e91ada4c3b3df947e877232a9"], 1118 .seed = [NSData dataWithHexString:@"95bca9e3859894b3dd869fa7ecd5bbc6401bf3e4"], 1119 .encryptedMessage = [NSData dataWithHexString:@"75290872ccfd4a4505660d651f56da6daa09ca1301d890632f6a992f3d565cee464afded40ed3b5be9356714ea5aa7655f4a1366c2f17c728f6f2c5a5d1f8e28429bc4e6f8f2cff8da8dc0e0a9808e45fd09ea2fa40cb2b6ce6ffff5c0e159d11b68d90a85f7b84e103b09e682666480c657505c0929259468a314786d74eab131573cf234bf57db7d9e66cc6748192e002dc0deea930585f0831fdcd9bc33d51f79ed2ffc16bcf4d59812fcebcaa3f9069b0e445686d644c25ccf63b456ee5fa6ffe96f19cdf751fed9eaf35957754dbf4bfea5216aa1844dc507cb2d080e722eba150308c2b5ff1193620f1766ecf4481bafb943bd292877f2136ca494aba0"], 1120 }, 1121 { 1122 .label = @"10-6", 1123 .keys = keys[10], 1124 .message = [NSData dataWithHexString:@"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac"], 1125 .seed = [NSData dataWithHexString:@"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32"], 1126 .encryptedMessage = [NSData dataWithHexString:@"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46"], 1127 }, 1128 1129 }; 1130 1131 int max_cycles = 100; 1132 if (!getenv("SUBMISSION_TEST")) { 1133 max_cycles = 10; 1134 CFfprintf(stderr, "Running the far faster but far less reliable fast test.\nSet the SUBMISSION_TEST environment variable for full testing\n"); 1135 } 1136 1137 for (int j = 0; j < max_cycles; j++) { 1138 NSLog(@"Cycle %d", j); 1139 for (i = 0; i < sizeof(tests)/sizeof(KAT); i++) { 1140 NSLog(@"test#%d %@ L(IN)=%lu, L(OUT)=%lu", i, tests[i].label, (unsigned long)[tests[i].message length], (unsigned long)[tests[i].encryptedMessage length]); 1141 CFErrorRef err = NULL; 1142 1143 SecTransformRef encryptor = SecEncryptTransformCreate(tests[i].keys.pubKey, &err); 1144 1145 SecTransformSetAttribute(encryptor, kSecTransformInputAttributeName, tests[i].message, &err); 1146 SecTransformSetAttribute(encryptor, kSecPaddingKey, kSecPaddingOAEPKey, &err); 1147 SecTransformSetAttribute(encryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, &err); 1148 SecTransformSetAttribute(encryptor, CFSTR("FixedSeedForOAEPTesting"), tests[i].seed, &err); 1149 1150 CFTypeRef encryptedData = SecTransformExecute(encryptor, &err); 1151 STAssertNotNil((id)encryptedData, @"Expected to get encrypted data"); 1152 STAssertNil((NSError*)err, @"Expected no error, got err=%@", err); 1153 // Can't support "seed" with commoncrypto, just check round trip. 1154 //STAssertEqualObjects((id)encryptedData, (id)tests[i].encryptedMessage, @"encrypted data should have matched test vector (%@) data", tests[i].label); 1155 CFRelease(encryptor); 1156 1157 SecTransformRef decryptor = SecDecryptTransformCreate(tests[i].keys.privKey, NULL); 1158 SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, tests[i].encryptedMessage, NULL); 1159 // XXX: totally round trip, not even partial KAT (KAT can't really be done on OAEP 1160 // without supporitng settign the seed externally) 1161 SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, encryptedData, NULL); 1162 SecTransformSetAttribute(decryptor, kSecPaddingKey, kSecPaddingOAEPKey, NULL); 1163 SecTransformSetAttribute(decryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, NULL); 1164 CFTypeRef decryptedData = SecTransformExecute(decryptor, &err); 1165 STAssertNil((id)err, @"Expected no error, got: %@", err); 1166 STAssertNotNil((id)decryptedData, @"Expected to get decrypted data"); 1167 STAssertEqualObjects((id)decryptedData, tests[i].message, @"Expected decrypted data to match original message (%@)", tests[i].label); 1168 CFRelease(decryptor); 1169 } 1170 } 1171 1172 return; 1173} 1174 1175-(void)testNoSignKeyMakesError 1176{ 1177 NSData *data = [NSData dataWithBytes:"" length:1]; 1178 1179 struct test_case { 1180 NSString *name; 1181 CFErrorRef createError; 1182 SecTransformRef transform; 1183 } test_cases[] = { 1184 { 1185 .name = @"Sign", 1186 .createError = NULL, 1187 .transform = SecSignTransformCreate(NULL, &(test_cases[0].createError)) 1188 }, 1189 { 1190 .name = @"Verify", 1191 .createError = NULL, 1192 .transform = SecVerifyTransformCreate(NULL, (CFDataRef)data, &(test_cases[1].createError)) 1193 } 1194 }; 1195 1196 for(int i = 0; i < sizeof(test_cases) / sizeof(test_case); i++) { 1197 struct test_case *test = test_cases + i; 1198 STAssertNil((id)test->createError, @"Testing %@, unexpected error: %@", test->name, test->createError); 1199 STAssertNotNil((id)test->transform, @"Didn't manage to create transform for %@", test->name); 1200 if (!test->transform) { 1201 continue; 1202 } 1203 1204 __block CFErrorRef err = NULL; 1205 SecTransformSetAttribute(test->transform, kSecTransformInputAttributeName, data, &err); 1206 STAssertNil((id)err, @"Error setting input for %@: %@", test->name, err); 1207 1208 dispatch_group_t execute_done = dispatch_group_create(); 1209 dispatch_group_enter(execute_done); 1210 1211 SecTransformExecuteAsync(test->transform, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) { 1212 if (error) { 1213 err = error; 1214 } 1215 if (isFinal) { 1216 dispatch_group_leave(execute_done); 1217 } 1218 }); 1219 1220 STAssertFalse(dispatch_group_wait(execute_done, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)), @"Timeout waiting for %@ transform", test->name); 1221 STAssertErrorHas((id)err, @"missing required attributes?:.*KEY", @"Unexpected error during %@ test, expected one about missing keys: %@", test->name, err); 1222 dispatch_group_notify(execute_done, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(void) { 1223 dispatch_release(execute_done); 1224 }); 1225 } 1226} 1227 1228-(void)testHMAC 1229{ 1230 // make the data for the key and the data to be HMAC'd 1231 CFDataRef hmacData = CFDataCreate(NULL, (u_int8_t*) gHMACText, strlen(gHMACText)); 1232 CFDataRef hmacKey = CFDataCreate(NULL, (u_int8_t*) gHMACKey, strlen(gHMACKey)); 1233 SecTransformRef hmacRef; 1234 CFErrorRef error = NULL; 1235 CFDataRef result; 1236 CFDataRef rightAnswer; 1237 CFComparisonResult ok; 1238 1239 // create the object 1240 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA1, 20, &error); 1241 STAssertNil((id) error, @"Unexpected error returned."); 1242 1243 // set the key 1244 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error); 1245 STAssertNil((id) error, @"Unexpected error returned."); 1246 1247 // digest the data 1248 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error); 1249 STAssertNil((id) error, @"Unexpected error returned."); 1250 1251 result = (CFDataRef) SecTransformExecute(hmacRef, &error); 1252 if (error) 1253 { 1254 CFShow(error); 1255 STAssertNil((id) error, @"Unexpected error returned."); 1256 CFRelease(error); 1257 } 1258 1259 STAssertNotNil((id) result, @"No data returned for SHA1"); 1260 1261 // check to make sure we got the right answer 1262 rightAnswer = CFDataCreate(NULL, gSHA1HMAC, sizeof(gSHA1HMAC)); 1263 ok = CFEqual(rightAnswer, result); 1264 CFRelease(rightAnswer); 1265 CFRelease(hmacRef); 1266 CFRelease(result); 1267 1268 if (error) 1269 { 1270 CFRelease(error); 1271 } 1272 1273 STAssertTrue(ok, @"Digest returned incorrect HMACSHA1 result."); 1274 1275 //+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+ 1276 1277 // create the object 1278 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA2, 256, &error); 1279 STAssertNil((id) error, @"Unexpected error returned."); 1280 1281 // set the key 1282 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error); 1283 STAssertNil((id) error, @"Unexpected error returned."); 1284 1285 // digest the data 1286 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error); 1287 STAssertNil((id) error, @"Unexpected error returned."); 1288 1289 result = (CFDataRef) SecTransformExecute(hmacRef, &error); 1290 if (error != nil) 1291 { 1292 CFShow(error); 1293 STAssertNil((id) error, @"Unexpected error returned."); 1294 CFRelease(error); 1295 } 1296 1297 STAssertNotNil((id) result, @"No data returned for SHA256"); 1298 1299 rightAnswer = CFDataCreate(NULL, gSHA256HMAC, sizeof(gSHA256HMAC)); 1300 ok = CFEqual(result, rightAnswer); 1301 1302 CFRelease(rightAnswer); 1303 CFRelease(hmacRef); 1304 1305 CFRelease(hmacData); 1306 CFRelease(hmacKey); 1307 CFRelease(result); 1308 1309 STAssertTrue(ok, @"Digest returned incorrect HMACSHA256 result."); 1310} 1311 1312 1313 1314-(void)echoParams:(NSString*)p1 p2:(NSString*)p2 1315{ 1316} 1317 1318-(void)testReadStreamTransform 1319{ 1320 // point to our test data 1321 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/usr/share/dict/words"), kCFURLPOSIXPathStyle, false); 1322 FSRef force_resolve; 1323 STAssertTrue(CFURLGetFSRef(url, &force_resolve), @"Expected to create FSRef from %@", url); 1324 CFURLRef resolved_url = CFURLCreateFromFSRef(NULL, &force_resolve); 1325 CFNumberRef size_on_disk = NULL; 1326 CFURLCopyResourcePropertyForKey(resolved_url, kCFURLFileSizeKey, &size_on_disk, NULL); 1327 STAssertNotNil((id)size_on_disk, @"Expected to fetch size"); 1328 1329 CFReadStreamRef readStreamRef = CFReadStreamCreateWithFile(NULL, url); 1330 SecTransformRef transform = SecTransformCreateReadTransformWithReadStream(readStreamRef); 1331 STAssertNotNil((id) transform, @"Returned transform should not be nil."); 1332 1333 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); 1334 dispatch_queue_t queue = dispatch_queue_create("ReadStream queue", NULL); 1335 __block ssize_t bytes_presented = 0; 1336 1337 SecTransformExecuteAsync(transform, queue, 1338 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) 1339 { 1340 if (message) 1341 { 1342 bytes_presented += CFDataGetLength((CFDataRef)message); 1343 } 1344 if (isFinal) 1345 { 1346 STAssertNil((id)error, @"Unexpected error!"); 1347 dispatch_semaphore_signal(waitSemaphore); 1348 } 1349 }); 1350 1351 dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER); 1352 NSNumber *size_via_stream = [NSNumber numberWithLongLong:bytes_presented]; 1353 STAssertEqualObjects(size_via_stream, (NSNumber*)size_on_disk, @"Expected sizes to match"); 1354 CFRelease(size_on_disk); 1355 1356 dispatch_release(queue); 1357 dispatch_release(waitSemaphore); 1358 CFRelease(transform); 1359 CFRelease(readStreamRef); 1360 CFRelease(url); 1361 CFRelease(resolved_url); 1362} 1363 1364-(void)testMGF 1365{ 1366 UInt8 raw_seed[] = {0xaa, 0xfd, 0x12, 0xf6, 0x59, 0xca, 0xe6, 0x34, 0x89, 0xb4, 0x79, 0xe5, 0x07, 0x6d, 0xde, 0xc2, 0xf0, 0x6c, 0xb5, 0x8f}; 1367 UInt8 raw_mgf107[] = {0x06, 0xe1, 0xde, 0xb2, 0x36, 0x9a, 0xa5, 0xa5, 0xc7, 0x07, 0xd8, 0x2c, 0x8e, 0x4e, 0x93, 0x24, 0x8a, 0xc7, 0x83, 0xde, 0xe0, 0xb2, 0xc0, 0x46, 0x26, 0xf5, 0xaf, 0xf9, 0x3e, 0xdc, 0xfb, 0x25, 0xc9, 0xc2, 0xb3, 0xff, 0x8a, 0xe1, 0x0e, 0x83, 0x9a, 0x2d, 0xdb, 0x4c, 0xdc, 0xfe, 0x4f, 0xf4, 0x77, 0x28, 0xb4, 0xa1, 0xb7, 0xc1, 0x36, 0x2b, 0xaa, 0xd2, 0x9a, 0xb4, 0x8d, 0x28, 0x69, 0xd5, 0x02, 0x41, 0x21, 0x43, 0x58, 0x11, 0x59, 0x1b, 0xe3, 0x92, 0xf9, 0x82, 0xfb, 0x3e, 0x87, 0xd0, 0x95, 0xae, 0xb4, 0x04, 0x48, 0xdb, 0x97, 0x2f, 0x3a, 0xc1, 0x4e, 0xaf, 0xf4, 0x9c, 0x8c, 0x3b, 0x7c, 0xfc, 0x95, 0x1a, 0x51, 0xec, 0xd1, 0xdd, 0xe6, 0x12, 0x64}; 1368 CFDataRef seed = CFDataCreate(NULL, raw_seed, sizeof(raw_seed)); 1369 CFDataRef mgf107 = CFDataCreate(NULL, raw_mgf107, sizeof(raw_mgf107)); 1370 CFErrorRef err = NULL; 1371 1372 SecTransformRef mgfTransform = SecCreateMaskGenerationFunctionTransform(NULL, 107, &err); 1373 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err); 1374 err = NULL; 1375 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, seed, &err); 1376 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err); 1377 err = NULL; 1378 CFDataRef mgfOutput = (CFDataRef)SecTransformExecute(mgfTransform, &err); 1379 STAssertNotNil((id)mgfOutput, @"Expected output from mgf, got error %@", err); 1380 STAssertEqualObjects((id)mgfOutput, (id)mgf107, @"Expected matching output"); 1381 1382 CFRelease(mgfTransform); 1383 // XXX: leak test?? 1384 1385 UInt8 raw_maskedDB[] = {0xdc, 0xd8, 0x7d, 0x5c, 0x68, 0xf1, 0xee, 0xa8, 0xf5, 0x52, 0x67, 0xc3, 0x1b, 0x2e, 0x8b, 0xb4, 0x25, 0x1f, 0x84, 0xd7, 0xe0, 0xb2, 0xc0, 0x46, 0x26, 0xf5, 0xaf, 0xf9, 0x3e, 0xdc, 0xfb, 0x25, 0xc9, 0xc2, 0xb3, 0xff, 0x8a, 0xe1, 0x0e, 0x83, 0x9a, 0x2d, 0xdb, 0x4c, 0xdc, 0xfe, 0x4f, 0xf4, 0x77, 0x28, 0xb4, 0xa1, 0xb7, 0xc1, 0x36, 0x2b, 0xaa, 0xd2, 0x9a, 0xb4, 0x8d, 0x28, 0x69, 0xd5, 0x02, 0x41, 0x21, 0x43, 0x58, 0x11, 0x59, 0x1b, 0xe3, 0x92, 0xf9, 0x82, 0xfb, 0x3e, 0x87, 0xd0, 0x95, 0xae, 0xb4, 0x04, 0x48, 0xdb, 0x97, 0x2f, 0x3a, 0xc1, 0x4f, 0x7b, 0xc2, 0x75, 0x19, 0x52, 0x81, 0xce, 0x32, 0xd2, 0xf1, 0xb7, 0x6d, 0x4d, 0x35, 0x3e, 0x2d}; 1386 1387 UInt8 raw_mgf20[] = {0x41, 0x87, 0x0b, 0x5a, 0xb0, 0x29, 0xe6, 0x57, 0xd9, 0x57, 0x50, 0xb5, 0x4c, 0x28, 0x3c, 0x08, 0x72, 0x5d, 0xbe, 0xa9}; 1388 CFDataRef maskedDB = CFDataCreate(NULL, raw_maskedDB, sizeof(raw_maskedDB)); 1389 CFDataRef mgf20 = CFDataCreate(NULL, raw_mgf20, sizeof(raw_mgf20)); 1390 err = NULL; 1391 1392 mgfTransform = SecCreateMaskGenerationFunctionTransform(kSecDigestSHA1, 20, &err); 1393 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err); 1394 err = NULL; 1395 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, maskedDB, &err); 1396 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err); 1397 err = NULL; 1398 mgfOutput = (CFDataRef)SecTransformExecute(mgfTransform, &err); 1399 STAssertNotNil((id)mgfOutput, @"Expected output from mgf, got error %@", err); 1400 STAssertEqualObjects((id)mgfOutput, (id)mgf20, @"Expected matching output"); 1401} 1402 1403-(void)testAbortParams 1404{ 1405 // make a simple transform 1406 SecTransformRef a = SecNullTransformCreate(); 1407 1408 // try to abort the transform 1409 CFErrorRef errorRef = NULL; 1410 STAssertFalse(SecTransformSetAttribute(a, CFSTR("ABORT"), NULL, &errorRef), @"SecTransformSetAttribute should have returned FALSE"); 1411 STAssertNotNil((id) errorRef, @"SecTransformSetAttribute should have had an error."); 1412 if (errorRef != NULL) 1413 { 1414 CFRelease(errorRef); 1415 } 1416 1417 CFRelease(a); 1418 1419 // We have instant end of stream, it is wired directly to null_abort's ABORT. It is wired to the final drain via a delay and some other 1420 // things. If the end of stream makes it to the final drain we get an empty CFData. If the abort triggers then abort has invalidly 1421 // triggered off of a NULL value. 1422 SecGroupTransformRef test_null_abort_via_connection = SecTransformCreateGroupTransform(); 1423 SecTransformRef pass_through = SecNullTransformCreate(); 1424 SecTransformRef null_abort = SecNullTransformCreate(); 1425 1426 CFURLRef dev_null_url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/dev/null"), kCFURLPOSIXPathStyle, NO); 1427 CFReadStreamRef dev_null_stream = CFReadStreamCreateWithFile(NULL, dev_null_url); 1428 CFReadStreamOpen(dev_null_stream); 1429 CFRelease(dev_null_url); 1430 1431 SecTransformSetAttribute(pass_through, kSecTransformInputAttributeName, dev_null_stream, NULL); 1432 SecTransformConnectTransforms(pass_through, kSecTransformOutputAttributeName, null_abort, kSecTransformAbortAttributeName, test_null_abort_via_connection, NULL); 1433 1434 SecTransformRef delay_null = delay_transform(NSEC_PER_SEC / 10); 1435 SecTransformConnectTransforms(pass_through, kSecTransformOutputAttributeName, delay_null, kSecTransformInputAttributeName, test_null_abort_via_connection, NULL); 1436 SecTransformConnectTransforms(delay_null, kSecTransformOutputAttributeName, null_abort, kSecTransformInputAttributeName, test_null_abort_via_connection, NULL); 1437 1438 1439 CFErrorRef err = NULL; 1440 CFTypeRef not_null = SecTransformExecute(test_null_abort_via_connection, &err); 1441 1442 STAssertNotNil((id)not_null, @"aborted via a NULL from a connection? err=%@", err); 1443 1444 if (err) 1445 { 1446 CFRelease(err); 1447 } 1448 1449 CFRelease(test_null_abort_via_connection); 1450 CFRelease(pass_through); 1451 CFRelease(null_abort); 1452 CFRelease(delay_null); 1453 1454 CFReadStreamClose(dev_null_stream); 1455 CFRelease(dev_null_stream); 1456} 1457 1458 1459-(void)testDisconnect 1460{ 1461 SecTransformRef a = SecNullTransformCreate(); 1462 SecTransformRef b = SecNullTransformCreate(); 1463 SecTransformRef c = SecNullTransformCreate(); 1464 SecGroupTransformRef g = SecTransformCreateGroupTransform(); 1465 1466 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, g, NULL); 1467 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName, g, NULL); 1468 1469 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName); 1470 STAssertTrue(SecGroupTransformHasMember(g, a), @"A should still be in the group, but isn't"); 1471 1472 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName); 1473 STAssertFalse(SecGroupTransformHasMember(g, a), @"A should no longer be in the group, but is"); 1474 1475 CFRelease(g); 1476 CFRelease(c); 1477 CFRelease(b); 1478 CFRelease(a); 1479} 1480 1481 1482-(void)testAbort 1483{ 1484 CFStringRef abort_test_name = CFSTR("com.apple.security.unit-test.abortTest"); 1485 1486 SecTransformCreateBlock setupBlock = 1487 ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) 1488 { 1489 params->send(kSecTransformInputAttributeName, kSecTransformMetaAttributeDeferred, kCFBooleanTrue); 1490 1491 params->overrideAttribute(kSecTransformActionAttributeNotification, CFSTR("PB"), ^(SecTransformAttributeRef ah, CFTypeRef value) { 1492 // Makes sure we can shut down (via ABORT) a transform that has a pending pushback 1493 params->pushback(ah, value); 1494 return (CFTypeRef)NULL; 1495 }); 1496 }; 1497 1498 1499 SecTransformRef a; 1500 SecTransformRef dt; 1501 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 1502 1503 // make two of these transforms and link them together 1504 a = custom_transform(abort_test_name, setupBlock); 1505 STAssertNotNil((id) a, @"SecCustomTransformCreate failed"); 1506 1507 dt = delay_transform(NSEC_PER_SEC / 10); 1508 STAssertNotNil((id) dt, @"SecCustomTransformCreate failed"); 1509 1510 // connect the two transforms 1511 CFErrorRef error; 1512 1513 // hook the output up so that the abort automatically fires. 1514 SecTransformConnectTransforms(dt, kSecTransformOutputAttributeName, a, CFSTR("ABORT"), group, &error); 1515 STAssertNil((id) error, @"SecTransformConnectTransforms failed."); 1516 1517 // also hook it up to the input because the input attribute is required on a null transform 1518 SecTransformConnectTransforms(dt, CFSTR("NOVALUES"), a, kSecTransformInputAttributeName, group, &error); 1519 STAssertNil((id) error, @"SecTransformConnectTransforms failed."); 1520 1521 // pass a plain piece of data down the transform just for fun... 1522 const u_int8_t data[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4}; 1523 1524 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, data, sizeof(data), kCFAllocatorNull); 1525 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, dataRef, NULL); 1526 1527 CFStringRef str = CFStringCreateMutable(NULL, 0); 1528 SecTransformSetAttribute(a, CFSTR("PB"), str, NULL); 1529 1530 CFTypeRef er = SecTransformExecute(a, &error); 1531 1532 STAssertNil((id)er, @"Didn't expect an result from aborted transform"); 1533 STAssertNotNil((id)error, @"Expected error from execute"); 1534 1535 if (error) 1536 { 1537 CFShow(error); 1538 1539 // while we are at it, make sure that the user dictionary has the originating transform 1540 CFDictionaryRef userDictionary = CFErrorCopyUserInfo(error); 1541 STAssertNotNil((id) CFDictionaryGetValue(userDictionary, kSecTransformAbortOriginatorKey), @"Originating transform not listed."); 1542 CFRelease(error); 1543 } 1544 1545 CFRelease(a); 1546 CFRelease(dt); 1547 CFRelease(group); 1548 CFRelease(dataRef); 1549 1550/* 1551 // XXX: these should both be 1, not 3 or 4. WTF? Is this an abort issue, or a generic leak? 1552 // STAssertEquals(rc0, CFGetRetainCount(str), @"The value we sent to PB hasn't been released (value retained by pushback)"); 1553 // STAssertEquals(rc0, CFGetRetainCount(dataRef), @"The value we sent to INPUT hasn't been released"); 1554*/ 1555} 1556 1557-(void)testPreAbort { 1558 CFErrorRef error = NULL; 1559 SecTransformRef prebort = SecNullTransformCreate(); 1560 SecTransformSetAttribute(prebort, kSecTransformInputAttributeName, CFSTR("quux"), NULL); 1561 SecTransformSetAttribute(prebort, CFSTR("ABORT"), CFSTR("OOPS"), NULL); 1562 CFTypeRef er = SecTransformExecute(prebort, &error); 1563 STAssertNil((id)er, @"Didn't expect an result from pre-aborted transform"); 1564 STAssertNotNil((id)error, @"Expected error from execute of pre-aborted transform"); 1565 CFRelease(error); 1566} 1567 1568#ifdef DEBUG 1569-(void)testFireAndForget 1570{ 1571 bool isGC = false; 1572 NSGarbageCollector* gc = [NSGarbageCollector defaultCollector]; 1573 if (gc) 1574 { 1575 isGC = [gc isEnabled]; 1576 } 1577 1578 CFIndex retCount = 0; 1579 1580 // make transforms 1581 SecNullTransformRef a = SecNullTransformCreate(); 1582 SecNullTransformRef b = SecNullTransformCreate(); 1583 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 1584 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL); 1585 1586 if (!isGC) 1587 { 1588 retCount = CFGetRetainCount(group); 1589 } 1590 1591 // set up a blob of data to fire 1592 const u_int8_t data[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4}; 1593 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, data, sizeof(data), kCFAllocatorNull); 1594 SecTransformSetAttribute(a, kSecTransformInputAttributeName, dataRef, NULL); 1595 CFRelease(dataRef); 1596 1597 // make dispatch related stuff 1598 dispatch_queue_t queue = dispatch_queue_create("ffqueue", NULL); 1599 // semaphore0's job is to be signaled when we know ExecuteAsync is actually executing (so we don't sample the retain 1600 // count too soone), semaphore signals when we are about done with ExecuteAsync (I'm not sure why we need to know), 1601 // and semaphore2 is signaled to let the execute block know we are done sampling retain counts. 1602 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 1603 dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0); 1604 1605 // launch the chain 1606 SecTransformExecuteAsync(group, queue, 1607 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) 1608 { 1609 CFfprintf(stderr, "message %p, final %d\n", message, isFinal ? 1 : 0); 1610 STAssertEquals(queue, const_cast<const dispatch_queue_t>(dispatch_get_current_queue()), @"Expected to be executing on own queue, got %s", dispatch_queue_get_label(dispatch_get_current_queue())); 1611 if (isFinal) 1612 { 1613 fprintf(stderr, "Final message received.\n"); 1614 dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER); // make sure that the other chain has released its material 1615 dispatch_semaphore_signal(semaphore); 1616 } 1617 }); 1618 CFRelease(a); 1619 CFRelease(b); 1620 CFRelease(group); 1621 dispatch_semaphore_signal(semaphore2); 1622 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 1623 1624 // no crash? Life is good. 1625} 1626#endif 1627 1628-(void)testExternalSource 1629{ 1630 CFErrorRef err = NULL; 1631 SecTransformRef xs = SecExternalSourceTransformCreate(&err); 1632 SecTransformRef tee = SecNullTransformCreate(); 1633 SecTransformRef group = SecTransformCreateGroupTransform(); 1634 1635 SecTransformConnectTransforms(xs, kSecTransformOutputAttributeName, tee, kSecTransformInputAttributeName, group, &err); 1636 1637 dispatch_queue_t q = dispatch_queue_create("com.apple.security.unit-tests.test-external-source", 0); 1638 dispatch_group_t dg = dispatch_group_create(); 1639 dispatch_group_enter(dg); 1640 __block bool got_ping = false; 1641 1642 SecTransformExecuteAsync(group, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) { 1643 CFfprintf(stderr, "B: message %@, e %p, f %d\n", message ? message : (CFTypeRef)CFSTR("(NULL)"), error, isFinal); 1644 1645 if (message) { 1646 if (CFEqual(message, CFSTR("PING"))) { 1647 got_ping = true; 1648 } else { 1649 STFail(@"expected ping, got: %@", message); 1650 } 1651 } 1652 1653 if (error) { 1654 STFail(@"unexpected error: %@", error); 1655 } 1656 1657 if (isFinal) { 1658 if (!got_ping) { 1659 STFail(@"never got ping"); 1660 } 1661 dispatch_group_leave(dg); 1662 } 1663 }); 1664 1665 SecExternalSourceSetValue(tee, CFSTR("PONG"), &err); 1666 STAssertNotNil((id)err, @"Expected error setting tee"); 1667 STAssertErrorHas((id)err, @"ExternalSource", @"Error should note what should be passed in: %@", err); 1668 CFRelease(err); 1669 err = NULL; 1670 SecExternalSourceSetValue(xs, CFSTR("PING"), &err); 1671 STAssertNil((id)err, @"unexpected error setting xs: %@", err); 1672 SecExternalSourceSetValue(xs, NULL, &err); 1673 STAssertNil((id)err, @"unexpected error setting xs: %@", err); 1674 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER); 1675 1676 dispatch_release(dg); 1677 dispatch_release(q); 1678 CFRelease(xs); 1679 CFRelease(tee); 1680 CFRelease(group); 1681} 1682 1683-(void)testFindLastAndMonitor 1684{ 1685 SecNullTransformRef a = delay_transform(NSEC_PER_SEC / 10); 1686 SecNullTransformRef b = SecNullTransformCreate(); 1687 1688 SecGroupTransformRef groupRef = SecTransformCreateGroupTransform(); 1689 CFErrorRef error = NULL; 1690 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, groupRef, &error); 1691 STAssertNil((id)error, @"An error was returned when none was expected."); 1692 SecTransformSetAttribute(a, kSecTransformInputAttributeName, kCFNull, &error); 1693 STAssertNil((id)error, @"An error was returned when none was expected."); 1694 1695 1696 // get the last transform in the chain (unexecuted). It had better be b... 1697 SecTransformRef tr = SecGroupTransformFindLastTransform(groupRef); 1698 STAssertNotNil((id)tr, @"FindLastTransform returned NULL"); 1699 STAssertTrue(tr == b, @"FindLastTransform returned incorrect result"); 1700 STAssertFalse(tr == a, @"FindLastTransform returned the head of the chain"); 1701 1702 // execute the transform. This should attach an output monitor 1703 dispatch_queue_t queue = dispatch_queue_create("test delivery queue", NULL); 1704 dispatch_semaphore_t last_block_run = dispatch_semaphore_create(0L); 1705 dispatch_semaphore_t last_assert_run = dispatch_semaphore_create(0L); 1706 SecTransformExecuteAsync(groupRef, queue, 1707 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) 1708 { 1709 if (isFinal) 1710 { 1711 dispatch_semaphore_signal(last_block_run); 1712 dispatch_semaphore_wait(last_assert_run, DISPATCH_TIME_FOREVER); 1713 dispatch_release(last_assert_run); 1714 } 1715 1716 }); 1717 1718 dispatch_semaphore_wait(last_block_run, DISPATCH_TIME_FOREVER); 1719 1720 // see if the returned transform is the same now 1721 tr = SecGroupTransformFindLastTransform(groupRef); 1722 STAssertNotNil((id) tr, @"FindLastTransform returned NULL"); 1723 STAssertTrue(tr == b, @"FindLastTransform returned incorrect result"); 1724 STAssertFalse(tr == a, @"FindLastTransform returned the head of the chain"); 1725 1726 // get the monitor, it had better not be a or b 1727 tr = SecGroupTransformFindMonitor(groupRef); 1728 STAssertNotNil((id) tr, @"FindMonitor returned NULL"); 1729 STAssertFalse(tr == a, @"FindLastTransform returned the head of the chain"); 1730 STAssertFalse(tr == b, @"FindLastTransform returned the head of the chain"); 1731 1732 dispatch_semaphore_signal(last_assert_run); 1733 dispatch_release(queue); 1734 dispatch_release(last_block_run); 1735 CFRelease(a); 1736 CFRelease(b); 1737 CFRelease(groupRef); 1738} 1739 1740 1741-(void)testConnectUnsetAttributes /* <rdar://problem/7769955> Can't connect transform attributes with no setting */ 1742{ 1743 SecNullTransformRef a = SecNullTransformCreate(); 1744 SecNullTransformRef b = SecNullTransformCreate(); 1745 1746 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 1747 CFErrorRef error = NULL; 1748 SecTransformConnectTransforms(a, CFSTR("RANDOM_NAME"), b, CFSTR("RANDOM_DESTINATION"), group, &error); 1749 CFRelease(group); 1750 CFRelease(b); 1751 CFRelease(a); 1752 STAssertNil((id) error, @"An error was returned when none was expected."); 1753} 1754 1755-(void)testNoDataFlowPriorToInit /* <rdar://problem/8163542> Monitor must be attached before the data flow becomes active */ 1756{ 1757 CFStringRef name = CFSTR("com.apple.security.unit-test.flow-check"); 1758 SecTransformCreateBlock cb = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) { 1759 __block bool inited = false; 1760 __block bool saw_x_start = false; 1761 __block bool saw_null = false; 1762 __block int post_send_left = 8; 1763 SecTransformAttributeRef out_ah = params->get(kSecTransformOutputAttributeName, kSecTransformMetaAttributeRef); 1764 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("create")); 1765 1766 params->overrideTransform(kSecTransformActionStartingExecution, ^{ 1767 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("x-start")); 1768 inited = true; 1769 return (CFTypeRef)NULL; 1770 }); 1771 1772 params->overrideTransform(kSecTransformActionCanExecute, ^{ 1773 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("can-x")); 1774 return (CFTypeRef)NULL; 1775 }); 1776 1777 params->overrideAttribute(kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef ah, CFTypeRef value) { 1778 if (inited) { 1779 if (value) { 1780 if (!saw_x_start) { 1781 saw_x_start = CFStringHasPrefix((CFStringRef)value, CFSTR("x-start")); 1782 } 1783 if (saw_null) { 1784 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 88, "saw %@ after NULL", value)); 1785 } 1786 if (post_send_left--) { 1787 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("post-init")); 1788 } 1789 } else { 1790 saw_null = true; 1791 // The FIRST flow transform should not see x-start (it is the OUTPUT of the flow transform 1792 // before you in the chain), but all the other transforms should see it. 1793 if (params->get(CFSTR("FIRST"), kSecTransformMetaAttributeValue)) { 1794 if (saw_x_start) { 1795 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "saw bogus x-start on FIRST flow transform")); 1796 } else { 1797 params->send(out_ah, kSecTransformMetaAttributeValue, value); 1798 } 1799 } else { 1800 if (saw_x_start) { 1801 params->send(out_ah, kSecTransformMetaAttributeValue, value); 1802 } else { 1803 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "never saw x-start before EOS")); 1804 return (CFTypeRef)kCFNull; 1805 } 1806 } 1807 } 1808 } else { 1809 // attempting to put the value in the error string sometimes blows up, so I've left it out. 1810 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "got: value before init")); 1811 return (CFTypeRef)kCFNull; 1812 } 1813 return (CFTypeRef)value; 1814 }); 1815 }; 1816 1817 // Reliably reproduces with 100000 transforms in our group, but 1818 // not at 1000...doesn't even seem to do it at 50000. 1819 // Likely a timing issue triggered by heavy swapping. 1820 int n_transforms = 100000; 1821 1822 if (!getenv("SUBMISSION_TEST")) { 1823 n_transforms = 10000; 1824 CFfprintf(stderr, "Running the far faster but far less reliable fast test.\nSet the SUBMISSION_TEST environment variable for full testing\n"); 1825 } 1826 1827 int i; 1828 CFMutableArrayRef ta = CFArrayCreateMutable(NULL, n_transforms, &kCFTypeArrayCallBacks); 1829 CFErrorRef err = NULL; 1830 1831 for(i = 0; i < n_transforms; ++i) { 1832 SecTransformRef tr = custom_transform(name, cb); 1833 STAssertNil((id)err, @"Failure %@ creating %@ transform", err, name); 1834 CFStringRef l = CFStringCreateWithFormat(NULL, NULL, CFSTR("flow-%d"), i); 1835 SecTransformSetAttribute(tr, kSecTransformTransformName, l, &err); 1836 if (0 == i % 1000) { 1837 CFfprintf(stderr, "Created %@ of %d\n", l, n_transforms); 1838 } 1839 CFRelease(l); 1840 STAssertNil((id)err, @"Can't set name %@", err); 1841 CFArrayAppendValue(ta, tr); 1842 assert(CFArrayGetCount(ta)); 1843 assert(CFArrayGetCount(ta) == i+1); 1844 } 1845 1846 SecTransformRef prev_tr = NULL; 1847 SecTransformRef group = SecTransformCreateGroupTransform(); 1848 CFIndex cnt; 1849 1850 while ((cnt = CFArrayGetCount(ta))) { 1851 CFIndex r = arc4random() % cnt; 1852 SecTransformRef tr = CFArrayGetValueAtIndex(ta, r); 1853 if (prev_tr) { 1854 SecTransformConnectTransforms(tr, kSecTransformOutputAttributeName, prev_tr, kSecTransformInputAttributeName, group, &err); 1855 STAssertNil((id)err, @"Can't connect %@ to %@", tr, prev_tr); 1856 STAssertNotNil((id)group, @"nil group after connect"); 1857 CFRelease(prev_tr); 1858 } 1859 prev_tr = tr; 1860 CFArrayRemoveValueAtIndex(ta, r); 1861 1862 if (0 == cnt % 1000) { 1863 CFfprintf(stderr, "%d left to hook up\n", cnt); 1864 } 1865 } 1866 1867 CFTypeRef ptl = SecTransformGetAttribute(prev_tr, kSecTransformTransformName); 1868 CFfprintf(stderr, "Setting INPUT for %@\n", ptl); 1869 SecTransformSetAttribute(prev_tr, kSecTransformInputAttributeName, CFSTR("First!"), &err); 1870 STAssertNil((id)err, @"Can't set first's input? %@", err); 1871 SecTransformSetAttribute(prev_tr, CFSTR("FIRST"), kCFBooleanTrue, &err); 1872 STAssertNil((id)err, @"Can't set FIRST? %@", err); 1873 CFTypeRef r = SecTransformExecute(group, &err); 1874 STAssertNil((id)err, @"execution error: %@", err); 1875 STAssertNotNil((id)r, @"result expected from execute"); 1876 CFRelease(group); 1877 CFRelease(prev_tr); 1878} 1879 1880-(void)testNoDataDescription /* <rdar://problem/7791122> CFShow(SecCustomTransformNoData()) crashes */ 1881{ 1882 CFStringRef result = CFCopyDescription(SecTransformNoData()); // this is called under the hood in CFShow, and it doesn't dump output 1883 STAssertNotNil((id)result, @"SecTransformNoData can be formatted"); 1884 CFRelease(result); 1885} 1886 1887static SecTransformInstanceBlock KnownProblemPlumbing(CFStringRef name, 1888 SecTransformRef newTransform, 1889 SecTransformImplementationRef ref) 1890{ 1891 SecTransformInstanceBlock instanceBlock = 1892 ^{ 1893 CFErrorRef result = NULL; 1894 // At the moment fully disconnecting a transform from a group leaves it in the group, so it can't have any 1895 // kSecTransformMetaAttributeRequiresOutboundConnection=TRUE attributes (by default OUTPUT requires an outbound connection) 1896 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, 1897 kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanFalse); 1898 1899 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, 1900 ^(SecTransformAttributeRef ah, CFTypeRef value) 1901 { 1902 return (CFTypeRef)CFErrorCreate(NULL, kCFErrorDomainPOSIX, EOPNOTSUPP, NULL); 1903 }); 1904 return result; 1905 }; 1906 1907 return Block_copy(instanceBlock); 1908} 1909 1910-(void)knownProblemPlumbing // note, this test has been disconnected! 1911{ 1912 SecNullTransformRef a = SecNullTransformCreate(); 1913 CFStringRef name = CFSTR("com.apple.security.unit-test.error+outputless"); 1914 CFErrorRef err = NULL; 1915 1916 SecTransformRegister(name, &KnownProblemPlumbing, &err); 1917 1918 SecTransformRef b = SecTransformCreate(name, NULL); 1919 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 1920 1921 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL); 1922 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName); 1923 1924 1925 CFStringRef data = CFSTR("Test"); 1926 1927 SecTransformSetAttribute(a, kSecTransformInputAttributeName, data, NULL); 1928 CFTypeRef result = SecTransformExecute(a, &err); 1929 1930 STAssertEqualObjects((id)data, (id)result, @"Plumbing disconnect failed."); 1931 STAssertNil((id)err, @"Unexpected error=%@", err); 1932 CFRelease(a); 1933 CFRelease(b); 1934 CFRelease(group); 1935} 1936 1937-(void)testUnknownEncodeType { 1938 CFErrorRef err1 = NULL; 1939 CFStringRef invalid_encode_type = CFSTR("no such encoding type ☃✪"); 1940 SecTransformRef not_created = SecEncodeTransformCreate(invalid_encode_type, &err1); 1941 STAssertNil((id)not_created, @"Created encode transform with bad type"); 1942 STAssertErrorHas((NSError*)err1, @"☃✪", @"Error mentions bad encoding type: %@", err1); 1943 fprintf(stderr, "Err1 = %p\n", err1); 1944 if (err1) CFRelease(err1); 1945 err1 = NULL; 1946 1947 CFErrorRef err2 = NULL; 1948 SecTransformRef no_type_at_create = SecEncodeTransformCreate(NULL, &err2); 1949 fprintf(stderr, "Err2 = %p\n", err2); 1950 STAssertNotNil((id)no_type_at_create, @"should be able to create encoder with unset type, but got error %@", err2); 1951 1952 if (no_type_at_create) { 1953 CFErrorRef err3 = NULL; 1954 SecTransformSetAttribute(no_type_at_create, kSecTransformInputAttributeName, NULL, &err3); 1955 STAssertNil((id)err3, @"Can't set INPUT: %@", err3); 1956 if (err3) { 1957 CFRelease(err3); 1958 err3 = NULL; 1959 } 1960 STAssertTrue(SecTransformSetAttribute(no_type_at_create, kSecEncodeTypeAttribute, kSecBase32Encoding, &err3), @"Can't set encode to valid type error: %@", err3); 1961 STAssertFalse(SecTransformSetAttribute(no_type_at_create, kSecEncodeTypeAttribute, invalid_encode_type, &err3), @"Set encode to invalid type, no error signaled", err3); 1962 fprintf(stderr, "Err3 = %p\n", err3); 1963 if (err3) CFRelease(err3); 1964 1965 CFErrorRef err4 = NULL; 1966 CFTypeRef no_result = SecTransformExecute(no_type_at_create, &err4); 1967 STAssertNil((id)no_result, @"Got result when none expected %@"); 1968 STAssertNotNil((id)err4, @"No error when one expected"); 1969 fprintf(stderr, "Err4 = %p\n", err4); 1970 if (err4) CFRelease(err4); 1971 } else { 1972 STFail(@"Unable to run some tests"); 1973 } 1974 1975 CFRelease(no_type_at_create); 1976 CFRelease(invalid_encode_type); 1977} 1978 1979-(void)testNoUnderscores 1980{ 1981 SecTransformRef zt = SecEncodeTransformCreate(kSecZLibEncoding, NULL); 1982 CFErrorRef err = NULL; 1983 SecTransformSetAttribute(zt, CFSTR("_FAIL"), kCFBooleanTrue, &err); 1984 STAssertNotNil((id)err, @"Expeced an error setting _FAIL"); 1985 STAssertErrorHas((id)err, @"_FAIL", @"Expected error to contain _FAIL"); 1986 STAssertErrorHas((id)err, @"Encoder", @"Expecting error to name offending transform", err); 1987 CFTypeRef v = SecTransformGetAttribute(zt, CFSTR("_FAIL")); 1988 STAssertNil((id)v, @"Expected nil result, got v=%p", v); 1989 CFRelease(err); 1990 CFRelease(zt); 1991} 1992 1993-(void)testCanFetchDigestSizes 1994{ 1995 NSDictionary *digests = [NSDictionary dictionaryWithObjectsAndKeys: 1996 [NSNumber numberWithInt:128/8], kSecDigestMD2, 1997 [NSNumber numberWithInt:128/8], kSecDigestMD4, 1998 [NSNumber numberWithInt:128/8], kSecDigestMD5, 1999 [NSNumber numberWithInt:160/8], kSecDigestSHA1, 2000 [NSNumber numberWithInt:512/8], kSecDigestSHA2, 2001 nil]; 2002 NSData *zero = [NSData dataWithBytes:"" length:1]; 2003 2004 for (NSString *digestType in digests) { 2005 CFErrorRef err = NULL; 2006 SecTransformRef digest = SecDigestTransformCreate(digestType, 0, &err); 2007 STAssertNotNil((id)digest, @"Expected to make digest (err=%@)", err); 2008 STAssertNil((id)err, @"Unexpected error: %@", err); 2009 NSNumber *actualLength = (NSNumber*)SecTransformGetAttribute(digest, kSecDigestLengthAttribute); 2010 STAssertTrue([actualLength intValue] != 0, @"Got zero length back"); 2011 STAssertNotNil(actualLength, @"Expected to get a length"); 2012 STAssertEqualObjects(actualLength, [digests objectForKey:digestType], @"Expected lengths to match for %@", digestType); 2013 2014 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, zero, &err); 2015 STAssertNil((id)err, @"Unexpected error: %@", err); 2016 2017 NSData *output = (NSData *)SecTransformExecute(digest, &err); 2018 STAssertNil((id)err, @"Unexpected error: %@", err); 2019 STAssertNotNil((id)output, @"No output"); 2020 2021 STAssertEquals([actualLength intValue], (int)[output length], @"Actual output not expected length"); 2022 2023 [output release]; 2024 CFRelease(digest); 2025 } 2026} 2027 2028-(void)testBadTransformTypeNames 2029{ 2030 CFErrorRef error = NULL; 2031 Boolean ok = SecTransformRegister(CFSTR("Not valid: has a col..co...double dot thing"), DelayTransformBlock, &error); 2032 STAssertFalse(ok, @"Register of name with : fails"); 2033 STAssertErrorHas((id)error, @":", @"Error mentions invalid character (error=%@)", error); 2034 2035 ok = SecTransformRegister(CFSTR("Not/valid has a slash"), DelayTransformBlock, &error); 2036 STAssertFalse(ok, @"Register of name with / fails"); 2037 STAssertErrorHas((id)error, @"/", @"Error mentions invalid character (error=%@)", error); 2038 2039 ok = SecTransformRegister(CFSTR("https://NOT/VALID"), DelayTransformBlock, &error); 2040 STAssertFalse(ok, @"Register of name with : and / fails"); 2041 STAssertErrorHas((id)error, @"[:/]", @"Error mentions invalid character (error=%@)", error); 2042 2043 ok = SecTransformRegister(CFSTR("_not valid at start"), DelayTransformBlock, &error); 2044 STAssertFalse(ok, @"Register of _name fails"); 2045 STAssertErrorHas((id)error, @"_", @"Error mentions invalid character (error=%@)", error); 2046 2047 ok = SecTransformRegister(CFSTR("it is ok to have a _ after start"), DelayTransformBlock, &error); 2048 STAssertTrue(ok, @"Register of _ IN should have worked (error=%@)", error); 2049} 2050 2051-(void)testExecuteBlock { 2052 unsigned char *raw_data = (unsigned char *)"Just some bytes, you know"; 2053 //NSData *empty = [NSData dataWithBytes:NULL length:0]; 2054 NSData *data = [NSData dataWithBytes:raw_data length:strlen((const char *)raw_data)]; 2055 //NSUInteger ecnt = [empty retainCount]; 2056 2057 SecTransformRef zt = SecEncodeTransformCreate(kSecZLibEncoding, NULL); 2058 SecTransformSetAttribute(zt, kSecTransformInputAttributeName, data, NULL); 2059 dispatch_queue_t q = dispatch_queue_create("com.apple.security.testingQ", NULL); 2060 dispatch_queue_t q_sync = dispatch_queue_create("com.apple.security.testingQ_sync", NULL); 2061 dispatch_suspend((dispatch_object_t)q_sync); 2062 __block BOOL ran_block = NO; 2063 2064 SecTransformExecuteAsync(zt, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) { 2065// if ([empty length]) { 2066// NSLog(@"Empty data not so empty"); 2067// } 2068 STAssertTrue(dispatch_get_current_queue() == q, @"block dispatched to proper queue"); 2069 2070 if (!ran_block) { 2071 usleep(200); 2072 ran_block = YES; 2073 } 2074 2075 if (message == NULL) { 2076 dispatch_resume((dispatch_object_t)q_sync); 2077 } 2078 }); 2079 2080 //STAssertTrue(ecnt < [empty retainCount], @"SecTransformExecute retained block"); 2081 dispatch_sync(q_sync, ^{ }); 2082 STAssertTrue(ran_block, @"Block executed"); 2083 2084 dispatch_release(q_sync); 2085 dispatch_release(q); 2086 CFRelease(zt); 2087 2088 // test for 7735698 2089 // STAssertTrue(ecnt == [empty retainCount], @"SecTransformExecute released block"); 2090} 2091 2092static SecTransformInstanceBlock ConnectionCheck(CFStringRef name, 2093 SecTransformRef newTransform, 2094 SecTransformImplementationRef ref) 2095{ 2096 SecTransformInstanceBlock instanceBlock = 2097 ^{ 2098 CFErrorRef result = NULL; 2099 __block SecTransformMetaAttributeType dir = kSecTransformMetaAttributeValue; 2100 2101 SecTransformAttributeRef out_ah = 2102 SecTranformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef); 2103 2104 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DIRECTION"), 2105 ^(SecTransformAttributeRef ah, CFTypeRef value) 2106 { 2107 if (CFEqual(value, CFSTR("<"))) 2108 { 2109 dir = kSecTransformMetaAttributeHasInboundConnection; 2110 } 2111 else if (CFEqual(value, CFSTR(">"))) 2112 { 2113 dir = kSecTransformMetaAttributeHasOutboundConnections; 2114 } 2115 else 2116 { 2117 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unsupported direction %@, expected < or >", value); 2118 } 2119 return value; 2120 }); 2121 2122 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"), 2123 ^(SecTransformAttributeRef ah, CFTypeRef value) 2124 { 2125 if (dir != kSecTransformMetaAttributeValue) 2126 { 2127 if (value) 2128 { 2129 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, 2130 SecTranformCustomGetAttribute(ref, value, dir)); 2131 } 2132 else 2133 { 2134 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, NULL); 2135 } 2136 } 2137 else 2138 { 2139 SecTransformPushbackAttribute(ref, ah, value); 2140 } 2141 2142 return value; 2143 }); 2144 2145 return result; 2146 }; 2147 2148 return Block_copy(instanceBlock); 2149} 2150 2151-(void)testConnectionChecks { 2152 2153 CFStringRef name = CFSTR("com.apple.security.unit-test.connection-checks"); 2154 CFErrorRef error = NULL; 2155 SecTransformRegister(name, &*ConnectionCheck, &error); 2156 2157 struct test_case { 2158 NSString *attr, *dir; 2159 CFBooleanRef expect; 2160 } cases[] = { 2161 {@"INPUT", @"<", kCFBooleanTrue}, 2162 {@"OUTPUT", @">", kCFBooleanTrue}, 2163 {@"INPUT", @">", kCFBooleanFalse}, 2164 {@"OUTPUT", @"<", kCFBooleanFalse}, 2165 {@"DIRECTION", @"<", kCFBooleanFalse}, 2166 {@"DIRECTION", @">", kCFBooleanFalse}, 2167 }; 2168 2169 CFIndex i, n = sizeof(cases)/sizeof(test_case); 2170 for(i = 0; i < n; ++i) 2171 { 2172 test_case *t = cases + i; 2173 2174 SecTransformRef cct = SecTransformCreate(name, NULL); 2175 SecTransformRef tee0 = SecNullTransformCreate(); 2176 SecTransformRef tee1 = SecNullTransformCreate(); 2177 SecTransformRef group = SecTransformCreateGroupTransform(); 2178 2179 SecTransformSetAttribute(cct, CFSTR("DEBUG"), kCFBooleanTrue, NULL); 2180 SecTransformSetAttribute(tee0, CFSTR("DEBUG"), kCFBooleanTrue, NULL); 2181 SecTransformSetAttribute(tee1, CFSTR("DEBUG"), kCFBooleanTrue, NULL); 2182 2183 SecTransformSetAttribute(tee0, CFSTR("NAME"), CFSTR("tee0"), NULL); 2184 SecTransformSetAttribute(tee1, CFSTR("NAME"), CFSTR("tee1"), NULL); 2185 2186 SecTransformConnectTransforms(cct, CFSTR("OUTPUT"), tee1, CFSTR("INPUT"), group, NULL); 2187 SecTransformConnectTransforms(tee0, CFSTR("OUTPUT"), cct, CFSTR("INPUT"), group, NULL); 2188 2189 SecTransformSetAttribute(cct, CFSTR("DIRECTION"), t->dir, NULL); 2190 SecTransformSetAttribute(tee0, CFSTR("INPUT"), t->attr, NULL); 2191 CFErrorRef err = NULL; 2192 CFTypeRef r = SecTransformExecute(group, &err); 2193 STAssertNil((id)err, @"Error=%@ for case#%d", err, i); 2194 STAssertNotNil((id)r, @"Nil result for case#%d", i); 2195 STAssertEqualObjects((id)(t->expect), (id)r, @"Expected result for case#%d %@%@", i, t->dir, t->attr); 2196 2197 CFRelease(cct); 2198 CFRelease(tee0); 2199 CFRelease(tee1); 2200 CFRelease(group); 2201 } 2202 2203} 2204 2205static SecTransformInstanceBlock PushBackTest(CFStringRef name, 2206 SecTransformRef newTransform, 2207 SecTransformImplementationRef ref) 2208{ 2209 SecTransformInstanceBlock instanceBlock = 2210 ^{ 2211 CFErrorRef result = NULL; 2212 __block CFStringRef input_d = NULL; 2213 __block CFStringRef data_d = NULL; 2214 2215 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DATA"), 2216 ^(SecTransformAttributeRef ah, CFTypeRef value) 2217 { 2218 if (!input_d) 2219 { 2220 SecTransformPushbackAttribute(ref, ah, value); 2221 } 2222 else 2223 { 2224 if (data_d) 2225 { 2226 CFRelease(data_d); 2227 } 2228 data_d = (CFStringRef)CFRetain(value); 2229 } 2230 return value; 2231 }); 2232 2233 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"), 2234 ^(SecTransformAttributeRef ah, CFTypeRef value) 2235 { 2236 if (value) 2237 { 2238 if (input_d) 2239 { 2240 CFRelease(input_d); 2241 } 2242 input_d = (CFStringRef)CFRetain(value); 2243 if (!data_d) 2244 { 2245 SecTransformPushbackAttribute(ref, ah, value); 2246 return value; 2247 } 2248 } 2249 else 2250 { 2251 if (data_d) 2252 { 2253 SecTransformPushbackAttribute(ref, ah, NULL); 2254 value = data_d; 2255 data_d = NULL; 2256 } 2257 } 2258 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value); 2259 return value; 2260 }); 2261 2262 return result; 2263 }; 2264 2265 return Block_copy(instanceBlock); 2266} 2267 2268-(void)testPushback { 2269 2270 CFStringRef name = CFSTR("com.apple.security.unit-test.basic-pushback"); 2271 CFStringRef one = CFSTR("1"); 2272 CFStringRef two = CFSTR("2"); 2273 CFStringRef expect = CFSTR("12"); 2274 2275 // This unit test makes pushback look very complex, but that is because we are abusing it for test purposes. 2276 // normally it is a simple "if I need X before I can go on, and X isn't here yet pushback". Here we attempt 2277 // to carefully sequence 2 attributes to be the inverse of the normal order AND test pushback of NULL as well 2278 // as normal values. 2279 2280 CFErrorRef error = NULL; 2281 SecTransformRegister(name, &PushBackTest, &error); 2282 2283 SecTransformRef pt = SecTransformCreate(name, NULL); 2284 2285 SecTransformSetAttribute(pt, CFSTR("DATA"), two, NULL); 2286 SecTransformSetAttribute(pt, CFSTR("INPUT"), one, NULL); 2287 2288 CFTypeRef result = SecTransformExecute(pt, NULL); 2289 2290 STAssertEqualObjects((id)result, (id)expect, @"Testing pushback"); 2291 2292 CFRelease(pt); 2293 2294 // NOTE: we want to test doing a double pushback, but that sets the Abort attribute which currently causes an abort not an orderly shutdown 2295 2296} 2297 2298static SecTransformInstanceBlock CustomExternalization(CFStringRef name, 2299 SecTransformRef newTransform, 2300 SecTransformImplementationRef ref) 2301{ 2302 SecTransformInstanceBlock instanceBlock = 2303 ^{ 2304 CFErrorRef result = NULL; 2305 // Create a non-attribute 'instance' variable which will contain 2306 // the version number of this class 2307 2308 __block float versionNumber = 1.0; 2309 2310 // Register the custom externalize override 2311 SecTransformActionBlock ExternalizeExtraDataOverride = 2312 ^{ 2313 CFStringRef key = CFSTR("VersionNumber"); 2314 CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &versionNumber); 2315 2316 CFDictionaryRef result = CFDictionaryCreate(kCFAllocatorDefault, 2317 (const void **)&key, (const void **)&value, 2318 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 2319 2320 CFRelease(value); 2321 2322 2323 return (CFTypeRef)result; 2324 2325 }; 2326 SecTransformSetTransformAction(ref, kSecTransformActionExternalizeExtraData, ExternalizeExtraDataOverride); 2327 2328 // Register the custom internalize override 2329 SecTransformDataBlock InternalizeExtraDataOverride = 2330 ^(CFTypeRef d) 2331 { 2332 CFTypeRef internalizeResult = NULL; 2333 //id testObj = (id)d; 2334 2335 //STAssertNotNil(testObj, @"Internalize did NOT get a dictionary!"); 2336 2337 if (CFDictionaryGetTypeID() == CFGetTypeID(d)) 2338 { 2339 CFStringRef key = CFSTR("VersionNumber"); 2340 CFDictionaryRef dict = (CFDictionaryRef)d; 2341 CFNumberRef varsNum = (CFNumberRef)CFDictionaryGetValue(dict, key); 2342 // STAssertNotNil((NSNumber *)varsNum, 2343 // @"Unable to retrieve the dictionary when the internalized data override"); 2344 if (NULL != varsNum) 2345 { 2346 Boolean numResult = CFNumberGetValue(varsNum, kCFNumberFloatType, &versionNumber); 2347 // STAssertTrue(numResult, @"Could not get the version number from the CFNumberRef"); 2348 if (numResult) 2349 { 2350 //float knownVersion = 1.0; 2351 // STAssertTrue(knownVersion == versionNumber, @"Versions do not Match!"); 2352 } 2353 } 2354 } 2355 return internalizeResult; 2356 }; 2357 SecTransformSetDataAction(ref, kSecTransformActionInternalizeExtraData, 2358 InternalizeExtraDataOverride); 2359 2360 return result; 2361 }; 2362 2363 return Block_copy(instanceBlock); 2364} 2365 2366/* -------------------------------------------------------------------------- 2367 method: testCustomExternalization 2368 description: Test the ability to write out custom external data 2369 -------------------------------------------------------------------------- */ 2370- (void)testCustomExternalization 2371{ 2372 NSString* ctName = @"com.apple.security.unit-test-customExternalization"; 2373 NSError* error = nil; 2374 2375 CFStringRef aName = (CFStringRef)ctName; 2376 CFErrorRef* anError = (CFErrorRef *)&error; 2377 2378 Boolean registerResult = SecTransformRegister(aName, &CustomExternalization, anError); 2379 STAssertTrue(registerResult, @"Unable to register the custom externalization transform"); 2380 2381 SecTransformRef externalTrans = SecTransformCreate((CFStringRef)ctName, 2382 (CFErrorRef *)&error); 2383 2384 STAssertNotNil((id)externalTrans, @"Could not create the custom externalization transform"); 2385 2386 CFDictionaryRef externalData = SecTransformCopyExternalRepresentation(externalTrans); 2387 STAssertNotNil((NSDictionary *)externalData, @"Did not get a dictionary from SecTransformCopyExternalRepresentation"); 2388 2389 CFRelease(externalTrans); 2390 2391 externalTrans = NULL; 2392 externalTrans = SecTransformCreateFromExternalRepresentation(externalData, (CFErrorRef *)&error); 2393 STAssertNotNil((id)externalTrans, @"Could not create the custom external representation"); 2394 CFRelease(externalData); 2395 if (NULL != externalTrans) 2396 { 2397 CFRelease(externalTrans); 2398 } 2399} 2400 2401static SecTransformInstanceBlock TestString(CFStringRef name, 2402 SecTransformRef newTransform, 2403 SecTransformImplementationRef ref) 2404{ 2405 SecTransformInstanceBlock instanceBlock = 2406 ^{ 2407 CFErrorRef result = NULL; 2408 SecTransformSetDataAction(ref, kSecTransformActionProcessData, 2409 ^(CFTypeRef value) 2410 { 2411 CFDataRef d = (CFDataRef)value; 2412 if (d) { 2413 return (CFTypeRef)CFStringCreateWithBytes(NULL, CFDataGetBytePtr(d), CFDataGetLength(d), kCFStringEncodingMacRoman, FALSE); 2414 } else { 2415 return (CFTypeRef)d; 2416 } 2417 }); 2418 return result; 2419 }; 2420 2421 return Block_copy(instanceBlock); 2422} 2423 2424-(void)testStringResults { 2425 CFStringRef name = CFSTR("com.apple.security.unit-test.string-converter"); 2426 CFErrorRef error = NULL; 2427 SecTransformRegister(name, &TestString, &error); 2428 2429 SecTransformRef sr = SecTransformCreate(name, NULL); 2430 2431 unsigned char *msg = (unsigned char *)"This is a test message, it isn't large, but it will get broken into parts by the encode/decode transforms..."; 2432 CFDataRef data = CFDataCreate(NULL, msg, strlen((const char *)msg)); 2433 NSString *ns_msg = [NSString stringWithCString:(const char *)msg encoding:NSMacOSRomanStringEncoding]; 2434 2435 SecTransformRef er = SecEncodeTransformCreate(kSecBase32Encoding, NULL); 2436 SecTransformRef dr = SecDecodeTransformCreate(kSecBase32Encoding, NULL); 2437 2438 SecTransformSetAttribute(er, kSecTransformInputAttributeName, data, NULL); 2439 2440 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 2441 SecTransformConnectTransforms(er, kSecTransformOutputAttributeName, dr, kSecTransformInputAttributeName, group, NULL); 2442 SecTransformConnectTransforms(dr, kSecTransformOutputAttributeName, sr, kSecTransformInputAttributeName, group, NULL); 2443 2444 2445 CFStringRef result = (CFStringRef)SecTransformExecute(sr, NULL); 2446 STAssertEqualObjects(ns_msg, (NSString *)result, @"string results"); 2447 2448 CFRelease(result); 2449 CFRelease(group); 2450 CFRelease(dr); 2451 CFRelease(er); 2452 CFRelease(sr); 2453 if (error) 2454 { 2455 CFRelease(error); 2456 } 2457} 2458 2459static CFNumberRef MakeNumber1(long n) 2460{ 2461 return CFNumberCreate(NULL, kCFNumberLongType, &n); 2462} 2463 2464 2465 2466static SecTransformInstanceBlock TestRegisterCreate(CFStringRef name, 2467 SecTransformRef newTransform, 2468 SecTransformImplementationRef ref) 2469{ 2470 2471 2472 SecTransformInstanceBlock instanceBlock = 2473 ^{ 2474 __block long count = 0; 2475 2476 __block CFNumberRef countNum = MakeNumber1(count);; 2477 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum); 2478 CFRelease(countNum); 2479 fprintf(stderr, "countNum = %p\n", countNum); 2480 2481 CFErrorRef result = NULL; 2482 SecTransformSetDataAction(ref, kSecTransformActionProcessData, 2483 ^(CFTypeRef value) 2484 { 2485 CFDataRef d = (CFDataRef)value; 2486 if (d) 2487 { 2488 count += CFDataGetLength(d); 2489 2490 CFNumberRef countNum2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &count); 2491 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum2); 2492 CFRelease(countNum2); 2493 fprintf(stderr, "countNum = %p\n", countNum); 2494 2495 } else 2496 { 2497 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, NULL); 2498 } 2499 return value; 2500 }); 2501 2502 2503 return result; 2504 }; 2505 2506 return Block_copy(instanceBlock); 2507} 2508 2509- (void)testRegisterCreate 2510{ 2511 CFStringRef name = CFSTR("com.apple.security.unit-test.novel-unique-at-least-unusual-name"); 2512 long count = 0; 2513 CFNumberRef countNum = NULL; 2514 CFErrorRef error = NULL; 2515 Boolean ok = SecTransformRegister(name, &TestRegisterCreate, &error); 2516 STAssertTrue(ok, @"Successful register"); 2517 2518 SecTransformRef tr = SecTransformCreate(name, NULL); 2519 STAssertNotNil((NSObject *)tr, @"newly created custom transform"); 2520 SecTransformSetAttribute(tr, CFSTR("DEBUG"), kCFBooleanTrue, NULL); 2521 2522 char *data_bytes = (char *)"It was the best of transforms, it was the worst of transforms."; 2523 CFDataRef data = CFDataCreate(NULL, (const UInt8 *)data_bytes, strlen(data_bytes)); 2524 2525 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL); 2526 2527 SecTransformRef nt = SecNullTransformCreate(); 2528 SecTransformRef tg = SecTransformCreateGroupTransform(); 2529 SecTransformConnectTransforms(tr, CFSTR("OUTPUT"), nt, CFSTR("DISCARD"), tg, &error); 2530 STAssertNil((id)error, @"Connected tr's output to nt's discard: %@", error); 2531 SecTransformConnectTransforms(tr, CFSTR("Count"), nt, CFSTR("INPUT"), tg, &error); 2532 STAssertNil((id)error, @"Connected tr's count to nt's input: %@", error); 2533 2534 SecTransformSetAttribute(nt, CFSTR("DEBUG"), kCFBooleanTrue, NULL); 2535 2536 usleep(100); 2537 countNum = (CFNumberRef)SecTransformGetAttribute(tr, CFSTR("Count")); 2538 CFNumberGetValue(countNum, kCFNumberLongType, &count); 2539 CFRelease(countNum); 2540 STAssertTrue(count == 0, @"length unchanged before execute"); 2541 2542 countNum = (CFNumberRef)SecTransformExecute(tg, NULL); 2543 STAssertNotNil((id)countNum, @"Got result from execute"); 2544 STAssertEquals(CFGetTypeID(countNum), CFNumberGetTypeID(), @"expected a number from execute"); 2545 CFNumberGetValue(countNum, kCFNumberLongType, &count); 2546 CFRelease(countNum); 2547 2548 STAssertTrue(count == CFDataGetLength(data), @"Wrong data length"); 2549 2550 CFRelease(tg); 2551 CFRelease(nt); 2552 CFRelease(tr); 2553 CFRelease(data); 2554} 2555 2556 2557static SecTransformInstanceBlock CountTransformTest(CFStringRef name, 2558 SecTransformRef newTransform, 2559 SecTransformImplementationRef ref) 2560{ 2561 SecTransformInstanceBlock instanceBlock = 2562 ^{ 2563 CFErrorRef result = NULL; 2564 SecTransformSetAttributeAction(ref,kSecTransformActionAttributeNotification, CFSTR("INPUT"), 2565 ^(SecTransformAttributeRef ah, CFTypeRef value) 2566 { 2567 if (value) { 2568 if (CFGetTypeID(value) != CFNumberGetTypeID()) { 2569 SecTransformCustomSetAttribute(ref, CFSTR("ABORT"), kSecTransformMetaAttributeValue, CFSTR("Bad type")); 2570 return value; 2571 } 2572 CFNumberRef nr = (CFNumberRef)value; 2573 int max, i; 2574 CFNumberGetValue(nr, kCFNumberIntType, &max); 2575 for(i = 0; i < max; ++i) { 2576 nr = CFNumberCreate(NULL, kCFNumberIntType, &i); 2577 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, nr); 2578 CFRelease(nr); 2579 } 2580 } else { 2581 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value); 2582 } 2583 2584 return value; 2585 }); 2586 2587 return result; 2588 }; 2589 2590 return Block_copy(instanceBlock); 2591} 2592 2593static SecTransformRef count_transform(int n) { 2594 CFStringRef name = CFSTR("com.apple.security.unit-test.count"); 2595 static dispatch_once_t once; 2596 2597 dispatch_once(&once, 2598 ^{ 2599 SecTransformRegister(name, &CountTransformTest, NULL); 2600 }); 2601 2602 SecTransformRef ct = SecTransformCreate(name, NULL); 2603 CFNumberRef num = CFNumberCreate(NULL, kCFNumberIntType, &n); 2604 SecTransformSetAttribute(ct, CFSTR("INPUT"), num, NULL); 2605 CFRelease(num); 2606 2607 return ct; 2608} 2609 2610 2611static SecTransformInstanceBlock StallTest(CFStringRef name, 2612 SecTransformRef newTransform, 2613 SecTransformImplementationRef ref) 2614{ 2615 SecTransformInstanceBlock instanceBlock = 2616 ^{ 2617 CFErrorRef result = NULL; 2618 __block bool go = false; 2619 2620 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("GO"), 2621 ^(SecTransformAttributeRef ah, CFTypeRef value) 2622 { 2623 go = true; 2624 return value; 2625 }); 2626 2627 SecTransformAttributeRef in_ah = SecTransformCustomGetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeRef); 2628 SecTransformAttributeRef out_ah = SecTransformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef); 2629 2630 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL, 2631 ^(SecTransformAttributeRef ah, CFTypeRef value) 2632 { 2633 if (!go) { 2634 SecTransformPushbackAttribute(ref, ah, value); 2635 } else { 2636 if (ah == in_ah) { 2637 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, value); 2638 } 2639 } 2640 return value; 2641 }); 2642 2643 return result; 2644 }; 2645 2646 return Block_copy(instanceBlock); 2647} 2648 2649-(void)testStall { 2650 CFStringRef name = CFSTR("com.apple.security.unit-test.stall"); 2651 2652 (void)SecTransformRegister(name, &StallTest, NULL); 2653 2654 SecTransformRef stall = SecTransformCreate(name, NULL); 2655 SecTransformRef seven = count_transform(7); 2656 SecTransformRef group = SecTransformCreateGroupTransform(); 2657 SecTransformRef delay = delay_transform(NSEC_PER_SEC / 10); 2658 2659 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("FOO"), group, NULL); 2660 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("BAR"), group, NULL); 2661 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("BAZ"), group, NULL); 2662 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("INPUT"), group, NULL); 2663 SecTransformConnectTransforms(delay, CFSTR("OUTPUT"), stall, CFSTR("GO"), group, NULL); 2664 2665 SecTransformSetAttribute(delay, CFSTR("INPUT"), (CFNumberRef)[NSNumber numberWithInt:42], NULL); 2666 2667 CFErrorRef err = NULL; 2668 CFTypeRef r = SecTransformExecute(group, &err); 2669 2670 STAssertNotNil((id)r, @"Results from testStall"); 2671 STAssertNil((id)err, @"Got %@ error from testStall", err); 2672 NSArray *array_seven = [NSArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumber numberWithInt:3], [NSNumber numberWithInt:4], [NSNumber numberWithInt:5], [NSNumber numberWithInt:6], NULL]; 2673 STAssertEqualObjects((id)r, array_seven, @"Correct stall test results"); 2674 2675 CFRelease(delay); 2676 CFRelease(group); 2677 CFRelease(seven); 2678 CFRelease(stall); 2679} 2680 2681-(void)testInappropriateExecution 2682{ 2683 // We want to have more then enough work for all the CPUs to help force a race, so twice 2684 // the number of logical CPUs should do it. NOTE: the completion blocks got to a low 2685 // priority concurrent queue to encourage them to finish out of order and put more 2686 // stress on the system we are testing. 2687 2688 int logical_cpus = 1; 2689 size_t int_size = sizeof(logical_cpus); 2690 int return_code = sysctlbyname("hw.logicalcpu_max", &logical_cpus, &int_size, NULL, 0); 2691 int e = errno; // Save this value so it doesn't get trashed by any subsequent syscalls 2692 STAssertEquals(return_code, 0, @"sysctlbyname failed %s (%d), assuming 1 CPU", strerror(e), e); 2693 2694 SecTransformRef count_a_bunch = count_transform(logical_cpus * 2); 2695 CFErrorRef err = NULL; 2696 dispatch_group_t wait_for_async_to_complete = dispatch_group_create(); 2697 dispatch_group_t outstanding_executions = dispatch_group_create(); 2698 SecTransformRef count_group = SecTransformCreateGroupTransform(); 2699 2700 SecTransformConnectTransforms(count_a_bunch, CFSTR("kludge1"), count_a_bunch, CFSTR("kludge2"), count_group, &err); 2701 STAssertNil((id)err, @"Error (%@) connecting count transform to itself", err); 2702 2703 dispatch_group_enter(wait_for_async_to_complete); 2704 SecTransformExecuteAsync(count_a_bunch, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) 2705 { 2706 dispatch_group_enter(outstanding_executions); 2707 2708 CFErrorRef err = NULL; 2709 CFTypeRef no_result = SecTransformExecute(count_a_bunch, &err); 2710 STAssertNil((id)no_result, @"Attempting to execute an already executing transform should fail, not provide results: %@", no_result); 2711 STAssertNotNil((id)err, @"Attempting to execute an already executing transform should produce some sort of error"); 2712 CFRelease(err); 2713 2714 dispatch_group_leave(outstanding_executions); 2715 2716 if (isFinal) 2717 { 2718 // Give any pending executions time to get to the group_enter 2719 usleep(100); 2720 dispatch_group_wait(outstanding_executions, DISPATCH_TIME_FOREVER); 2721 dispatch_release(outstanding_executions); 2722 dispatch_group_leave(wait_for_async_to_complete); 2723 } 2724 }); 2725 2726 // Before that SecTransformExecuteAsync completes, we do some more work at >low priority to help 2727 // keep the completion blocks landing out of order. In particular we run a transform to 2728 // completion, and then confirm that we can't run it again. 2729 2730 SecTransformRef no_work = SecNullTransformCreate(); 2731 SecTransformRef no_work_group = SecTransformCreateGroupTransform(); 2732 SecTransformConnectTransforms(no_work, CFSTR("kludge1"), no_work, CFSTR("kludge2"), no_work_group, &err); 2733 STAssertNil((id)err, @"Can't connect no_work to itself (to make no_work_group), err=%@", err); 2734 2735 SecTransformSetAttribute(no_work, CFSTR("INPUT"), CFSTR("value"), NULL); 2736 CFTypeRef no_result = SecTransformExecute(no_work_group, &err); 2737 STAssertNil((id)err, @"First execute of Null Transform should be ok, got e=%@", err); 2738 STAssertNotNil((id)no_result, @"First execute of Null Transform should produce a value"); 2739 2740 no_result = SecTransformExecute(no_work_group, &err); 2741 2742 STAssertNotNil((id)err, @"Second execute of Null Transform should fail!"); 2743 STAssertNil((id)no_result, @"Second execute of Null Transform shouldn't produce a value, got r=%@", no_result); 2744 CFRelease(err); 2745 2746 // Now we wait for that first batch of tests to finish, we don't want to call STFail after self goes away. 2747 2748 dispatch_group_wait(wait_for_async_to_complete, DISPATCH_TIME_FOREVER); 2749 dispatch_release(wait_for_async_to_complete); 2750 2751 if (no_result) CFRelease(no_result); 2752 if (no_work) CFRelease(no_work); 2753 if (no_work_group) CFRelease(no_work_group); 2754 if (count_group) CFRelease(count_group); 2755 if (count_a_bunch) CFRelease(count_a_bunch); 2756} 2757 2758static SecTransformInstanceBlock ConnectionReqTest(CFStringRef name, 2759 SecTransformRef newTransform, 2760 SecTransformImplementationRef ref) 2761{ 2762 SecTransformInstanceBlock instanceBlock = 2763 ^{ 2764 CFErrorRef result = NULL; 2765 SecTransformAttributeRef xah = 2766 (SecTransformAttributeRef)SecTranformCustomGetAttribute(ref, CFSTR("XYZZY"), kSecTransformMetaAttributeRef); 2767 2768 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanTrue); 2769 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanFalse); 2770 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"), 2771 ^(SecTransformAttributeRef ah, CFTypeRef value) 2772 { 2773 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeValue, value); 2774 return value; 2775 }); 2776 2777 return result; 2778 }; 2779 2780 return Block_copy(instanceBlock); 2781} 2782 2783 2784-(void)testConnectionReq { 2785 2786 CFStringRef req_xyzzy_name = CFSTR("com.apple.security.unit-test.req_xyzzy"); 2787 2788 (void)SecTransformRegister(req_xyzzy_name, &ConnectionReqTest, NULL); 2789 2790 SecTransformRef tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL); 2791 2792 CFTypeRef in_value = (CFTypeRef)@"Fnord"; 2793 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL); 2794 2795 CFErrorRef err = NULL; 2796 CFTypeRef r = SecTransformExecute(tr_req_xyzzy, &err); 2797 2798 STAssertNil((id)r, @"Execute of tr_req_xyzzy with no xyzzy r=%@", r); 2799 STAssertErrorHas((id)err, @"req_xyzzy", @"Error failed to refer to the transform by name (%@)", err); 2800 STAssertErrorHas((id)err, @"XYZZY", @"Error failed to refer to missing attribute by name (%@)", err); 2801 STAssertErrorHas((id)err, @"requires.*outbound connection", @"Error failed to diagnose invalid condition (%@)", err); 2802 2803 CFRelease(err); 2804 CFRelease(tr_req_xyzzy); 2805 if (r) CFRelease(r); 2806 2807 /* 2808 2809 Note For Josh: 2810 2811 To make this work we need Josh's fix for FindLastTransform! 2812 2813 CFRelease(tr_req_xyzzy); 2814 tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL); 2815 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL); 2816 2817 SecTransformRef group = SecTransformCreateGroupTransform(); 2818 SecTransformRef tee = SecNullTransformCreate(); 2819 SecTransformConnectTransforms(tr_req_xyzzy, CFSTR("XYZZY"), tee, kSecTransformInputAttributeName, group, &err); 2820 STAssertNil((id)err, @"err=%@ from connect", err); 2821 STAssertNotNil((id)group, @"No group after connect"); 2822 r = SecTransformExecute(group, &err); 2823 STAssertNil((id)err, @"Execute err=%@"); 2824 STAssertEqualObjects((id)in_value, (id)r, @"Execution Result"); 2825 2826 */ 2827} 2828 2829static SecTransformInstanceBlock DeferredTest(CFStringRef name, 2830 SecTransformRef newTransform, 2831 SecTransformImplementationRef ref) 2832{ 2833 SecTransformInstanceBlock instanceBlock = 2834 ^{ 2835 CFErrorRef result = NULL; 2836 SecTransformCustomSetAttribute(ref, CFSTR("LATE"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue); 2837 SecTransformCustomSetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeDeferred, kCFBooleanFalse); 2838 2839 __block CFTypeRef in_v = NULL, late_v = NULL; 2840 2841 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"), 2842 ^(SecTransformAttributeRef ah, CFTypeRef value) 2843 { 2844 if (NULL != late_v) { 2845 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, 2846 CreateGenericErrorRef(CFSTR("FAIL"), 1, "LATE (%@) should process after INPUT (%@)", late_v, value)); 2847 } 2848 in_v = value; 2849 return value; 2850 }); 2851 2852 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("LATE"), 2853 ^(SecTransformAttributeRef ah, CFTypeRef value) 2854 { 2855 if (NULL == in_v) { 2856 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, 2857 CreateGenericErrorRef(CFSTR("FAIL"), 1, "INPUT (%@) should process before LATE (%@)", in_v, value)); 2858 } 2859 2860 late_v = value; 2861 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, NULL); 2862 return value; 2863 }); 2864 2865 return result; 2866 }; 2867 2868 return Block_copy(instanceBlock); 2869} 2870 2871 2872-(void)testDeferred { 2873 CFStringRef deferred_name = CFSTR("com.apple.security.unit-test.deferred"); 2874 2875 (void)SecTransformRegister(deferred_name, &DeferredTest, NULL); 2876 2877 SecTransformRef dt = SecTransformCreate(deferred_name, NULL); 2878 2879 // these set attribute calls are failing, but we're ignoring the failures 2880 SecTransformSetAttribute(dt, CFSTR("INPUT"), (CFTypeRef)CFSTR("BLAH"), NULL); 2881 SecTransformSetAttribute(dt, CFSTR("LATE"), (CFTypeRef)CFSTR("QUUX"), NULL); 2882 CFErrorRef err = NULL; 2883 SecTransformExecute(dt, &err); 2884 STAssertNil((id)err, @"Error from execute err=%@", err); 2885 2886 if (err) CFRelease(err); 2887 // CFRelease(dt); 2888} 2889 2890static SecTransformInstanceBlock SaveRestoreTest(CFStringRef name, 2891 SecTransformRef newTransform, 2892 SecTransformImplementationRef ref) 2893{ 2894 SecTransformInstanceBlock instanceBlock = 2895 ^{ 2896 CFErrorRef result = NULL; 2897 SecTransformCustomSetAttribute(ref, CFSTR("Needed"), kSecTransformMetaAttributeRequired, kCFBooleanTrue); 2898 SecTransformCustomSetAttribute(ref, CFSTR("NoSaves"), kSecTransformMetaAttributeExternalize, kCFBooleanFalse); 2899 2900 return result; 2901 }; 2902 2903 return Block_copy(instanceBlock); 2904} 2905 2906-(void)testSaveRestore 2907{ 2908 2909 unsigned char raw_data[] = "Val-U-Sav, nw wth lss vwls!"; 2910 CFDataRef data = CFDataCreate(NULL, (const UInt8*)&raw_data, sizeof(raw_data)); 2911 CFErrorRef err = NULL; 2912 2913 CFStringRef name = CFSTR("com.apple.security.unit-test.SaveRestoreTest"); 2914 2915 (void)SecTransformRegister(name, &SaveRestoreTest, NULL); 2916 2917 SecTransformRef tr1 = SecTransformCreate(name, NULL); 2918 2919 SecTransformSetAttribute(tr1, CFSTR("Optional"), CFSTR("42"), NULL); 2920 SecTransformSetAttribute(tr1, CFSTR("Needed"), CFSTR("and provided"), NULL); 2921 SecTransformSetAttribute(tr1, CFSTR("NoSaves"), CFSTR("42"), NULL); 2922 2923 CFDictionaryRef xr = SecTransformCopyExternalRepresentation(tr1); 2924 STAssertNotNil((NSDictionary *)xr, @"external rep"); 2925 SecTransformRef tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL); 2926 SecTransformSetAttribute(tr2, kSecTransformInputAttributeName, data, NULL); 2927 CFTypeRef none = SecTransformGetAttribute(tr2, CFSTR("NoSaves")); 2928 STAssertNil((id)none, @"Expected %@ to be nil", none); 2929 CFTypeRef forty_two = SecTransformGetAttribute(tr2, CFSTR("Optional")); 2930 STAssertEqualObjects((id)forty_two, @"42", @"restored incorrect value"); 2931 2932 CFDataRef d = (CFDataRef)SecTransformExecute((NSObject *)tr2, &err); 2933 2934 STAssertNotNil((NSData * )d, @"execute result (err=%@)", err); 2935 2936 if (err) { 2937 CFRelease(err); 2938 } 2939 2940 CFRelease(tr1); 2941 CFRelease(tr2); 2942 CFRelease(xr); 2943 2944 tr1 = SecTransformCreate(name, NULL); 2945 SecTransformSetAttribute(tr1, CFSTR("Needed"), CFSTR("and provided"), NULL); 2946 SecTransformSetAttribute(tr1, CFSTR("NoSaves"), CFSTR("42"), NULL); 2947 xr = SecTransformCopyExternalRepresentation(tr1); 2948 tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL); 2949 2950 2951 2952 //tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL); 2953 SecTransformRef tga = SecTransformCreateGroupTransform(); 2954 SecTransformSetAttribute(tr1, kSecTransformInputAttributeName, data, NULL); 2955 2956 // XXX did not swap 2957 SecTransformConnectTransforms(tr1, CFSTR("OUTPUT"), tr2, CFSTR("INPUT"), tga, NULL); 2958 CFStringRef has1 = CFSTR("I has one!"); 2959 CFStringRef has2 = CFSTR("I has two of them!"); 2960 SecTransformSetAttribute(tr1, CFSTR("Needed"), has1, NULL); 2961 SecTransformSetAttribute(tr2, CFSTR("Needed"), has2, NULL); 2962 xr = SecTransformCopyExternalRepresentation(tr1); 2963 STAssertNotNil((NSDictionary *)xr, @"external rep for 2"); 2964 NSLog(@"xr=%@", xr); 2965 2966 SecTransformRef tgb = SecTransformCreateFromExternalRepresentation(xr, &err); 2967 STAssertNil((id)tgb, @"made transform group with duplicate labels"); 2968 STAssertErrorHas((id)err, (NSString*)name, @"Error failed to identify the transform (%@)", err); 2969 STAssertErrorHas((id)err, @"damage|duplicate", @"Error failed to diagnose the invalid condition (%@)", err); 2970 2971 CFStringRef new_name2 = CFSTR("SaveRestoreTestThingie#2"); 2972 CFStringRef fetched_name; 2973 int attempts; 2974 2975 for(attempts = 0; attempts < 20; ++attempts) 2976 { 2977 SecTransformSetAttribute(tr2, CFSTR("NAME"), new_name2, &err); 2978 fetched_name = (CFStringRef)SecTransformGetAttribute(tr2, CFSTR("NAME")); 2979 2980 STAssertNil((id)err, @"Error from setting tr2's name: %@", err); 2981 STAssertEqualObjects((id)fetched_name, (id)new_name2, @"Set tr2's name, attempt %d", attempts); 2982 if (CFEqual(fetched_name, new_name2)) 2983 { 2984 break; 2985 } 2986 if (attempts > 10) 2987 { 2988 usleep(1000); 2989 } 2990 } 2991 2992 xr = SecTransformCopyExternalRepresentation(tr1); 2993 STAssertNotNil((NSDictionary *)xr, @"external rep for 2, take 2"); 2994 NSLog(@"xr=%@", xr); 2995 2996 tgb = SecTransformCreateFromExternalRepresentation(xr, &err); 2997 STAssertNotNil((id)tgb, @"made transform group (take 2)"); 2998 STAssertNil((id)err, @"error from make 2 take 2 (err=%@)", err); 2999 3000 SecTransformRef tr1b = SecTransformFindByName(tgb, (CFStringRef)SecTransformGetAttribute(tr1, CFSTR("NAME"))); 3001 STAssertNotNil((id)tr1b, @"Found tr1b"); 3002 SecTransformRef tr2b = SecTransformFindByName(tgb, (CFStringRef)SecTransformGetAttribute(tr2, CFSTR("NAME"))); 3003 STAssertNotNil((id)tr2b, @"Found tr2b"); 3004 3005 CFStringRef has1b = (CFStringRef)SecTransformGetAttribute(tr1b, CFSTR("Needed")); 3006 STAssertNotNil((id)tr1b, @"tr1b's name"); 3007 CFStringRef has2b = (CFStringRef)SecTransformGetAttribute(tr2b, CFSTR("Needed")); 3008 STAssertNotNil((id)tr2b, @"tr1b's name"); 3009 3010 STAssertEqualObjects((id)has1, (id)has1b, @"has1 == has1b"); 3011 STAssertEqualObjects((id)has2, (id)has2b, @"has2 == has2b"); 3012 3013} 3014 3015-(void)testRequiredAttributes 3016{ 3017 CFStringRef name = CFSTR("com.apple.security.unit-test.requiresStuffThings"); 3018 CFErrorRef error; 3019 // In addition to testing required attributes, this also does a partial "lifecycle" test, making sure we 3020 // pass through the stages, don't regress stages, and don't receive the wrong events in the wrong stages. 3021 typedef enum { S_INITED = 0, S_STARTED, S_RUN, S_EOS, S_GONE } state_t; 3022 3023 __block state_t state = S_INITED; 3024 dispatch_group_t leave_on_finalize = dispatch_group_create(); 3025 3026 SecTransformCreateBlock required_attributes_create_block = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) { 3027 params->overrideAttribute(kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef attribute, CFTypeRef value) { 3028 // NOTE: this is for testing with a single data value, not a series. 3029 if (value) 3030 { 3031 STAssertTrue(state == S_STARTED, @"Init'ed for data (state=%d)", state); 3032 state = S_RUN; 3033 } else { 3034 STAssertTrue(state == S_RUN, @"In run state at EOS (state=%d)", state); 3035 state = S_EOS; 3036 } 3037 params->send(kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value); 3038 return value; 3039 }); 3040 3041 params->send(CFSTR("Stuff"), kSecTransformMetaAttributeRequired, kCFBooleanTrue); 3042 params->send(CFSTR("Things"), kSecTransformMetaAttributeRequired, kCFBooleanTrue); 3043 3044 params->overrideTransform(kSecTransformActionStartingExecution, ^{ 3045 STAssertTrue(state == S_INITED, @"Inited (state=%d)"); 3046 state = S_STARTED; 3047 return (CFTypeRef)NULL; 3048 }); 3049 3050 params->overrideTransform(kSecTransformActionFinalize, ^{ 3051 state = S_GONE; 3052 dispatch_group_leave(leave_on_finalize); 3053 return (CFTypeRef)NULL; 3054 }); 3055 }; 3056 3057 dispatch_group_enter(leave_on_finalize); 3058 SecTransformRef tr = custom_transform(name, required_attributes_create_block); 3059 STAssertNotNil((NSObject *)tr, @"newly created custom transform"); 3060 3061 char *data_bytes = (char *)"It was the best of transforms, it was the worst of transforms."; 3062 CFDataRef data = CFDataCreate(NULL, (const UInt8*)data_bytes, strlen(data_bytes)); 3063 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL); 3064 usleep(100); 3065 STAssertTrue(state == S_INITED, @"not run yet"); 3066 CFDataRef rdata = (CFDataRef)SecTransformExecute((NSObject *)tr, &error); 3067 3068 STAssertTrue(rdata == NULL, @"Expected no result, but got: %@", rdata); 3069 STAssertErrorHas((id)error, @"missing required attributes?", @"Error describes condition (%@)", error); 3070 STAssertErrorHas((id)error, @" Things[ ,)]", @"Missing attributes named (%@)", error); 3071 STAssertErrorHas((id)error, @" Stuff[ ,)]", @"Missing attributes named (%@)", error); 3072 STAssertErrorHas((id)error, @"requiresStuffThings", @"Name of erroring Transform in message (%@)", error); 3073 3074 if (error) { 3075 CFRelease(error); 3076 } 3077 CFRelease(tr); 3078 3079 STAssertFalse(dispatch_group_wait(leave_on_finalize, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"group was ready"); 3080 STAssertTrue(state == S_GONE, @"Transform should be gone, state=%d", state); 3081 3082 dispatch_group_enter(leave_on_finalize); 3083 state = S_INITED; 3084 tr = custom_transform(name, required_attributes_create_block); 3085 STAssertNotNil((NSObject *)tr, @"newly created custom transform"); 3086 3087 error = NULL; 3088 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL); 3089 SecTransformSetAttribute(tr, CFSTR("Things"), CFSTR("grubby things"), NULL); 3090 SecTransformSetAttribute(tr, CFSTR("Stuff"), CFSTR("Cool stuff"), NULL); 3091 rdata = (CFDataRef)SecTransformExecute(tr, &error); 3092 3093 STAssertNotNil((NSData *)rdata, @"Got data back"); 3094 STAssertEqualObjects((NSData *)rdata, (NSData *)data, @"Data unchanged"); 3095 STAssertTrue(state == S_EOS, @"Transform hit EOS"); 3096 STAssertTrue(error == NULL, @"Error not set"); 3097 3098 CFRelease(tr); 3099 STAssertFalse(dispatch_group_wait(leave_on_finalize, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"group was ready"); 3100 STAssertTrue(state == S_GONE, @"Transform gone (state=%d)", state); 3101 dispatch_group_notify(leave_on_finalize, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 3102 dispatch_release(leave_on_finalize); 3103 }); 3104} 3105 3106static SecTransformInstanceBlock AttributeNotificationTest(CFStringRef name, 3107 SecTransformRef newTransform, 3108 SecTransformImplementationRef ref) 3109{ 3110 SecTransformInstanceBlock instanceBlock = 3111 ^{ 3112 CFErrorRef result = NULL; 3113 3114 3115 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL, 3116 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value) 3117 { 3118 SecTransformCustomSetAttribute(ref, CFSTR("Generic"), kSecTransformMetaAttributeValue, kCFBooleanTrue); 3119 return value; 3120 }); 3121 3122 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("Specific"), 3123 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value) 3124 { 3125 SecTransformCustomSetAttribute(ref, CFSTR("Specific"), kSecTransformMetaAttributeValue, kCFBooleanTrue); 3126 return value; 3127 3128 }); 3129 3130 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("AlsoSpecific"), 3131 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value) 3132 { 3133 SecTransformCustomSetAttribute(ref, CFSTR("AlsoSpecific"), kSecTransformMetaAttributeValue, kCFBooleanTrue); 3134 3135 return value; 3136 }); 3137 3138 return result; 3139 }; 3140 3141 return Block_copy(instanceBlock); 3142} 3143 3144-(void)testAttributeNotifications 3145{ 3146 NSString *name = @"com.apple.security.unit-test.testAttributeNotifications"; 3147 Boolean generic_called = NO; 3148 Boolean specific_called = NO; 3149 Boolean also_specific_called = NO; 3150 3151 Boolean ok = SecTransformRegister((CFStringRef)name, &AttributeNotificationTest, NULL); 3152 3153 STAssertTrue(ok, @"Successful register"); 3154 3155 SecTransformRef tr = SecTransformCreate((CFStringRef)name, NULL); 3156 3157 CFStringRef aNameStr = ((CFStringRef)name); 3158 SecTransformSetAttribute(tr, CFSTR("Generic"), aNameStr, NULL); 3159 SecTransformSetAttribute(tr, CFSTR("Specific"), aNameStr, NULL); 3160 SecTransformSetAttribute(tr, CFSTR("AlsoSpecific"), aNameStr, NULL); 3161 3162 generic_called = (kCFBooleanTrue == (CFBooleanRef)SecTransformGetAttribute(tr, CFSTR("Generic"))); 3163 specific_called = (kCFBooleanTrue == (CFBooleanRef)SecTransformGetAttribute(tr, CFSTR("Specific"))); 3164 also_specific_called = (kCFBooleanTrue == (CFBooleanRef)SecTransformGetAttribute(tr, CFSTR("AlsoSpecific"))); 3165 3166 3167 STAssertTrue(generic_called, @"generic called"); 3168 STAssertTrue(specific_called, @"specific called"); 3169 STAssertTrue(also_specific_called, @"also specific called"); 3170 3171 CFRelease(tr); 3172} 3173 3174-(void)testEncryptAndDecryptTransforms 3175{ 3176 NSAutoreleasePool *pool = [NSAutoreleasePool new]; 3177 3178 // generate a symmetrical key for testing 3179 OSStatus err = errSecSuccess; 3180 3181 NSString* algNames[] = 3182 { 3183 @"AES 128", 3184 @"AES 192", 3185 @"AES 256", 3186 @"DES", 3187 @"3DES", 3188 @"CAST", 3189 @"RC4" 3190 }; 3191 3192 CSSM_ALGORITHMS symmetricalAlgos[] = 3193 { 3194 CSSM_ALGID_AES, 3195 CSSM_ALGID_AES, 3196 CSSM_ALGID_AES, 3197 CSSM_ALGID_DES, 3198 CSSM_ALGID_3DES_3KEY_EDE, 3199 CSSM_ALGID_CAST, 3200 CSSM_ALGID_RC4 3201 }; 3202 3203 uint32 keySizes[] = 3204 { 3205 128, 3206 192, 3207 256, 3208 64, 3209 192, 3210 40, 3211 8 3212 }; 3213 3214 CSSM_KEYUSE keyUse = CSSM_KEYUSE_ANY; 3215 CSSM_KEYATTR_FLAGS keyAttrFlags = CSSM_KEYATTR_RETURN_DEFAULT; 3216 SecAccessRef accessRef = NULL; 3217 CSSM_CC_HANDLE handle = ((CSSM_CC_HANDLE)0); 3218 3219 NSString* dataStr = @"At the round earth's imagined corners blow\ 3220 Your trumpets, angels, and arise, arise\ 3221 From death, you numberless infinities\ 3222 Of souls, and to your scattered bodies go,\ 3223 All whom the flood did, and fire shall, overthrow,\ 3224 All whom war, dearth, age, agues, tyrannies,\ 3225 Despair, law, chance, hath slain, and you whose eyes\ 3226 Shall behold God, and never taste death's woe.\ 3227 But let them sleep, Lord, and me mourn a space,\ 3228 For, if above all these my sins abound,\ 3229 'Tis late to ask abundance of Thy grace,\ 3230 When we are there. Here on this lowly ground\ 3231 Teach me how to repent; for that's as good\ 3232 As if Thou'dst sealed my pardon, with Thy blood."; 3233 3234 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding]; 3235 int numItems = (sizeof(symmetricalAlgos) / sizeof(CSSM_ALGORITHMS)); 3236 int iCnt = 0; 3237 3238 for (iCnt = 0; iCnt < numItems; iCnt++) 3239 { 3240 SecKeyRef testKey = NULL; 3241 CSSM_ALGORITHMS algoToUse = symmetricalAlgos[iCnt]; 3242 uint32 keySizeInBits = keySizes[iCnt]; 3243 3244 err = SecKeyGenerate(NULL, algoToUse, keySizeInBits, handle, keyUse, keyAttrFlags, accessRef, &testKey); 3245 STAssertTrue(err == errSecSuccess, [NSString stringWithFormat:@"Unable to create a symmetrical key %@", algNames[iCnt]]); 3246 if (errSecSuccess != err) 3247 { 3248 continue; 3249 } 3250 __block CFErrorRef error = NULL; 3251 3252 SecTransformRef encryptSymRef = NULL; 3253 encryptSymRef = SecEncryptTransformCreate(testKey, &error); 3254 if (NULL != error) 3255 { 3256 CFRelease(testKey); 3257 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key %@", algNames[iCnt]]); 3258 continue; 3259 } 3260 3261 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error); 3262 if (NULL != error) 3263 { 3264 CFRelease(testKey); 3265 CFRelease(encryptSymRef); 3266 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key %@", algNames[iCnt]]); 3267 continue; 3268 } 3269 3270 // connect the output of the encryption to the input of the decryption transform 3271 3272 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 3273 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName, 3274 decryptSymRef, kSecTransformInputAttributeName, 3275 group, &error); 3276 if (NULL != error) 3277 { 3278 CFRelease(testKey); 3279 CFRelease(encryptSymRef); 3280 CFRelease(decryptSymRef); 3281 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key %@", algNames[iCnt]]); 3282 continue; 3283 } 3284 3285 3286 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData]; 3287 [dataStream open]; 3288 3289 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error); 3290 if (NULL != error) 3291 { 3292 CFRelease(testKey); 3293 CFRelease(encryptSymRef); 3294 CFRelease(decryptSymRef); 3295 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to set the input for key %@", algNames[iCnt]]); 3296 continue; 3297 } 3298 3299 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error); 3300 CFRelease(group); 3301 CFRelease(encryptSymRef); 3302 CFRelease(decryptSymRef); 3303 3304 if (NULL != error) 3305 { 3306 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for algo %@", algNames[iCnt]]); 3307 continue; 3308 CFRelease(error); 3309 } 3310 3311 if (NULL == transformResult || 0 == [(NSData*)transformResult length]) 3312 { 3313 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for %@", algNames[iCnt]]); 3314 continue; 3315 } 3316 3317 NSData* resultData = nil; 3318 if (CFGetTypeID(transformResult) == CFDataGetTypeID()) 3319 { 3320 resultData = (NSData*)transformResult; 3321 [resultData autorelease]; 3322 } 3323 3324 CFRelease(testKey); 3325 3326 STAssertTrue([testData isEqualToData:resultData], @"The output of the decrypt transform does NOT match the original input!"); 3327 } 3328 3329 3330 SecKeyRef publicKey = NULL; 3331 SecKeyRef privateKey = NULL; 3332 3333 keyAttrFlags = CSSM_KEYATTR_RETURN_REF; 3334 3335 const uint32 publicKeyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF; 3336 const uint32 privateKeyAttributes = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE; 3337 3338 CSSM_KEYUSE pubKeyUse = CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP; 3339 CSSM_KEYUSE privKeyUse = CSSM_KEYUSE_SIGN | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP; 3340 3341 3342 err = SecKeyCreatePair(NULL, CSSM_ALGID_RSA, 2048, ((CSSM_CC_HANDLE)0), 3343 pubKeyUse, publicKeyAttributes, 3344 privKeyUse, privateKeyAttributes, 3345 NULL, &publicKey, &privateKey); 3346 3347 STAssertTrue(errSecSuccess == err, @"Unable to create a key pair"); 3348 if (errSecSuccess != err) 3349 { 3350 cssmPerror(NULL, err); 3351 return; 3352 } 3353 3354 CFErrorRef error = NULL; 3355 SecTransformRef encryptSymRef = SecEncryptTransformCreate(publicKey , &error); 3356 if (NULL != error) 3357 { 3358 CFRelease(publicKey); 3359 CFRelease(privateKey); 3360 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key RSA"]); 3361 return; 3362 } 3363 3364 SecTransformRef decryptSymRef = SecDecryptTransformCreate(privateKey, &error); 3365 if (NULL != error) 3366 { 3367 CFRelease(publicKey); 3368 CFRelease(privateKey); 3369 CFRelease(encryptSymRef); 3370 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key RSA"]); 3371 return; 3372 } 3373 3374 // connect the output of the encryption to the input of the decryption transform 3375 3376 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 3377 (void)SecTransformConnectTransforms( encryptSymRef, kSecTransformOutputAttributeName, 3378 decryptSymRef, kSecTransformInputAttributeName, 3379 group, &error); 3380 if (NULL != error) 3381 { 3382 CFRelease(publicKey); 3383 CFRelease(privateKey); 3384 CFRelease(encryptSymRef); 3385 CFRelease(decryptSymRef); 3386 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key RSA"]); 3387 return; 3388 } 3389 3390 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData]; 3391 [dataStream open]; 3392 3393 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error); 3394 if (NULL != error) 3395 { 3396 CFRelease(publicKey); 3397 CFRelease(privateKey); 3398 CFRelease(encryptSymRef); 3399 CFRelease(decryptSymRef); 3400 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to set the input for key RSA"]); 3401 return; 3402 } 3403 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error); 3404 if (NULL != error) 3405 { 3406 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for RSA"]); 3407 CFRelease(error); 3408 return; 3409 } 3410 3411 if (NULL == transformResult || 0 == [(NSData*)transformResult length]) 3412 { 3413 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for RSA"]); 3414 return; 3415 } 3416 3417 NSData* resultData = nil; 3418 if (CFGetTypeID(transformResult) == CFDataGetTypeID()) 3419 { 3420 resultData = (NSData*)transformResult; 3421 [resultData autorelease]; 3422 } 3423 3424 CFRelease(publicKey); 3425 CFRelease(privateKey); 3426 CFRelease(encryptSymRef); 3427 CFRelease(decryptSymRef); 3428 3429 STAssertTrue([testData isEqualToData:resultData], @"(RSA)The output of the decrypt transform does NOT match the original input!"); 3430 3431 [pool drain]; 3432} 3433 3434// NOTE: this test is largely the same as testEncryptAndDecryptTransforms, but 3435// we make a single key and use it from many threads at once. This uncovered 3436// some locking issues, so makes a good regression test. 3437-(void)testMultiEncryptWithSameKey { 3438 // generate a symmetrical key for testing 3439 CSSM_KEYUSE keyUse = CSSM_KEYUSE_ANY; 3440 CSSM_KEYATTR_FLAGS keyAttrFlags = CSSM_KEYATTR_RETURN_DEFAULT; 3441 SecAccessRef accessRef = NULL; 3442 CSSM_CC_HANDLE handle = ((CSSM_CC_HANDLE)0); 3443 3444 NSString* dataStr = @"Reduce, reuse, recycle. No crashes please."; 3445 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding]; 3446 3447 SecKeyRef testKey = NULL; 3448 { 3449 OSStatus err; 3450 err = SecKeyGenerate(NULL, CSSM_ALGID_AES, 256, handle, keyUse, keyAttrFlags, accessRef, &testKey); 3451 STAssertTrue(err == errSecSuccess, @"Unable to create a symmetrical key err=%x", err); 3452 } 3453 3454 // The number of iterations is somewhat arbitrary. When we use to have failures they were 3455 // within 2*#logicalCPUs iterations, but nothing says we won't have a regression that happens 3456 // outside that window. 3457 dispatch_apply(128, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) { 3458 __block CFErrorRef error = NULL; 3459 3460 SecTransformRef encryptSymRef = NULL; 3461 encryptSymRef = SecEncryptTransformCreate(testKey, &error); 3462 if (NULL != error) 3463 { 3464 STFail(@"Unable to create the encrypt transform iteration#%d error=%@", i, error); 3465 return; 3466 } 3467 if (NULL == encryptSymRef) { 3468 STFail(@"Unable to create the encrypt transform iteration#%d, error=NULL", i); 3469 return; 3470 } 3471 3472 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error); 3473 if (NULL != error) 3474 { 3475 CFRelease(encryptSymRef); 3476 STFail(@"Unable to create the decrypt transform iteration#%d error=%@", i, error); 3477 return; 3478 } 3479 if (NULL == decryptSymRef) { 3480 CFRelease(encryptSymRef); 3481 STFail(@"Unable to create the decrypt transform iteration#%d, error=NULL", i); 3482 return; 3483 } 3484 3485 // connect the output of the encryption to the input of the decryption transform 3486 3487 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 3488 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName, 3489 decryptSymRef, kSecTransformInputAttributeName, 3490 group, &error); 3491 if (NULL != error) 3492 { 3493 CFRelease(encryptSymRef); 3494 CFRelease(decryptSymRef); 3495 STFail(@"Unable to connect transforms on iteration %d error=%@", i, error); 3496 return; 3497 } 3498 3499 3500 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData]; 3501 [dataStream open]; 3502 3503 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error); 3504 if (NULL != error) 3505 { 3506 CFRelease(encryptSymRef); 3507 CFRelease(decryptSymRef); 3508 STFail(@"Unable to set the input on iteration %d error=%@", i, error); 3509 return; 3510 } 3511 3512 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error); 3513 CFRelease(group); 3514 3515 if (NULL != error) 3516 { 3517 STFail(@"returned an error on iteration %d error=%@", i, error); 3518 CFRelease(error); 3519 return; 3520 } 3521 3522 if (NULL == transformResult || 0 == [(NSData*)transformResult length]) 3523 { 3524 STFail(@"transformResult was NULL or empty for iteration %d", i); 3525 return; 3526 } 3527 3528 NSData* resultData = nil; 3529 if (CFGetTypeID(transformResult) == CFDataGetTypeID()) 3530 { 3531 resultData = (NSData*)transformResult; 3532 [resultData autorelease]; 3533 } 3534 3535 CFRelease(encryptSymRef); 3536 CFRelease(decryptSymRef); 3537 3538 STAssertEqualObjects(testData, resultData, @"The output of the decrypt transform does NOT match the original input iteration %d", i); 3539 }); 3540 3541 CFRelease(testKey); 3542} 3543 3544static SecTransformInstanceBlock RoundTripCheck(CFStringRef name, 3545 SecTransformRef newTransform, 3546 SecTransformImplementationRef ref) 3547{ 3548 SecTransformInstanceBlock instanceBlock = 3549 ^{ 3550 CFErrorRef result = NULL; 3551 __block CFDataRef remainder = NULL; 3552 __block SecTransformStringOrAttributeRef ahead = NULL; 3553 __block int eof_count = 0; 3554 __block bool drain = false; 3555 3556 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue); 3557 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeStream, kCFBooleanTrue); 3558 3559 dispatch_block_t not_equal = 3560 ^{ 3561 // not equal 3562 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, kCFBooleanFalse); 3563 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL); 3564 drain = true; 3565 }; 3566 3567 SecTransformAttributeActionBlock action = 3568 ^(SecTransformAttributeRef ah, CFTypeRef value) 3569 { 3570 if (drain) 3571 { 3572 return (CFTypeRef)NULL; 3573 } 3574 3575 if (ahead == ah) 3576 { 3577 SecTransformPushbackAttribute(ref, ah, value); 3578 } 3579 else if (value) 3580 { 3581 CFDataRef d = (CFDataRef)value; 3582 if (remainder) 3583 { 3584 CFIndex compare_length; 3585 CFIndex remainder_length = CFDataGetLength(remainder); 3586 CFIndex d_length = CFDataGetLength(d); 3587 CFDataRef new_remainder = NULL; 3588 SecTransformAttributeRef new_ahead = NULL; 3589 3590 if (remainder_length == d_length) 3591 { 3592 compare_length = d_length; 3593 } 3594 else if (remainder_length < d_length) 3595 { 3596 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(d) + remainder_length, d_length - remainder_length); 3597 compare_length = remainder_length; 3598 new_ahead = ah; 3599 } else 3600 { 3601 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(remainder) + d_length, remainder_length - d_length); 3602 compare_length = d_length; 3603 new_ahead = ahead; 3604 } 3605 3606 if (bcmp(CFDataGetBytePtr(d), CFDataGetBytePtr(remainder), compare_length)) { 3607 not_equal(); 3608 } else 3609 { 3610 // same, keep going 3611 CFRelease(remainder); 3612 remainder = new_remainder; 3613 ahead = new_ahead; 3614 } 3615 } 3616 else 3617 { 3618 if (!eof_count) 3619 { 3620 ahead = ah; 3621 remainder = CFDataCreateCopy(NULL, d); 3622 } 3623 else 3624 { 3625 if (CFDataGetLength(d)) 3626 { 3627 not_equal(); 3628 } 3629 } 3630 } 3631 } 3632 else 3633 { // EOF case 3634 ahead = NULL; 3635 if (++eof_count == 2) 3636 { 3637 if (remainder) 3638 { 3639 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, 3640 kSecTransformMetaAttributeValue, 3641 CFDataGetLength(remainder) ? kCFBooleanFalse : kCFBooleanTrue); 3642 3643 CFRelease(remainder); 3644 } 3645 else 3646 { 3647 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, 3648 kSecTransformMetaAttributeValue, kCFBooleanTrue); 3649 } 3650 3651 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, 3652 kSecTransformMetaAttributeValue, NULL); 3653 } 3654 } 3655 3656 return (CFTypeRef)NULL; 3657 }; 3658 3659 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT2"), action); 3660 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, action); 3661 3662 return result; 3663 }; 3664 3665 return Block_copy(instanceBlock); 3666} 3667 3668static BOOL RoundTrip(CFStringRef fname, SecTransformRef in, SecTransformRef out, BOOL share) 3669{ 3670 static dispatch_once_t once; 3671 CFStringRef name = CFSTR("com.apple.examples.cmp"); 3672 // concepts: pushback, SecTransformSetAttributeAction vs. ProcessData, ah==, & send value to output 3673 3674 dispatch_once(&once, 3675 ^{ 3676 SecTransformRegister(name, &RoundTripCheck, NULL); 3677 }); 3678 3679 SecTransformRef cmp = SecTransformCreate(name, NULL); 3680 SecTransformRef group = SecTransformCreateGroupTransform(); 3681 CFErrorRef err = NULL; 3682 SecTransformConnectTransforms(in, kSecTransformOutputAttributeName, out, kSecTransformInputAttributeName, group, NULL); 3683 SecTransformConnectTransforms(out, kSecTransformOutputAttributeName, cmp, kSecTransformInputAttributeName, group, NULL); 3684 NSInputStream *is = [NSInputStream inputStreamWithFileAtPath:(NSString *)fname]; 3685 // XXX: failure to do this seem to crash SecTransformExecute when it releases the error, track down & fix or file radar 3686 [is open]; 3687 3688 NSInputStream *is2 = nil; 3689 3690 if (share) 3691 { 3692 SecTransformRef tee = SecNullTransformCreate(); 3693 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, in, kSecTransformInputAttributeName, group, NULL); 3694 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, cmp, CFSTR("INPUT2"), group, NULL); 3695 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, (CFTypeRef)is, NULL); 3696 CFRelease(tee); 3697 } else { 3698 is2 = [NSInputStream inputStreamWithFileAtPath:(NSString *)fname]; 3699 [is2 open]; 3700 SecTransformSetAttribute(in, kSecTransformInputAttributeName, (CFTypeRef)is, &err); 3701 SecTransformSetAttribute(cmp, CFSTR("INPUT2"), (CFTypeRef)is2, &err); 3702 } 3703 3704 assert(err == NULL); 3705 CFTypeRef r = SecTransformExecute(group, &err); 3706 3707 if (err) 3708 { 3709 CFRelease(err); 3710 } 3711 3712 CFRelease(group); 3713 CFRelease(cmp); 3714 3715 if (is2) 3716 { 3717 [is2 close]; 3718 } 3719 3720 if (is) 3721 { 3722 [is close]; 3723 } 3724 3725 if (r) 3726 { 3727 return r == kCFBooleanTrue; 3728 } 3729 else 3730 { 3731 CFfprintf(stderr, "round trip error: %@", err); 3732 return NO; 3733 } 3734} 3735 3736static SecTransformInstanceBlock LineLengthCheck(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref) 3737{ 3738 SecTransformInstanceBlock instanceBlock = ^{ 3739 CFErrorRef result = NULL; 3740 __block int bytesPastLastEOL = 0; 3741 __block int max = 0; 3742 3743 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("MAX"), ^(SecTransformAttributeRef ah, CFTypeRef value) { 3744 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &max); 3745 return value; 3746 }); 3747 3748 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef ah, CFTypeRef value) { 3749 if (NULL != value) { 3750 CFDataRef d = (CFDataRef)value; 3751 CFIndex len = CFDataGetLength(d); 3752 const UInt8 *bytes = CFDataGetBytePtr(d); 3753 3754 for(int i = 0; i < len; i++) { 3755 if (bytes[i] == '\n') { 3756 bytesPastLastEOL = 0; 3757 } else { 3758 bytesPastLastEOL++; 3759 if (bytesPastLastEOL > max) { 3760 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "MAX line length of %d exceeded", max)); 3761 break; 3762 } 3763 } 3764 } 3765 } 3766 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value); 3767 return value; 3768 }); 3769 3770 return result; 3771 }; 3772 3773 return Block_copy(instanceBlock); 3774} 3775 3776-(void)testLargeChunkEncode 3777{ 3778 NSError *err = NULL; 3779 NSData *d = [NSData dataWithContentsOfFile:@"/usr/share/dict/web2a" options:NSDataReadingMapped error: &err]; 3780 STAssertNil(err, @"dataWithContentsOfFile %@", err); 3781 CFStringRef types[] = {kSecZLibEncoding, kSecBase64Encoding, kSecBase32Encoding, NULL}; 3782 3783 dispatch_group_t dg = dispatch_group_create(); 3784 3785 CFStringRef lengthCheckName = CFSTR("com.apple.security.unit-test.lineLengthCheck"); 3786 SecTransformRegister(lengthCheckName, LineLengthCheck, (CFErrorRef *)&err); 3787 STAssertNil(err, @"Expected to register %@", lengthCheckName); 3788 3789 for(int i = 0; types[i]; i++) { 3790 int max_j = 80; 3791 CFStringRef etype = types[i]; 3792 3793 void (^trial)(NSString *testName, id lineLength, int maxLineLength) = ^(NSString *testName, id lineLength, int maxLineLength) { 3794 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 3795 3796 SecTransformRef et = SecEncodeTransformCreate(etype, (CFErrorRef *)&err); 3797 SecTransformRef dt = SecDecodeTransformCreate(etype, (CFErrorRef *)&err); 3798 3799 SecTransformRef lineLengthChecker = (etype == kSecZLibEncoding) ? SecNullTransformCreate() : SecTransformCreate(lengthCheckName, NULL); 3800 STAssertNotNil((id)lineLengthChecker, @"Expected to create line length checker"); 3801 SecTransformSetAttribute(lineLengthChecker, CFSTR("MAX"), [NSNumber numberWithInt:maxLineLength], NULL); 3802 3803 SecTransformConnectTransforms(et, kSecTransformOutputAttributeName, lineLengthChecker, kSecTransformInputAttributeName, group, (CFErrorRef *)&err); 3804 SecTransformConnectTransforms(lineLengthChecker, kSecTransformOutputAttributeName, dt, kSecTransformInputAttributeName, group, (CFErrorRef *)&err); 3805 3806 SecTransformSetAttribute(et, kSecTransformInputAttributeName, (CFDataRef)d, (CFErrorRef *)&err); 3807 SecTransformSetAttribute(et, kSecEncodeLineLengthAttribute, lineLength, (CFErrorRef *)&err); 3808 SecTransformSetAttribute(et, CFSTR("NAME"), (CFStringRef)testName, (CFErrorRef *)&err); 3809 3810 dispatch_group_async(dg, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3811 CFDataRef result = (CFDataRef)SecTransformExecute(group, (CFErrorRef *)&err); 3812 3813 STAssertNil(err, @"execute for %@ got %@", testName, err); 3814 STAssertNotNil((id)result, @"No result from execute of %@", testName); 3815 3816 if (result) { 3817 STAssertEqualObjects(d, (id)result, @"test %@ failed", testName); 3818 } 3819 }); 3820 }; 3821 3822 for(int j = max_j; j > 70; --j) { 3823 if (etype == kSecZLibEncoding && j != max_j) { 3824 break; 3825 } 3826 trial([NSString stringWithFormat:@"%@-%d", etype, j], [NSNumber numberWithInt:j], j); 3827 } 3828 3829 if (etype != kSecZLibEncoding) { 3830 trial([NSString stringWithFormat:@"%@-LL64", etype], (id)kSecLineLength64, 64); 3831 trial([NSString stringWithFormat:@"%@-LL76", etype], (id)kSecLineLength76, 76); 3832 } 3833 } 3834 3835 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER); 3836} 3837 3838-(void)testZLib { 3839 SecTransformRef et = SecEncodeTransformCreate(kSecZLibEncoding, NULL); 3840 SecTransformRef dt = SecDecodeTransformCreate(kSecZLibEncoding, NULL); 3841 3842 // using a tee would require >10 buffered items (we need to buffer about 64K), so we pass share=NO 3843 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/web2a", et, dt, NO), @"Roundtrip /usr/share/dict/web2a"); 3844 3845 CFRelease(et); 3846 CFRelease(dt); 3847 3848 /* 3849 If we want this we need a 'new' custom transform that will get receive the ratio data and be able to 3850 query that data. 3851 3852 CFNumberRef r1 = (CFNumberRef)SecTransformGetAttribute(et, kSecCompressionRatio); 3853 CFNumberRef r2 = (CFNumberRef)SecTransformGetAttribute(dt, kSecCompressionRatio); 3854 3855 STAssertNotNil((NSNumber *)r1, @"encode ratio"); 3856 STAssertNotNil((NSNumber *)r2, @"decode ratio"); 3857 STAssertEqualObjects((NSNumber *)r1, (NSNumber *)r2, @"same ratios"); 3858 */ 3859} 3860 3861static SecTransformInstanceBlock CycleCheckTest(CFStringRef name, 3862 SecTransformRef newTransform, 3863 SecTransformImplementationRef ref) 3864{ 3865 SecTransformInstanceBlock instanceBlock = 3866 ^{ 3867 CFErrorRef result = NULL; 3868 int zero = 0; 3869 __block CFNumberRef feedback = CFNumberCreate(NULL, kCFNumberIntType, &zero); 3870 3871 SecTransformCustomSetAttribute(ref, CFSTR("FEEDBACK"), kSecTransformMetaAttributeCanCycle, kCFBooleanTrue); 3872 3873 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"), 3874 ^(SecTransformAttributeRef ah, CFTypeRef value) 3875 { 3876 if (value == NULL) { 3877 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value); 3878 return value; 3879 } 3880 if (feedback == NULL) { 3881 SecTransformPushbackAttribute(ref, ah, value); 3882 return (CFTypeRef)NULL; 3883 } 3884 3885 int x, y; 3886 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &x); 3887 CFNumberGetValue(feedback, kCFNumberIntType, &y); 3888 x ^= y; 3889 CFNumberRef res = CFNumberCreate(NULL, kCFNumberIntType, &x); 3890 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, res); 3891 CFRelease(res); 3892 CFRelease(feedback); 3893 feedback = NULL; 3894 return (CFTypeRef)NULL; 3895 }); 3896 3897 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("FEEDBACK"), 3898 ^(SecTransformAttributeRef ah, CFTypeRef value) 3899 { 3900 if (value) { 3901 if (feedback) { 3902 SecTransformPushbackAttribute(ref, ah, value); 3903 } else { 3904 feedback = (CFNumberRef)CFRetain(value); 3905 } 3906 } 3907 3908 return (CFTypeRef)NULL; 3909 }); 3910 3911 return result; 3912 3913 }; 3914 3915 return Block_copy(instanceBlock); 3916} 3917 3918-(void)testCycleCheck { 3919 3920 SecTransformRef cat = SecNullTransformCreate(); 3921 SecTransformRef group = SecTransformCreateGroupTransform(); 3922 CFErrorRef err = NULL; 3923 3924 CFStringRef name = CFSTR("com.apple.examples.unit-test.loop-test"); 3925 3926 SecTransformRegister(name, &CycleCheckTest, NULL); 3927 3928 SecTransformRef twenty = count_transform(20); 3929 3930 // this is getting an internal error, but it's being ignored. 3931 SecTransformRef xxor = SecTransformCreate(name, &err); 3932 3933 SecTransformConnectTransforms(xxor, CFSTR("OUTPUT"), cat, CFSTR("INPUT"), group, &err); 3934 STAssertNil((id)err, @"xor->cat"); 3935 SecTransformConnectTransforms(xxor, CFSTR("OUTPUT"), xxor, CFSTR("FEEDBACK"), group, &err); 3936 STAssertNil((id)err, @"xor->xor"); 3937 SecTransformConnectTransforms(twenty, CFSTR("OUTPUT"), xxor, CFSTR("INPUT"), group, &err); 3938 STAssertNil((id)err, @"twenty->xor"); 3939 3940 //SecTransformSetAttribute(xxor, CFSTR("DEBUG"), kCFBooleanTrue, &err); 3941 3942 CFTypeRef r = SecTransformExecute(group, &err); 3943 STAssertNil((id)err, @"execute err=%@", err); 3944 STAssertNotNil((id)r, @"no results from execute"); 3945 3946 if (r) { 3947 CFNumberRef z = (CFNumberRef)[NSNumber numberWithInt:0]; 3948 CFIndex n = CFArrayGetCountOfValue((CFArrayRef)r, CFRangeMake(0, CFArrayGetCount((CFArrayRef)r)), z); 3949 // There should be six zeros in the xor->feedback chain from 0 to 19. 3950 STAssertEquals(n, (CFIndex) 6, @"There should be six zeros in %@", r); 3951 } 3952 3953 CFRelease(r); 3954 CFRelease(group); 3955 CFRelease(twenty); 3956 CFRelease(xxor); 3957 CFRelease(cat); 3958} 3959 3960-(void)testValidate { 3961 SecTransformRef group = SecTransformCreateGroupTransform(); 3962 CFErrorRef err = NULL; 3963 3964 CFStringRef data_or_null_name = CFSTR("com.apple.examples.unit-test.data-or-null"); 3965 SecTransformCreateBlock data_or_null = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) { 3966 params->overrideAttribute(kSecTransformActionAttributeValidation, CFSTR("INPUT"), SecTransformCreateValidatorForCFtype(CFDataGetTypeID(), YES)); 3967 }; 3968 3969 3970 SecTransformRef makes_numbers = count_transform(20); 3971 SecTransformRef wants_data = custom_transform(data_or_null_name, data_or_null); 3972 3973 SecTransformConnectTransforms(makes_numbers, CFSTR("OUTPUT"), wants_data, CFSTR("INPUT"), group, NULL); 3974 STAssertNil((id)err, @"unexpected connect error: %@", err); 3975 CFTypeRef r = SecTransformExecute(group, &err); 3976 STAssertNil((id)r, @"Got non-null result (%@) when expecting null!", r); 3977 STAssertNotNil((id)err, @"Expected an error!", err); 3978 STAssertErrorHas((id)err, @"/INPUT", @"Error indicated attribute that was set incorrectly"); 3979 STAssertErrorHas((id)err, @" type CFNumber", @"Error indicated provided type"); 3980 STAssertErrorHas((id)err, @" a CFData", @"Error indicated required type"); 3981 3982 if (err) { 3983 CFRelease(err); 3984 } 3985 err = NULL; 3986 CFRelease(wants_data); 3987 3988 wants_data = custom_transform(data_or_null_name, data_or_null); 3989 3990 char raw_data[] = "`Twas brillig, and the slithy toves / Did gyre and gimble in the wabe: / All mimsy were the borogoves, / And the mome raths outgrabe."; 3991 CFDataRef the_data = CFDataCreate(NULL, (UInt8*)raw_data, strlen(raw_data)); 3992 SecTransformSetAttribute(wants_data, kSecTransformInputAttributeName, the_data, &err); 3993 CFRelease(the_data); 3994 3995 STAssertNil((id)err, @"unexpected set error: %@", err); 3996 r = SecTransformExecute(wants_data, &err); 3997 STAssertNotNil((id)r, @"Expected a result, got error: %@", err); 3998 if (r) { 3999 STAssertEqualObjects((id)the_data, (id)r, @"Invalid result"); 4000 } 4001 4002 CFStringRef numbers_only_name = CFSTR("com.apple.examples.unit-test.numbers-only"); 4003 SecTransformCreateBlock numbers_only = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) { 4004 params->overrideAttribute(kSecTransformActionAttributeValidation, CFSTR("INPUT"), SecTransformCreateValidatorForCFtype(CFNumberGetTypeID(), NO)); 4005 }; 4006 4007 CFRelease(group); 4008 CFRelease(makes_numbers); 4009 CFRelease(wants_data); 4010 4011 group = SecTransformCreateGroupTransform(); 4012 makes_numbers = count_transform(20); 4013 SecTransformRef wants_numbers = custom_transform(numbers_only_name, numbers_only); 4014 4015 SecTransformConnectTransforms(makes_numbers, CFSTR("OUTPUT"), wants_numbers, CFSTR("INPUT"), group, NULL); 4016 STAssertNil((id)err, @"unexpected connect error: %@", err); 4017 r = SecTransformExecute(group, &err); 4018 CFfprintf(stderr, "r=%@; err=%@\n", r, err); 4019 STAssertNil((id)r, @"Got non-null result (%@) when expecting null!", r); 4020 STAssertNotNil((id)err, @"Expected an error!", err); 4021 STAssertErrorHas((id)err, @"/INPUT", @"Error indicated attribute that was set incorrectly"); 4022 STAssertErrorHas((id)err, @"received NULL value", @"Error indicated provided value is NULL"); 4023 STAssertErrorHas((id)err, @" a CFNumber", @"Error indicated required type"); 4024 4025 CFRelease(err); 4026 CFRelease(group); 4027 CFRelease(makes_numbers); 4028 CFRelease(wants_numbers); 4029} 4030 4031-(void)testCodeBase32 { 4032 struct base32_test_vector { 4033 const char *plain_text; 4034 const char *base32_rfc4648; 4035 const char *base32_fde; 4036 }; 4037 4038 // RFC 4648 test vectors 4039 static base32_test_vector base32_test_vectors[] = { 4040 {"", "", ""}, 4041 {"f", "MY======", "MY======"}, 4042 {"fo", "MZXQ====", "MZXQ===="}, 4043 {"foo", "MZXW6===", "MZXW6==="}, 4044 {"foob", "MZXW6YQ=", "MZXW6YQ="}, 4045 {"fooba", "MZXW6YTB", "MZXW6YTB"}, 4046 {"foobar", "MZXW6YTBOI======", "MZXW6YTBO8======"}}; 4047 4048 void (^test)(NSString *test_name, SecTransformRef transform, const char *input, const char *expected_output, NSString *error_format) = 4049 ^(NSString *test_name, SecTransformRef transform, const char *input, const char *expected_output, NSString *error_format) 4050 { 4051 if (!transform) { 4052 STFail(@"No transform for %@", test_name); 4053 return; 4054 } 4055 4056 CFErrorRef err = NULL; 4057 NSData *input_data = [NSData dataWithBytes:input length:strlen(input)]; 4058 NSData *expected_output_data = [NSData dataWithBytes:expected_output length:strlen(expected_output)]; 4059 SecTransformSetAttribute(transform, kSecTransformInputAttributeName, input_data, &err); 4060 STAssertNil((NSError *)err, @"unexpected error %@ from SecTransformSetAttribute for %@", err, test_name); 4061 NSData *output_data = (NSData *)SecTransformExecute(transform, &err); 4062 [output_data autorelease]; 4063 STAssertNil((NSError *)err, @"Error from %@ execute (in=%s, err=%s)", test_name, input, err); 4064 STAssertNotNil(output_data, @"Unexpected nil output from %@ execute (in=%s)", test_name, input); 4065 if (output_data) { 4066 NSString *output_string = [NSString alloc]; 4067 output_string = [output_string initWithBytes:[output_data bytes] length:[output_data length] encoding:NSMacOSRomanStringEncoding]; 4068 [output_string autorelease]; 4069 NSString *msg = [NSString stringWithFormat:error_format, input, expected_output, output_string]; 4070 STAssertEqualObjects(expected_output_data, output_data, @"%@ %@", test_name, msg); 4071 } 4072 CFRelease(transform); 4073 }; 4074 4075 for(int idx = 0; idx < sizeof(base32_test_vectors)/sizeof(*base32_test_vectors); idx++) 4076 { 4077 SecTransformRef base32encoder = SecEncodeTransformCreate(kSecBase32Encoding, NULL); 4078 test(@"base32 encode", base32encoder, base32_test_vectors[idx].plain_text, base32_test_vectors[idx].base32_rfc4648, @"B32(\"%1$s\") should be \"%2$s\", got \"%3$@\""); 4079 4080 SecTransformRef base32decoder = SecDecodeTransformCreate(kSecBase32Encoding, NULL); 4081 test(@"base32 decode", base32decoder, base32_test_vectors[idx].base32_rfc4648, base32_test_vectors[idx].plain_text, @"B32dec(\"%1$s\") should be \"%2$s\", got \"%3$@\""); 4082 4083 SecTransformRef base32FDEencoder = SecEncodeTransformCreate(CFSTR("base32FDE"), NULL); 4084 test(@"base32FDE encode", base32FDEencoder, base32_test_vectors[idx].plain_text, base32_test_vectors[idx].base32_fde, @"B32(\"%1$s\") should be \"%2$s\", got \"%3$@\""); 4085 4086 SecTransformRef base32FDEdecoder = SecDecodeTransformCreate(CFSTR("base32FDE"), NULL); 4087 test(@"base32FDE decode", base32FDEdecoder, base32_test_vectors[idx].base32_fde, base32_test_vectors[idx].plain_text, @"B32dec(\"%1$s\") should be \"%2$s\", got \"%3$@\""); 4088 } 4089 4090 SecTransformRef bet = SecEncodeTransformCreate(kSecBase32Encoding, NULL); 4091 STAssertNotNil((id)bet, @"got bulk base 32 encoder"); 4092 SecTransformRef bdt = SecDecodeTransformCreate(kSecBase32Encoding, NULL); 4093 STAssertNotNil((id)bdt, @"got bulk base 32 decoder"); 4094 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", bet, bdt, YES), @"Roundtrip base32 /usr/share/dict/words"); 4095 4096 CFRelease(bet); 4097 CFRelease(bdt); 4098 4099 // FDE uses a modified base32 alphabet, we want to test it here. 4100 SecTransformRef FDE_encode_transform = SecEncodeTransformCreate(@"base32FDE", NULL); 4101 STAssertNotNil((id)FDE_encode_transform, @"got FDE encoder"); 4102 SecTransformRef FDE_decode_transform = SecDecodeTransformCreate(@"base32FDE", NULL); 4103 STAssertNotNil((id)FDE_decode_transform, @"got bulk base 32 decoder"); 4104 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", FDE_encode_transform, FDE_decode_transform, YES), @"Roundtrip base32FDE /usr/share/dict/words"); 4105 4106 CFRelease(FDE_encode_transform); 4107 CFRelease(FDE_decode_transform); 4108} 4109 4110-(void)testCodeBase64 { 4111 CFErrorRef error = NULL; 4112 4113#if 0 4114 SecTransformRef tr = SecDecodeTransformCreate(@"Not a real encoding", &error); 4115 // XXX: known failure in Transform::SetAttribute 7707822 -- I would fix on this branch, but I think that code has diverged 4116 STAssertTrue(tr == NULL, @"Checks for invalid encodings"); 4117 NSLog(@"Error: %@", error); 4118#endif 4119 4120 SecTransformRef dt = SecDecodeTransformCreate(kSecBase64Encoding, NULL); 4121 STAssertNotNil((id)dt, @"Got decoder"); 4122 4123 const char raw_data0[] = "Tm90IHV1ZW5jb2RlZAo="; 4124 const char raw_data1[] = "Not uuencoded\n"; 4125 CFDataRef data0 = CFDataCreate(NULL, (const UInt8*)raw_data0, strlen(raw_data0)); 4126 CFDataRef data1 = CFDataCreate(NULL, (const UInt8*)raw_data1, strlen(raw_data1)); 4127 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, data0, NULL); 4128 4129 CFDataRef decoded_data = (CFDataRef)SecTransformExecute(dt, &error); 4130 STAssertNotNil((NSData *)decoded_data, @"Got a decode result"); 4131 STAssertEqualObjects((NSData *)decoded_data, (NSData *)data1, @"Proper decode results"); 4132 4133 SecTransformRef et = SecEncodeTransformCreate(kSecBase64Encoding, NULL); 4134 STAssertNotNil((id)et, @"Got encoder"); 4135 4136 SecTransformSetAttribute(et, kSecTransformInputAttributeName, data1, NULL); 4137 4138 CFDataRef encoded_data = (CFDataRef)SecTransformExecute(et, NULL); 4139 STAssertNotNil((NSData *)encoded_data, @"Got an encode result"); 4140 4141 STAssertEqualObjects((NSData *)encoded_data, (NSData *)data0, @"Proper encode results"); 4142 4143 // Negative testing, assume the following struct 4144 // struct __CFData { 4145 // CFRuntimeBase _base; 4146 // CFIndex _length; /* number of bytes */ 4147 // CFIndex _capacity; /* maximum number of bytes */ 4148 // CFAllocatorRef _bytesDeallocator; /* used only for immutable; if NULL, no deallocation */ 4149 // uint8_t *_bytes; /* compaction: direct access to _bytes is only valid when data is not inline */ 4150 // }; 4151 SecTransformRef et_neg = SecEncodeTransformCreate(kSecBase64Encoding, NULL); 4152 STAssertNotNil((id)et_neg, @"Got encoder for negative testing"); 4153 4154 CFIndex *data1_length=(CFIndex*)((unsigned char *)data1 + sizeof(CFRuntimeBase)); 4155 CFIndex data1_backup=*data1_length; 4156 if (sizeof(CFIndex)==8) 4157 { 4158 *data1_length=0x5ffffffffffffff7; 4159 } 4160 else if (sizeof(CFIndex)==4) 4161 { 4162 *data1_length=0x5ffffff7; 4163 } 4164 else 4165 { 4166 STAssertTrue(false, @"Test error, representation of CFIndex not supported. Sizeof(CFIndex)=%d. Only support 4 or 8",sizeof(CFIndex)); 4167 } 4168 STAssertTrue(CFDataGetLength(data1)==*data1_length, @"Length not properly set - test bug - reads %lu expect %lu",CFDataGetLength(data1),*data1_length); 4169 SecTransformSetAttribute(et_neg, kSecTransformInputAttributeName, data1, NULL); 4170 CFDataRef encoded_data2 = (CFDataRef)SecTransformExecute(et_neg, &error); 4171 STAssertNil((id)encoded_data2, @"No encoded data for negative testing"); 4172 STAssertNotNil((id)error, @"Got error for negative testing"); 4173 *data1_length=data1_backup; 4174 if (error!=NULL) 4175 { 4176 STAssertTrue((CFErrorGetCode(error)==kSecTransformErrorInvalidLength), 4177 @"Error for invalid length, got %lu expect %lu",CFErrorGetCode(error),kSecTransformErrorInvalidLength); 4178 } 4179 // XXX also for general testing we want a "RandomChunkSizer" that copies INPUT to OUTPUT, but makes random size chunks (incl 0) as it goes. 4180 4181 SecTransformRef dt2 = SecDecodeTransformCreate(kSecBase64Encoding, NULL); 4182 SecTransformRef et2 = SecEncodeTransformCreate(kSecBase64Encoding, NULL); 4183 int ll = 75; 4184 SecTransformSetAttribute(et2, kSecEncodeLineLengthAttribute, CFNumberCreate(NULL, kCFNumberIntType, &ll), NULL); 4185 4186 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", et2, dt2, YES), @"Roundtrip base64 /usr/share/dict/words"); 4187 4188 CFRelease(et2); 4189 CFRelease(dt2); 4190 CFRelease(et); 4191 CFRelease(et_neg); 4192 CFRelease(dt); 4193} 4194 4195static SecTransformInstanceBlock ErrorResultsTest(CFStringRef name, 4196 SecTransformRef newTransform, 4197 SecTransformImplementationRef ref) 4198{ 4199 SecTransformInstanceBlock instanceBlock = 4200 ^{ 4201 CFErrorRef result = NULL; 4202 SecTransformSetDataAction(ref, kSecTransformActionProcessData, 4203 ^(CFTypeRef value) 4204 { 4205 if (value != NULL) 4206 { 4207 return (CFTypeRef)CFErrorCreate(NULL, CFSTR("expected error"), 42, NULL); 4208 } 4209 else 4210 { 4211 return SecTransformNoData(); 4212 } 4213 }); 4214 4215 return result; 4216 }; 4217 4218 return Block_copy(instanceBlock); 4219} 4220 4221 4222-(void)testErrorResults { 4223 CFStringRef name = CFSTR("com.apple.security.unit-test.error-results"); 4224 SecTransformRegister(name, &ErrorResultsTest, NULL); 4225 4226 SecTransformRef tr = SecTransformCreate(name, NULL); 4227 CFDataRef data = CFDataCreate(NULL, NULL, 0); 4228 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL); 4229 4230 CFErrorRef err = NULL; 4231 CFTypeRef no_result = SecTransformExecute(tr, &err); 4232 4233 STAssertErrorHas((id)err, @"expected error", @"Signaled error has original string"); 4234 STAssertErrorHas((id)err, @"42", @"Signaled error has original error code"); 4235 STAssertNil((id)no_result, @"No result from erroring transform"); 4236 CFRelease(data); 4237 CFRelease(tr); 4238 CFRelease(err); 4239} 4240 4241-(void)testErrorExecutesInRightQueue { 4242 // testExecuteBlock checks to see if blocks are generally executed on the proper queue, this specifically checks 4243 // for an error while starting (which was originally improperly coded). 4244 4245 SecTransformRef unassigned_input = SecNullTransformCreate(); 4246 dispatch_queue_t q = dispatch_queue_create("com.apple.unit-test.ErrorExecutesInRightQueue", NULL); 4247 dispatch_group_t got_final = dispatch_group_create(); 4248 dispatch_group_enter(got_final); 4249 __block bool saw_data = false; 4250 __block bool saw_error = false; 4251 4252 SecTransformExecuteAsync(unassigned_input, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) { 4253 STAssertEquals(q, const_cast<const dispatch_queue_t>(dispatch_get_current_queue()), @"Should be running on %p, but is running on %p", q, dispatch_get_current_queue()); 4254 saw_data = saw_data || (message != NULL); 4255 saw_error = saw_error || (error != NULL); 4256 if (isFinal) { 4257 dispatch_group_leave(got_final); 4258 } 4259 }); 4260 4261 STAssertFalse(dispatch_group_wait(got_final, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"Execute completed"); 4262 STAssertFalse(saw_data, @"Should have seen no data (but did)"); 4263 STAssertTrue(saw_error, @"Should have seen error (but didn't)"); 4264 4265 CFRelease(unassigned_input); 4266 dispatch_group_notify(got_final, q, ^{ 4267 dispatch_release(got_final); 4268 dispatch_release(q); 4269 }); 4270 4271} 4272 4273-(void)testSignVerify { 4274 unsigned char *raw_message = (unsigned char *)"Controlling complexity is the essence of computer programming. - Brian Kernigan"; 4275 dispatch_group_t dg = dispatch_group_create(); 4276 CFErrorRef err = NULL; 4277 CFDataRef message = CFDataCreate(NULL, raw_message, strlen((const char *)raw_message)); 4278 __block SecKeyRef rsa_pub_key = NULL; 4279 __block SecKeyRef rsa_priv_key = NULL; 4280 __block SecKeyRef ecdsa_pub_key = NULL; 4281 __block SecKeyRef ecdsa_priv_key = NULL; 4282 __block SecKeyRef dsa_pub_key = NULL; 4283 __block SecKeyRef dsa_priv_key = NULL; 4284 4285 char *tmp_dir; 4286 asprintf(&tmp_dir, "%s/sign-verify-test-keychain-", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp"); 4287 4288 unsigned char *raw_bad_message = (unsigned char *)"Standards are great, there are so many to choose from - Andrew S. Tanenbaum (maybe)"; 4289 CFDataRef bad_message = CFDataCreate(NULL, raw_bad_message, strlen((const char *)raw_bad_message)); 4290 4291 // when safe replace with a concurrent queue 4292 dispatch_queue_t key_q = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 4293 4294 dispatch_group_async(dg, key_q, 4295 ^{ 4296 NSAutoreleasePool *pool = [NSAutoreleasePool new]; 4297 4298 // (note the key must be bigger then a SHA2-256 signature plus the DER.1 packing of the OID, so 1024 was chosen for that, not speed or safety) 4299 NSDictionary *key_opts = [NSDictionary dictionaryWithObjectsAndKeys: 4300 (NSString *)kSecAttrKeyTypeRSA, (NSString *)kSecAttrKeyType, 4301 [NSNumber numberWithInt:1024], (NSString *)kSecAttrKeySizeInBits, 4302 @"RSA transform unit test key", (NSString *)kSecAttrLabel, 4303 nil]; 4304 OSStatus gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &rsa_pub_key, &rsa_priv_key); 4305 STAssertTrue(gp_status == 0, @"RSA (gp_status=0x%x)", gp_status); 4306 [pool drain]; 4307 }); 4308 4309 dispatch_group_async(dg, key_q, 4310 ^{ 4311 OSStatus gp_status; 4312#if 0 4313 // I don't know how "safe" a 512 bit ECDSA key is, but again this is just for testing, not for signing any real data 4314 NSDictionary *key_opts = [NSDictionary dictionaryWithObjectsAndKeys: 4315 (NSString *)kSecAttrKeyTypeECDSA, (NSString *)kSecAttrKeyType, 4316 [NSNumber numberWithInt:512], (NSString *)kSecAttrKeySizeInBits, 4317 @"ECDSA transform unit test key", (NSString *)kSecAttrLabel, 4318 nil]; 4319 gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &ecdsa_pub_key, &ecdsa_priv_key); 4320#else 4321 { 4322 SecKeychainRef tmp_keychain = NULL; 4323 gp_status = SecKeyCreatePair(tmp_keychain, CSSM_ALGID_ECDSA, 256, NULL, 4324 CSSM_KEYUSE_VERIFY, 4325 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT, 4326 CSSM_KEYUSE_SIGN, 4327 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT, 4328 NULL, &ecdsa_pub_key, &ecdsa_priv_key); 4329 } 4330#endif 4331 if (gp_status) 4332 { 4333 STAssertTrue(gp_status == 0, @"ECDSA (gp_status=0x%x)", gp_status); 4334 } 4335 }); 4336 4337 dispatch_group_async(dg, key_q, 4338 ^{ 4339 OSStatus gp_status; 4340#if 0 4341 // I don't know how "safe" a 1024 bit DSA key is, but again this is just for testing, not for signing any real data 4342 NSDictionary *key_opts = [NSDictionary dictionaryWithObjectsAndKeys:(NSString *)kSecAttrKeyTypeDSA, 4343 (NSString *)kSecAttrKeyType, [NSNumber numberWithInt:512], (NSString *)kSecAttrKeySizeInBits, nil]; 4344 gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &ecdsa_pub_key, &ecdsa_priv_key); 4345#else 4346 { 4347 const char *passwd = "this is not secret"; 4348 SecKeychainRef tmp_keychain = NULL; 4349 char *kcfname; 4350 asprintf(&kcfname, "%s-DSA-XXXXXXXXXX", tmp_dir); 4351 // NOTE: "mktemp" isn't as safe as you might think...but this is test code and doesn't have to be, but 4352 // if you copy it elsewhere you may well need to rewrite it. (use mkstemp) 4353 mktemp(kcfname); 4354 gp_status = SecKeychainCreate(kcfname, (UInt32) strlen(passwd), passwd, NO, NULL, &tmp_keychain); 4355 STAssertTrue(gp_status == 0, @"SecKeychainCreate (gp_status=0x%x)", gp_status); 4356 gp_status = SecKeyCreatePair(tmp_keychain, CSSM_ALGID_DSA, 512, NULL, 4357 CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_WRAP, 4358 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_RETURN_REF, 4359 CSSM_KEYUSE_SIGN|CSSM_KEYUSE_DECRYPT|CSSM_KEYUSE_UNWRAP, 4360 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_RETURN_REF, 4361 NULL, &dsa_pub_key, &dsa_priv_key); 4362 free(kcfname); 4363 } 4364#endif 4365 STAssertTrue(gp_status == 0, @"DSA (gp_status=0x%x)", gp_status); 4366 }); 4367 4368 struct sv_test { 4369 NSString *name; 4370 SecKeyRef pub_key, priv_key; 4371 CFDataRef msg_sign, msg_verify; 4372 CFTypeRef dalgo_sign, dalgo_verify; 4373 int dlen_sign, dlen_verify; 4374 BOOL pass; 4375 }; 4376 4377 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER); 4378 4379 struct sv_test sv_tests[] = 4380 { 4381 {@"Basic RSA", rsa_pub_key, rsa_priv_key, message, message, NULL, NULL, 0, 0, YES}, 4382 {@"Basic RSA (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, NULL, NULL, 0, 0, NO}, 4383 {@"RSA, mismatched digest algos", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA1, 0, 0, NO}, 4384 4385 {@"RSA SHA1 MD5", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, YES}, 4386 {@"RSA SHA1 MD5 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, NO}, 4387 4388 {@"RSA MD5", rsa_pub_key, rsa_priv_key, message, message, kSecDigestMD5, kSecDigestMD5, 0, 0, YES}, 4389 {@"RSA MD5 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestMD5, kSecDigestMD5, 0, 0, NO}, 4390 4391 {@"RSA MD2", rsa_pub_key, rsa_priv_key, message, message, kSecDigestMD2, kSecDigestMD2, 0, 0, YES}, 4392 {@"RSA MD2 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestMD2, kSecDigestMD2, 0, 0, NO}, 4393 4394 {@"RSA SHA2 512", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, YES}, 4395 {@"RSA SHA2 512 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, NO}, 4396 {@"RSA SHA2 512 vs. 384", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 512, 384, NO}, 4397 4398 {@"RSA SHA2 384", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, YES}, 4399 {@"RSA SHA2 384 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, NO}, 4400 4401 {@"RSA SHA2 256", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, YES}, 4402 {@"RSA SHA2 256 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, NO}, 4403 4404 {@"RSA SHA2 224", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, YES}, 4405 {@"RSA SHA2 224 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, NO}, 4406 4407 {@"RSA SHA2 0", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, YES}, 4408 {@"RSA SHA2 0 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, NO}, 4409 4410 {@"Basic ECDSA", ecdsa_pub_key, ecdsa_priv_key, message, message, NULL, NULL, 0, 0, YES}, 4411 {@"Basic ECDSA (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, NULL, NULL, 0, 0, NO}, 4412 {@"ECDSA (mismatched digest algos)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA1, 0, 0, NO}, 4413 4414 {@"ECDSA SHA1", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, YES}, 4415 {@"ECDSA SHA1 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, NO}, 4416 4417 {@"ECDSA SHA2 224", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, YES}, 4418 {@"ECDSA SHA2 224 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, NO}, 4419 4420 {@"ECDSA SHA2 256", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, YES}, 4421 {@"ECDSA SHA2 256 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, NO}, 4422 4423 {@"ECDSA SHA2 384", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, YES}, 4424 {@"ECDSA SHA2 384 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, NO}, 4425 4426 {@"ECDSA SHA2 512", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, YES}, 4427 {@"ECDSA SHA2 512 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, NO}, 4428 4429 {@"ECDSA SHA2 0", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, YES}, 4430 {@"ECDSA SHA2 0 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, NO}, 4431 4432 {@"Basic DSA", dsa_pub_key, dsa_priv_key, message, message, NULL, NULL, 0, 0, YES}, 4433 {@"Basic DSA (tampered data)", dsa_pub_key, dsa_priv_key, message, bad_message, NULL, NULL, 0, 0, NO}, 4434 // only SHA1 is supported, so no mismatched digest algo test is available 4435 4436 {@"DSA SHA1", dsa_pub_key, dsa_priv_key, message, message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, YES}, 4437 {@"DSA SHA1 (tampered data)", dsa_pub_key, dsa_priv_key, message, bad_message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, NO}, 4438 }; 4439 4440 free(tmp_dir); 4441 4442 int i; 4443 for(i = 0; i < sizeof(sv_tests)/sizeof(sv_test); i++) 4444 { 4445 CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest}; 4446 //CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest, kSecInputIsRaw}; 4447 const int ilim = sizeof(input_cases)/sizeof(input_cases[0]); 4448 int ii = 0, ij = 0; 4449 for(; ii < ilim; ++ii) 4450 { 4451 for(ij = 0; ij < ilim; ++ij) 4452 { 4453 err = NULL; 4454 struct sv_test *tst = sv_tests + i; 4455 NSString *tname = [NSString stringWithFormat:@"%@ %@ %@", tst->name, input_cases[ii], input_cases[ij]]; 4456 4457 CFStringRef sign_input_is = input_cases[ii]; 4458 CFStringRef verify_input_is = input_cases[ij]; 4459 4460 if (sign_input_is != kSecInputIsPlainText && tst->dalgo_sign == NULL) { 4461 continue; 4462 } 4463 if (verify_input_is != kSecInputIsPlainText && tst->dalgo_verify == NULL) { 4464 continue; 4465 } 4466 4467 if ((sign_input_is == kSecInputIsRaw || verify_input_is == kSecInputIsRaw) && [tst->name rangeOfString:@"RSA"].location == NSNotFound) { 4468 // we can only synthesize these tests for RSA 4469 NSLog(@"No %@ test", tname); 4470 continue; 4471 } 4472 4473 STAssertNotNil((id)tst->pub_key, @"Have pub_key for %@", tname); 4474 STAssertNotNil((id)tst->priv_key, @"Have priv_key for %@", tname); 4475 4476 if (tst->pub_key == nil || tst->priv_key == nil) { 4477 continue; 4478 } 4479 4480 SecTransformRef sign = SecSignTransformCreate(tst->priv_key, &err); 4481 STAssertNil((NSError *)err, @"creating sign for %@", tname); 4482 STAssertNotNil((id)sign, @"Creating sign for %@", tname); 4483 4484 if (sign == NULL) { 4485 continue; 4486 } 4487 4488 SecTransformRef verify = SecVerifyTransformCreate(tst->pub_key, NULL, &err); 4489 STAssertNotNil((id)verify, @"Creating verify for %@", tname); 4490 STAssertNil((NSError *)err, @"Creating verify for %@", tname); 4491 4492 if (verify == NULL) { 4493 continue; 4494 } 4495 4496 SecTransformRef sign_digest = NULL; 4497 SecTransformRef verify_digest = NULL; 4498 SecTransformRef sign2 = NULL; 4499 4500 if (tst->dalgo_sign) 4501 { 4502 SecTransformSetAttribute(sign, kSecDigestTypeAttribute, tst->dalgo_sign, &err); 4503 STAssertNil((NSError *)err, @"Setting sign's digest type for %@", tname); 4504 SecTransformSetAttribute(sign, kSecDigestLengthAttribute, [NSNumber numberWithInt:tst->dlen_sign], &err); 4505 STAssertNil((NSError *)err, @"Setting sign's digest length for %@", tname); 4506 4507 if (sign_input_is == kSecInputIsDigest) 4508 { 4509 sign_digest = SecDigestTransformCreate(tst->dalgo_sign, tst->dlen_sign, &err); 4510 STAssertNotNil((id)sign_digest, @"Create sign's %@-%d digest transform (for %@)", tst->dalgo_sign, tst->dlen_sign, tname); 4511 STAssertNil((NSError *)err, @"Making sign's digester (for %@) - err=%@", tname, err); 4512 4513 SecTransformSetAttribute(sign, kSecInputIsAttributeName, sign_input_is, &err); 4514 STAssertNil((NSError *)err, @"Setting sign's InputIs (for %@) - err=%@", tname, err); 4515 } 4516 } 4517 4518 if (tst->dalgo_verify) { 4519 SecTransformSetAttribute(verify, kSecDigestTypeAttribute, tst->dalgo_verify, &err); 4520 STAssertNil((NSError *)err, @"Setting verify's digest type for %@", tname); 4521 SecTransformSetAttribute(verify, kSecDigestLengthAttribute, [NSNumber numberWithInt:tst->dlen_verify], &err); 4522 STAssertNil((NSError *)err, @"Setting verify's digest length for %@", tname); 4523 4524 if (verify_input_is == kSecInputIsDigest) { 4525 verify_digest = SecDigestTransformCreate(tst->dalgo_verify, tst->dlen_verify, &err); 4526 STAssertNotNil((id)verify_digest, @"Create verify's %@-%d digest transform (for %@)", tst->dalgo_verify, tst->dlen_verify, tname); 4527 STAssertNil((NSError *)err, @"Making verify's digester (for %@) - err=%@", tname, err); 4528 4529 SecTransformSetAttribute(verify, kSecInputIsAttributeName, verify_input_is, &err); 4530 STAssertNil((NSError *)err, @"Setting verify's InputIs (for %@) - err=%@", tname, err); 4531 } 4532 } 4533 4534 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 4535 SecTransformSetAttribute(sign_digest ? sign_digest : sign, kSecTransformInputAttributeName, tst->msg_sign, (CFErrorRef *)&err); 4536 if (sign_digest) { 4537 STAssertNil((NSError *)err, @"Setting sign's digest's input for %@", tname); 4538 SecTransformConnectTransforms(sign_digest, kSecTransformOutputAttributeName, 4539 sign, kSecTransformInputAttributeName, group, NULL); 4540 } else { 4541 STAssertNil((NSError *)err, @"Setting sign's input for %@", tname); 4542 } 4543 4544 4545 SecTransformSetAttribute(verify_digest ? verify_digest : verify, kSecTransformInputAttributeName, tst->msg_verify, (CFErrorRef *)&err); 4546 if (verify_digest) { 4547 STAssertNil((NSError *)err, @"Setting verify's digest's input for %@", tname); 4548 SecTransformConnectTransforms(verify_digest, kSecTransformOutputAttributeName, 4549 verify, kSecTransformInputAttributeName, group, NULL); 4550 } else { 4551 STAssertNil((NSError *)err, @"Setting verify's input for %@", tname); 4552 } 4553 4554 SecTransformConnectTransforms(sign2 ? sign2 : sign, kSecTransformOutputAttributeName, verify, kSecSignatureAttributeName, group, NULL); 4555 4556 dispatch_group_enter(dg); 4557 dispatch_queue_t temp_q = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 4558 SecTransformExecuteAsync(sign, temp_q, 4559 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) 4560 { 4561 if (message) 4562 { 4563 if (tst->pass) 4564 { 4565 STAssertTrue(message == kCFBooleanTrue, @"Failed to verify proper signature %@; message = %@", tname, message); 4566 } else 4567 { 4568 STAssertTrue(message == kCFBooleanFalse, @"Failed to detect tampering %@; message = %@", tname, message); 4569 } 4570 } 4571 4572 STAssertNil((NSError *)err, @"Executed ok for %@ (err=%@)", tname, error); 4573 4574 if (isFinal) 4575 { 4576 dispatch_group_leave(dg); 4577 } 4578 }); 4579 4580 CFRelease(sign); 4581 CFRelease(verify); 4582 CFRelease(group); 4583 } 4584 } 4585 } 4586 4587 struct raw_test { 4588 SecKeyRef pub, priv; 4589 NSString *name; 4590 } raw_tests[] = { 4591 {rsa_pub_key, rsa_priv_key, @"RSA raw test"}, 4592 {dsa_pub_key, dsa_priv_key, @"DSA raw test"}, 4593 {ecdsa_pub_key, ecdsa_priv_key, @"ECDSA raw test"}, 4594 }; 4595 4596 for(i = 0; i < sizeof(raw_tests)/sizeof(raw_tests[0]); ++i) { 4597 raw_test *t = raw_tests + i; 4598 SecTransformRef tee = SecNullTransformCreate(); 4599 const char *raw_bytes = "some bytes"; 4600 CFDataRef bytes = CFDataCreate(NULL, (UInt8*)raw_bytes, strlen(raw_bytes)); 4601 CFErrorRef err = NULL; 4602 4603 SecTransformRef sign = SecSignTransformCreate(t->priv, &err); 4604 STAssertNil((id)err, @"%@ test sign create err=%@", t->name, err); 4605 4606 SecTransformRef verify = SecVerifyTransformCreate(t->pub, NULL, &err); 4607 STAssertNil((id)err, @"%@ test verify create err=%@", t->name, err); 4608 4609 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 4610 SecTransformConnectTransforms(sign, kSecTransformOutputAttributeName, verify, kSecSignatureAttributeName, group, &err); 4611 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, sign, kSecTransformInputAttributeName, group, &err); 4612 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, verify, kSecTransformInputAttributeName, group, &err); 4613 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, bytes, &err); 4614 STAssertNil((id)err, @"%@ setup error=%@", t->name, err); 4615 CFRetain(group); 4616 dispatch_group_async(dg, dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 4617 CFErrorRef xerr = NULL; 4618 CFTypeRef result = SecTransformExecute(group, &xerr); 4619 CFRelease(group); 4620 4621 if (result) { 4622 STAssertTrue(result == kCFBooleanTrue, @"%@ sign result=%@", t->name, result); 4623 } else { 4624 STFail(@"%@ no result", t->name); 4625 } 4626 STAssertNil((id)err, @"%@ execute error=%@", t->name, xerr); 4627 }); 4628 CFRelease(group); 4629 } 4630 4631 // Test some things we want to fail for: 4632 4633 SecTransformRef tee = SecNullTransformCreate(); 4634 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, message, NULL); 4635 SecTransformRef vrfy = SecVerifyTransformCreate(ecdsa_pub_key, NULL, NULL); 4636 4637 SecGroupTransformRef group = SecTransformCreateGroupTransform(); 4638 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, vrfy, kSecSignatureAttributeName, group, NULL); 4639 SecTransformSetAttribute(vrfy, kSecDigestTypeAttribute, CFSTR("No such type"), NULL); 4640 SecTransformSetAttribute(vrfy, kSecTransformInputAttributeName, message, NULL); 4641 err = NULL; 4642 CFTypeRef no_result = SecTransformExecute(group, (CFErrorRef*)&err); 4643 CFRelease(group); 4644 4645 STAssertNil((id)no_result, @"No result from nonexistent digest"); 4646 STAssertErrorHas((id)err, @"[Ii]nvalid digest algorithm", @"Error message describes nature of error (%@)", err); 4647 STAssertErrorHas((id)err, @"ECDSA signature", @"Error is not overly general (%@)", err); 4648 STAssertErrorHas((id)err, @"ECDSA signature", @"Error is not overly general (%@)", err); 4649 STAssertErrorHas((id)err, @"SHA1.*SHA2", @"Error describes valid algorithms (%@)", err); 4650 CFRelease(vrfy); 4651 4652 // It would be awesome if we supported all the digests, and this test went away. 4653 vrfy = SecVerifyTransformCreate(dsa_pub_key, message, NULL); 4654 tee = SecNullTransformCreate(); 4655 4656 group = SecTransformCreateGroupTransform(); 4657 SecTransformConnectTransforms(vrfy, kSecSignatureAttributeName, tee, kSecTransformOutputAttributeName, group, NULL); 4658 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, vrfy, kSecTransformInputAttributeName, group, NULL); 4659 SecTransformSetAttribute(vrfy, kSecDigestTypeAttribute, kSecDigestSHA2, NULL); 4660 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, message, NULL); 4661 err = NULL; 4662 no_result = SecTransformExecute(group, (CFErrorRef*)&err); 4663 CFRelease(group); 4664 4665 STAssertNil((id)no_result, @"No result from invalid digest"); 4666 STAssertErrorHas((id)err, @"[Ii]nvalid digest algorithm", @"Error message gives problem statement (%@)", err); 4667 STAssertErrorHas((id)err, @"[^A-Z]DSA signature", @"Error is not overly general (%@)", err); 4668 STAssertErrorHas((id)err, @"SHA1", @"Correct algorithm is named (%@)", err); 4669 4670 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER); 4671} 4672 4673static BOOL keyWithBytes(CFDataRef keyData, SecKeyRef* key, CFTypeRef keyClass) { 4674 CFErrorRef errorRef=NULL; 4675 CFMutableDictionaryRef parameters; 4676 parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 10, NULL, NULL); 4677 4678 /* 4679 kSecAttrKeyClass values: 4680 kSecAttrKeyClassPublic 4681 kSecAttrKeyClassPrivate 4682 kSecAttrKeyClassSymmetric 4683 */ 4684 CFDictionaryAddValue(parameters, kSecAttrKeyClass, keyClass); 4685 CFDictionaryAddValue(parameters, kSecAttrIsPermanent, kCFBooleanFalse); /* also means we have raw bits */ 4686 CFDictionaryAddValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA); /* also means we have raw bits */ 4687 *key = SecKeyCreateFromData(parameters, keyData, &errorRef); 4688 CFRelease(parameters); 4689 return (key != NULL); 4690} 4691 4692-(void)testVerifyWithKeyFromBytes { 4693 /* 4694 static const uint8_t original_pubKeyData[] = 4695 { 4696 0x30, 0x48, 0x02, 0x41, 0x00, 0xd1, 0x4d, 0x1c, 0xe6, 0xbd, 0xd6, 0x8c, 0x4b, 0x77, 0x1e, 0x9f, 4697 0xbc, 0xe1, 0xf6, 0x96, 0xf2, 0x55, 0xa2, 0xdc, 0x28, 0x36, 0x39, 0xf4, 0xec, 0x5b, 0x85, 0x9b, 4698 0x3c, 0x7f, 0x98, 0xe0, 0xed, 0x49, 0xf5, 0x44, 0xb1, 0x87, 0xa8, 0xf6, 0x7f, 0x55, 0xc0, 0x39, 4699 0xf0, 0xe7, 0xcc, 0x9c, 0x84, 0xde, 0x7d, 0x9a, 0x87, 0x38, 0xf2, 0x4b, 0x11, 0x6f, 0x63, 0x90, 4700 0xfc, 0x72, 0x2c, 0x86, 0xa3, 0x02, 0x03, 0x01, 0x00, 0x01 4701 }; */ 4702 4703 // openssl genrsa -out /tmp/rsa512.pem 4704 // openssl rsa -inform PEM -in /tmp/rsa512.pem -outform DER -out /tmp/rsa512.der 4705 // hexdump -C /tmp/rsa512.der | cut -c10-58 | tr -s ' ' ' ' | sed -e 's/ /, 0x/g' -e 's/$/,/' | cut -c3-|pbcopy 4706 static const uint8_t pubKeyData[] = { 4707 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 4708 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xbf, 0xd5, 0xce, 0x43, 0x59, 0xd5, 0xf8, 4709 0x41, 0xb2, 0xe1, 0x16, 0x02, 0x2a, 0x16, 0xcb, 0xef, 0x49, 0xea, 0x98, 0x71, 0xf8, 0xfb, 0x94, 4710 0x23, 0x12, 0xf7, 0xbc, 0x80, 0xd0, 0x8b, 0xfd, 0x29, 0xb8, 0xfc, 0x2c, 0x3d, 0x13, 0x6f, 0x37, 4711 0xef, 0xa7, 0x1e, 0xf9, 0x4c, 0x3d, 0x38, 0x3a, 0x2f, 0x6b, 0xa8, 0x16, 0x00, 0x27, 0x5a, 0xbe, 4712 0x3d, 0x61, 0xdd, 0x18, 0x45, 0x22, 0xdb, 0x1a, 0xff, 0x02, 0x03, 0x01, 0x00, 0x01, 4713 }; 4714 static const uint8_t signatureData[] = 4715 { 4716 0xbc, 0x76, 0x2a, 0x50, 0x4e, 0x17, 0x0b, 0xa9, 0x31, 0x3b, 0xc5, 0xb0, 0x4d, 0x2a, 0x01, 0x9a, 4717 0xbb, 0x5e, 0x7b, 0x6e, 0x90, 0x2f, 0xaf, 0x3f, 0x40, 0xdb, 0xb0, 0xfc, 0x49, 0xcf, 0xbb, 0xb6, 4718 0x08, 0xf0, 0xbb, 0x04, 0x5f, 0x89, 0x0b, 0x10, 0x47, 0x06, 0x93, 0xb3, 0xb7, 0x0b, 0x4e, 0x17, 4719 0xe9, 0xb1, 0x55, 0x94, 0x63, 0x30, 0x0b, 0xa3, 0xb1, 0x28, 0xba, 0xe8, 0xef, 0xb4, 0xbd, 0xc5 4720 }; 4721 4722 const char *raw_data = "Data to verify"; 4723 CFDataRef data = CFDataCreate(NULL, (UInt8*) raw_data, strlen(raw_data)); 4724 4725 SecKeyRef key; 4726 CFDataRef cfkeybytes; 4727 CFErrorRef error; 4728 cfkeybytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pubKeyData, sizeof(pubKeyData),kCFAllocatorNull); 4729 4730 if(keyWithBytes(cfkeybytes, &key, kSecAttrKeyClassPublic)){ 4731 CFDataRef signature = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, signatureData, sizeof(signatureData),kCFAllocatorNull); 4732 SecTransformRef vt = SecVerifyTransformCreate(key,signature,&error); 4733 SecTransformSetAttribute(vt, kSecTransformDebugAttributeName, @"YES", NULL); 4734 SecTransformSetAttribute(vt, kSecTransformInputAttributeName, data, &error); 4735 CFBooleanRef signature_ok = (CFBooleanRef) SecTransformExecute(vt, &error); 4736 4737 CFRelease(vt); 4738 CFRelease(key); 4739 CFRelease(signature); 4740 CFRelease(data); 4741 CFRelease(cfkeybytes); 4742 4743 NSLog(@"STE result %@, err=%@", signature_ok, error); 4744 STAssertNil((id)error, @"Error from SecTransformExecute: %@", error); 4745 } else { 4746 STFail(@"Can't get SecKeyCreateFromData to work"); 4747 } 4748} 4749 4750-(void)testAESAndCastKeysFromBytes { 4751 CFErrorRef err = NULL; 4752 struct tcase { 4753 const char *name; 4754 CFTypeRef key_type; 4755 NSData *key_data; 4756 }; 4757 const char *aes_kbytes = "0123456789012345"; 4758 const char *cast_kbytes = "01234567"; 4759 4760 struct tcase cases[] = { 4761 {"AES", kSecAttrKeyTypeAES, [NSData dataWithBytes:aes_kbytes length:strlen(aes_kbytes)]}, 4762 {"CAST", kSecAttrKeyTypeCAST, [NSData dataWithBytes:cast_kbytes length:strlen(cast_kbytes)]}, 4763 }; 4764 4765 int i; 4766 for(i = 0; i < sizeof(cases)/sizeof(cases[0]); ++i) { 4767 NSDictionary *parm = [NSDictionary dictionaryWithObjectsAndKeys: 4768 (id)kSecAttrKeyClassSymmetric, kSecAttrKeyClass, 4769 (id)cases[i].key_type, kSecAttrKeyType, 4770 (id)kCFBooleanFalse, kSecAttrIsPermanent, 4771 NULL]; 4772 4773 SecKeyRef k = SecKeyCreateFromData((CFDictionaryRef)parm, (CFDataRef)cases[i].key_data, (CFErrorRef *)&err); 4774 STAssertNotNil((id)k, @"%s SecKeyCreateFromData didn't", cases[i].name); 4775 STAssertNil((id)err, @"%s SecKeyCreateFromData err=%@", err); 4776 4777 SecTransformRef et = SecEncryptTransformCreate(k, &err); 4778 STAssertNotNil((id)et, @"No %s EncryptTransform created", cases[i].name); 4779 STAssertNil((id)err, @"Error from %s SecEncryptTransformCreate err=%@", cases[i].name, err); 4780 4781 SecTransformRef dt = SecDecryptTransformCreate(k, &err); 4782 STAssertNotNil((id)dt, @"No %s DecryptTransform created", cases[i].name); 4783 STAssertNil((id)err, @"Error from %s SecDecryptTransformCreate err=%@", cases[i].name, err); 4784 4785 if (k) { 4786 BOOL rt_ok = RoundTrip(CFSTR("/usr/share/dict/propernames"), et, dt, YES); 4787 CFRelease(et); 4788 CFRelease(dt); 4789 STAssertTrue(rt_ok, @"%s's round trip", cases[i].name); 4790 } 4791 } 4792} 4793 4794-(void)testDispatchAsumptions { 4795 // Failures here don't directly indicate we have a bug. It would indicate that 4796 // either dispatch has one, or that we rely on something dispatch never promised 4797 // and has changed. 4798 4799 dispatch_semaphore_t pre_sem = dispatch_semaphore_create(0); 4800 dispatch_semaphore_t post_sem = dispatch_semaphore_create(0); 4801 __block bool pre_wait_works = false; 4802 4803 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 4804 STAssertTrue(0 == dispatch_semaphore_wait(pre_sem, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"semaphore signal prior to wait pre-wakes"); 4805 pre_wait_works = true; 4806 dispatch_semaphore_signal(post_sem); 4807 }); 4808 dispatch_semaphore_signal(pre_sem); 4809 STAssertTrue(0 == dispatch_semaphore_wait(post_sem, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"signal after wait wakes"); 4810 STAssertTrue(pre_wait_works, @"pre-wait worked"); 4811 4812 4813} 4814 4815// Build a group containing 3 subgroups, G1 which has 2 encoders, G2 and G3 which have one 4816// decoder each. Exports and attributes are hooked up so execution results in a CFData 4817// with the same contents as input_data. "self" is used by the STAssert macros. 4818// The various transforms are assigned names: G1, G2, G3, E64, EZLIB, DZLIB, D64. 4819static SecTransformRef build_nested_groups(id self, CFDataRef input_data) { 4820 SecGroupTransformRef outer = SecTransformCreateGroupTransform(); 4821 SecGroupTransformRef g1 = SecTransformCreateGroupTransform(); 4822 SecGroupTransformRef g2 = SecTransformCreateGroupTransform(); 4823 SecGroupTransformRef g3 = SecTransformCreateGroupTransform(); 4824 4825 CFErrorRef err = NULL; 4826 4827 SecTransformSetAttribute(outer, kSecTransformTransformName, CFSTR("OUTER"), &err); 4828 STAssertNil((id)err, @"Can't set outer's name: %@", err); 4829 SecTransformSetAttribute(g1, kSecTransformTransformName, CFSTR("G1"), &err); 4830 STAssertNil((id)err, @"Can't set g1's name: %@", err); 4831 SecTransformSetAttribute(g2, kSecTransformTransformName, CFSTR("G2"), &err); 4832 STAssertNil((id)err, @"Can't set g2's name: %@", err); 4833 SecTransformSetAttribute(g3, kSecTransformTransformName, CFSTR("G3"), &err); 4834 STAssertNil((id)err, @"Can't set g3's name: %@", err); 4835 4836 SecTransformRef e64 = SecEncodeTransformCreate(kSecBase64Encoding, &err); 4837 STAssertNil((id)err, @"Expected err to be nil, got: %@", err); 4838 STAssertNotNil((id)e64, @"Could not make Encode64 transform"); 4839 SecTransformSetAttribute(e64, kSecTransformTransformName, CFSTR("E64"), NULL); 4840 SecTransformRef ezlib = SecEncodeTransformCreate(kSecZLibEncoding, &err); 4841 STAssertNil((id)err, @"Expected err to be nil, got: %@", err); 4842 STAssertNotNil((id)ezlib, @"Could not make Encode ZLib transform"); 4843 SecTransformSetAttribute(ezlib, kSecTransformTransformName, CFSTR("EZLIB"), NULL); 4844 4845 SecTransformConnectTransforms(e64, kSecTransformOutputAttributeName, ezlib, kSecTransformInputAttributeName, g1, &err); 4846 STAssertNil((id)err, @"Can't connect e64 to ezlib: %@", err); 4847 SecTransformConnectTransforms(g1, kSecTransformInputAttributeName, e64, kSecTransformInputAttributeName, g1, &err); 4848 STAssertNil((id)err, @"Can't connect g1's input to e64's input: %@", err); 4849 SecTransformConnectTransforms(ezlib, kSecTransformOutputAttributeName, g1, kSecTransformOutputAttributeName, g1, &err); 4850 STAssertNil((id)err, @"Can't connect ezlib's output to g1's output: %@", err); 4851 4852 SecTransformRef dzlib = SecDecodeTransformCreate(kSecZLibEncoding, &err); 4853 STAssertNil((id)err, @"Expected err to be nil, got: %@", err); 4854 STAssertNotNil((id)dzlib, @"Could not make Decode ZLib transform"); 4855 SecTransformSetAttribute(dzlib, kSecTransformTransformName, CFSTR("dzlib"), NULL); 4856 SecTransformRef d64 = SecDecodeTransformCreate(kSecBase64Encoding, &err); 4857 STAssertNil((id)err, @"Expected err to be nil, got: %@", err); 4858 STAssertNotNil((id)d64, @"Could not make Decode64 transform"); 4859 SecTransformSetAttribute(dzlib, kSecTransformTransformName, CFSTR("D64"), NULL); 4860 4861 // putting just one transform in g2 and g3 4862 SecTransformConnectTransforms(g2, kSecTransformInputAttributeName, dzlib, kSecTransformInputAttributeName, g2, &err); 4863 STAssertNil((id)err, @"Can't connect g2's input to dzlib's input: %@", err); 4864 SecTransformConnectTransforms(dzlib, kSecTransformOutputAttributeName, g2, kSecTransformOutputAttributeName, g2, &err); 4865 STAssertNil((id)err, @"Can't connect dzlib's output to g2's output: %@", err); 4866 4867 SecTransformConnectTransforms(g3, kSecTransformInputAttributeName, d64, kSecTransformInputAttributeName, g3, &err); 4868 STAssertNil((id)err, @"Can't connect g2's input to d64's input: %@", err); 4869 SecTransformConnectTransforms(d64, kSecTransformOutputAttributeName, g3, kSecTransformOutputAttributeName, g3, &err); 4870 STAssertNil((id)err, @"Can't connect d64's output to g2's output: %@", err); 4871 4872 SecTransformConnectTransforms(g1, kSecTransformOutputAttributeName, g2, kSecTransformInputAttributeName, outer, &err); 4873 STAssertNil((id)err, @"Can't connect g1 to g2 (dzlib): %@", err); 4874 SecTransformConnectTransforms(g2, kSecTransformOutputAttributeName, g3, kSecTransformInputAttributeName, outer, &err); 4875 STAssertNil((id)err, @"Can't connect g2 (dzlib) to g3 (d64): %@", err); 4876 4877 SecTransformSetAttribute(g1, kSecTransformInputAttributeName, input_data, &err); 4878 STAssertNil((id)err, @"Can't set g1's input: %@", err); 4879 4880 4881 CFRelease(e64); 4882 CFRelease(ezlib); 4883 CFRelease(dzlib); 4884 CFRelease(d64); 4885 CFRelease(g1); 4886 CFRelease(g2); 4887 CFRelease(g3); 4888 return outer; 4889} 4890 4891-(void)testGroupsInGroups { 4892 UInt8 original_bytes[] = "'Twas brillig and the...was that smiley toads? Something with chives? Aw heck!"; 4893 CFDataRef original = CFDataCreate(NULL, original_bytes, sizeof(original_bytes)); 4894 4895 // Test executing the top group, a sub group, and a non-group member. 4896 for (NSString *name in [NSArray arrayWithObjects:@"OUTER", @"G1", @"D64", nil]) { 4897 CFErrorRef err = NULL; 4898 SecGroupTransformRef outer = build_nested_groups(self, original); 4899 SecTransformRef start_at = SecTransformFindByName(outer, (CFStringRef)name); 4900 STAssertNotNil((id)start_at, @"Expected to find %@", name); 4901 4902 CFDataRef output = (CFDataRef)SecTransformExecute(start_at, &err); 4903 STAssertNil((id)err, @"Can't execute directly created nested transform starting at %@: %@", start_at, err); 4904 STAssertEqualObjects((id)output, (id)original, @"Output and original should match (started at %@)", start_at); 4905 CFRelease(outer); 4906 if (err) { 4907 CFRelease(err); 4908 } 4909 } 4910 4911 { 4912 SecGroupTransformRef bad_outer = build_nested_groups(self, original); 4913 SecTransformRef d64 = SecTransformFindByName(bad_outer, CFSTR("D64")); 4914 STAssertNotNil((id)d64, @"Expected to find d64"); 4915 CFErrorRef err = NULL; 4916 // d64 is in a group in bad_outer, we set things up to fail 4917 // and later expect execute to fail because of it. 4918 SecTransformSetAttribute(d64, kSecDecodeTypeAttribute, CFSTR("NOT valid"), &err); 4919 if (err) { 4920 // It can fail right away 4921 ErrorHas((NSError*)err, @"Unsupported decode type"); 4922 } else { 4923 // Or later (see below) 4924 STAssertNil((id)err, @"Expected to set decode type: %@", err); 4925 } 4926 4927 SecTransformRef e64 = SecTransformFindByName(bad_outer, CFSTR("E64")); 4928 STAssertNotNil((id)e64, @"Expected to find e64"); 4929 CFStringRef any = CFSTR("ANY"); 4930 // e64 and d64 aren't in the same groups, but they are in outer. 4931 // There should be no way to (directly) connect them, so try all 4932 // 4 groups and make sure none work. 4933 for (NSString *group_name in [NSArray arrayWithObjects:@"OUTER", @"G1", @"G2", @"G3", nil]) { 4934 SecTransformRef connect_in = SecTransformFindByName(bad_outer, (CFStringRef)group_name); 4935 STAssertNotNil((id)connect_in, @"Expected to find %@", group_name); 4936 err = NULL; 4937 SecTransformConnectTransforms(d64, any, e64, any, bad_outer, &err); 4938 STAssertNotNil((id)err, @"Expected error on cross group connect (in %@)", group_name); 4939 if (err) { 4940 STAssertEquals(CFErrorGetCode(err), (CFIndex)kSecTransformErrorInvalidConnection, @"error code (in %@)", group_name); 4941 STAssertEqualObjects((id)CFErrorGetDomain(err), (id)kSecTransformErrorDomain, @"error domain (in %@)", group_name); 4942 CFRelease(err); 4943 err = NULL; 4944 } 4945 4946 // While we are here, make sure we can't set a non-exported group attribute 4947 SecTransformSetAttribute((SecTransformRef)connect_in, CFSTR("nobody-exports-me"), CFSTR("VALUE"), &err); 4948 STAssertNotNil((id)err, @"Expected an error setting a non-exported attribute on %@", connect_in); 4949 // Make sure this is the error we expect, not something unrelated to our transgression 4950 ErrorHas((NSError*)err, @"non-exported attribute"); 4951 // Error should have the name of the offending attribute 4952 ErrorHas((NSError*)err, @"nobody-exports-me"); 4953 if (err) { 4954 CFRelease(err); 4955 err = NULL; 4956 } 4957 } 4958 4959 CFTypeRef no_result = SecTransformExecute(bad_outer, &err); 4960 STAssertNotNil((id)err, @"Expected error"); 4961 ErrorHas((NSError*)err, @"Unsupported decode type"); 4962 STAssertNil((id)no_result, @"Expected no result, got: %@", no_result); 4963 CFRelease(bad_outer); 4964 4965 // Make sure we can't connect to or from non-exported group attributes 4966 bad_outer = build_nested_groups(self, original); 4967 STAssertNotNil((id)bad_outer, @"Expected to build nested transform"); 4968 SecTransformRef g1 = SecTransformFindByName(bad_outer, CFSTR("G1")); 4969 STAssertNotNil((id)g1, @"Expected to find g1"); 4970 SecTransformRef appendix = SecNullTransformCreate(); 4971 SecTransformConnectTransforms(appendix, kSecTransformOutputAttributeName, g1, CFSTR("NONE"), bad_outer, &err); 4972 STAssertNotNil((id)err, @"Expected to fail connecting appendix to g1, but didn't"); 4973 ErrorHas((NSError*)err, @"non-exported attribute"); 4974 if (err) { 4975 CFRelease(err); 4976 err = NULL; 4977 } 4978 SecTransformConnectTransforms(g1, CFSTR("DOES_NOT_EXIST"), appendix, kSecTransformInputAttributeName, bad_outer, &err); 4979 STAssertNotNil((id)err, @"Expected to fail connecting g1 to appendix, but didn't"); 4980 ErrorHas((NSError*)err, @"non-exported attribute"); 4981 if (err) { 4982 CFRelease(err); 4983 err = NULL; 4984 } 4985 4986 CFRelease(bad_outer); 4987 CFRelease(appendix); 4988 } 4989} 4990 4991// 10080968 covers this case. It isn't a regression (it was impossible to create nested groups 4992// until recently), but it needs to be addressed before we ship. 4993-(void)disabledUntilPR_10080968_testExternalizeGroupsInGroups { 4994 CFErrorRef err = NULL; 4995 UInt8 original_bytes[] = "Sic Semper Tyrannosaurus!"; 4996 CFDataRef original = CFDataCreate(NULL, original_bytes, sizeof(original_bytes)); 4997 4998 SecGroupTransformRef outer = build_nested_groups(self, original); 4999 NSLog(@"outer=%@", SecTransformDotForDebugging(outer)); 5000 SecTransformRef d64 = SecTransformFindByName(outer, CFSTR("D64")); 5001 STAssertNotNil((id)d64, @"Expected to find d64"); 5002 5003 CFDictionaryRef freezeDriedNestedGroups = SecTransformCopyExternalRepresentation(d64); 5004 STAssertNotNil((id)freezeDriedNestedGroups, @"Expected to externalize group"); 5005 5006 SecTransformRef outer2 = SecTransformCreateFromExternalRepresentation(freezeDriedNestedGroups, &err); 5007 STAssertNil((id)err, @"Can't create nested group err: %@", err); 5008 STAssertNotNil((id)outer2, @"Expected transform fron xrep: %@", freezeDriedNestedGroups); 5009 NSLog(@"outer2=%@", SecTransformDotForDebugging(outer2)); 5010 5011 CFTypeRef output2 = SecTransformExecute(outer2, &err); 5012 STAssertNil((id)err, @"Can't execute outer2: %@", err); 5013 STAssertEqualObjects((id)output2, (id)original, @"Output2 and original should match"); 5014} 5015 5016static NSString *CopyLeakLine() 5017{ 5018 static char os_build[16]; 5019 static dispatch_once_t get_os_build_once; 5020 static BOOL broken_leaks_command = NO; 5021 5022 dispatch_once(&get_os_build_once, ^{ 5023 int mib[] = { CTL_KERN, KERN_OSVERSION }; 5024 size_t bufsz = sizeof(os_build); 5025 sysctl(mib, 2, os_build, &bufsz, NULL, 0); 5026 5027 if (4 == sizeof(char*) && 0 == strcmp(os_build, "12A75")) { 5028 // 12A75's leaks command was badly broken for 32 bit. 5029 // Running it suspends otest, and it is too hard to 5030 // recover. 5031 broken_leaks_command = YES; 5032 } 5033 }); 5034 5035 if (broken_leaks_command) { 5036 return [NSString stringWithFormat:@"Leaks command is broken in %s", os_build]; 5037 } 5038 5039 NSRegularExpression *matchLeaksLine = [NSRegularExpression regularExpressionWithPattern:@"^Process \\d+: \\d+ leaks for \\d+ total leaked bytes.$" options:NSRegularExpressionAnchorsMatchLines error:NULL]; 5040 5041 char *leak_command = NULL; 5042 NSString *fname = [NSString stringWithFormat:@"/tmp/L%d-%d", getpid(), (int)arc4random()]; 5043 asprintf(&leak_command, "(/usr/bin/leaks %d >%s || (echo OOPS; kill -CONT %d))", getpid(), [fname UTF8String], getpid()); 5044 system(leak_command); 5045 free(leak_command); 5046 NSString *output = [NSString stringWithContentsOfFile:fname encoding:NSUTF8StringEncoding error:NULL]; 5047 NSTextCheckingResult *result = [matchLeaksLine firstMatchInString:output options:0 range:NSMakeRange(0, [output length])]; 5048 if (result.range.location == NSNotFound) { 5049 return NULL; 5050 } 5051 NSRange matchRange = result.range; 5052 return [output substringWithRange:matchRange]; 5053} 5054 5055-(void)testAAASimpleLeakTest { 5056 NSString *starting_leaks = CopyLeakLine(); 5057 STAssertNotNil(starting_leaks, @"Found initial leaks"); 5058 for(int i = 0; i < 10; i++) { 5059 CFRelease(SecTransformCreateGroupTransform()); 5060 } 5061 5062 NSString *current_leaks = NULL; 5063 5064 // Some of the destruction is async, so if they don't pan out the same, a little sleep and retry 5065 // can legitimately fix it. 5066 for(int i = 0; i < 10; i++) { 5067 current_leaks = CopyLeakLine(); 5068 if ([current_leaks isEqualToString:starting_leaks]) { 5069 break; 5070 } else { 5071 sleep(1); 5072 } 5073 } 5074 5075 STAssertNotNil(current_leaks, @"Found current leaks"); 5076 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks"); 5077} 5078 5079-(void)testAAASimpleishLeakTest { 5080 NSLog(@"pid=%d", getpid()); 5081 NSString *starting_leaks = CopyLeakLine(); 5082 STAssertNotNil(starting_leaks, @"Found initial leaks"); 5083 CFErrorRef err = NULL; 5084 5085 // Derived from Matt Wright's 10242560 test.c 5086 int fd = open("/dev/random", O_RDONLY); 5087 SecTransformRef b64encode = SecEncodeTransformCreate(kSecBase64Encoding, NULL); 5088 const int buffer_size = 1024; 5089 void *buffer = malloc(buffer_size); 5090 // For this test, ignore short reads 5091 read(fd, buffer, buffer_size); 5092 CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, (UInt8*)buffer, buffer_size, kCFAllocatorMalloc); 5093 SecTransformSetAttribute(b64encode, kSecTransformInputAttributeName, data, &err); 5094 STAssertNil((id)err, @"Expected no SecTransformSetAttribute error, got: %@", err); 5095 CFRelease(data); 5096 CFTypeRef output = SecTransformExecute(b64encode, &err); 5097 STAssertNotNil((id)output, @"Expected result"); 5098 STAssertNil((id)err, @"Expected no execute error, got: %@", err); 5099 CFRelease(output); 5100 CFRelease(b64encode); 5101 5102 NSString *current_leaks = NULL; 5103 5104 // Some of the destruction is async, so if they don't pan out the same, a little sleep and retry 5105 // can legitimately fix it. 5106 for(int i = 0; i < 10; i++) { 5107 current_leaks = CopyLeakLine(); 5108 if ([current_leaks isEqualToString:starting_leaks]) { 5109 break; 5110 } else { 5111 sleep(1); 5112 } 5113 } 5114 5115 STAssertNotNil(current_leaks, @"Found current leaks"); 5116 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks"); 5117} 5118 5119@end 5120