2 * Copyright (c) 2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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>
38 #import "SecNullTransform.h"
40 #include <dispatch/dispatch.h>
41 #import "SecMaskGenerationFunctionTransform.h"
42 #import "SecTransformInternal.h"
44 #include "SecTransformReadTransform.h"
45 #import "SecTransformValidator.h"
46 #include <sys/types.h>
47 #include <sys/sysctl.h>
52 #include <CommonCrypto/CommonCryptor.h>
54 #import "NSData+HexString.h"
55 #include <CoreFoundation/CFBase.h>
56 #include <CoreFoundation/CFData.h>
57 #include <CoreFoundation/CFRuntime.h>
59 // compatibility layer
60 struct 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);
68 typedef void (^SecTransformCreateBlock)(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params);
70 SecTransformCreateBlock global_create_block;
72 static SecTransformInstanceBlock block_for_custom_transform(CFStringRef name, SecTransformRef tr, SecTransformImplementationRef ir)
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)));
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);
83 params->overrideTransform = ^(CFStringRef action, SecTransformActionBlock newAction) {
84 return SecTransformSetTransformAction(ir, action, newAction);
87 params->get = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type) {
88 return SecTranformCustomGetAttribute(ir, attribute, type);
91 params->send = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value) {
92 return SecTransformCustomSetAttribute(ir, attribute, type, value);
95 params->pushback = ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) {
96 return SecTransformPushbackAttribute(ir, attribute, value);
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);
105 global_create_block(name, tr, params);
107 return (CFErrorRef)NULL;
110 return Block_copy(b);
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.
116 static SecTransformRef custom_transform(CFStringRef base_name, SecTransformCreateBlock cb)
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;
123 dispatch_sync(cnt_q, ^{
124 CFErrorRef err = NULL;
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);
131 CFfprintf(stderr, "Error %@ creating %@\n", err, base_name);
135 CFfprintf(stderr, "Error %@ registering %@\n", err, base_name);
138 global_create_block = NULL;
146 #define STAssertErrorHas(err, rx, msg...) STAssertTrue(ErrorHas(err, rx), ##msg);
148 static BOOL ErrorHas(NSError *error, NSString *rx) {
152 if (![error isKindOfClass:[NSError class]]) {
156 NSString *es = [error description];
160 return [es rangeOfString:rx options:NSRegularExpressionSearch].location != NSNotFound;
164 static SecTransformInstanceBlock DelayTransformBlock(CFStringRef name,
165 SecTransformRef newTransform,
166 SecTransformImplementationRef ref)
168 SecTransformInstanceBlock instanceBlock =
170 CFErrorRef result = NULL;
173 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
177 if (NULL != value && CFNumberGetTypeID() == CFGetTypeID(value))
180 CFNumberGetValue((CFNumberRef)value, kCFNumberLongLongType, &n);
181 usleep((useconds_t)(n / NSEC_PER_USEC));
189 return Block_copy(instanceBlock);
192 static SecTransformRef delay_transform(long long nsec) {
193 CFStringRef name = CFSTR("com.apple.security.unit-test.delay");
197 static dispatch_once_t once;
198 __block Boolean ok = TRUE;
200 dispatch_block_t aBlock = ^
202 ok = SecTransformRegister(name, &DelayTransformBlock, NULL);
205 dispatch_once(&once, aBlock);
212 SecTransformRef ct = SecTransformCreate(name, NULL);
213 CFNumberRef nr = CFNumberCreate(NULL, kCFNumberLongLongType, &nsec);
214 SecTransformSetAttribute(ct, CFSTR("DELAY"), nr, NULL);
220 @implementation custom
227 size_t mStringLength;
230 char *mCurrentString;
233 BufferStream(const char* buffer, size_t length) : mBuffer(buffer), mLength(length), mStringLength(0), mPos(0), mCurrentString(NULL) {}
236 const char* GetNextString();
237 void SplitString(const char*& stringA, const char*& stringB);
242 BufferStream::~BufferStream()
244 if (NULL != mCurrentString)
246 free(mCurrentString);
252 const char* BufferStream::GetNextString()
260 // run to either the end of the buffer or a return
261 while (p < mLength && mBuffer[p] != '\n')
268 // handle the end of the buffer specially, since it doesn't point
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;
281 return mCurrentString;
286 void BufferStream::SplitString(const char*& a, const char*& b)
288 // scan the buffer, looking for a ':'
290 while (mCurrentString[p] != 0 && mCurrentString[p] != ':')
295 // the first string is always our buffer pointer
298 if (mCurrentString[p] == ':')
300 mCurrentString[p] = 0;
302 // look for the beginning of the next string
304 while (p < mLength && isspace(mCurrentString[p]))
309 b = mCurrentString + p;
319 -(void)disabledtestzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
321 // open leaks and make a connection to it.
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);
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);
339 // set up our output parser
340 BufferStream bStream(rBuffer, (size_t)st.st_size);
341 const char* s = bStream.GetNextString();
343 bool didError = true;
347 // we have our string, split it and see what it means
351 bStream.SplitString(key, value);
352 if (strcmp(key, "leaks Report Version") != 0 || strcmp(value, "2.0") != 0)
367 // figure out what our target line will look like
369 asprintf(&target, "Process %d", thePid);
371 const char* nextString = bStream.GetNextString();
374 bStream.SplitString(key, value);
375 if (strcmp(key, target) == 0) // we found our target!!!
378 bStream.GetNextString();
379 bStream.SplitString(key, value);
381 if (value[0] != '0') // we have a non-zero result... :(
387 nextString = bStream.GetNextString();
393 STAssertFalse(didError, @"You have leaks!");
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);
413 static 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";
429 const NSString* gAbortTransformName = (NSString*) kSecTransformAbortAttributeName;
431 static 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.";
444 static 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};
449 static 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};
455 CFStringRef paddings[] = {kSecPaddingNoneKey, kSecPaddingPKCS7Key, kSecPaddingPKCS5Key, kSecPaddingPKCS1Key};
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
465 CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
466 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
467 &kCFTypeDictionaryValueCallBacks);
469 CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
471 cfdatacryptokey = CFDataCreate(kCFAllocatorDefault, rawcryptokey,
472 sizeof(rawcryptokey));
473 cryptokey = SecKeyCreateFromData(parameters,
474 cfdatacryptokey, &error);
475 STAssertNil((id)error, @"Unexpected SecKeyCreateFromData error: %@", error);
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;
483 sourceData = (CFDataRef)[NSData dataWithBytes:sourceCString length:len];
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);
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);
496 SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName, sourceData, &error);
497 STAssertNil((id)error, @"Couldn't set encrypt transform input: %@", error);
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");
503 SecTransformSetAttribute(decrypt, kSecTransformInputAttributeName, encryptedData, &error);
504 STAssertNil((id)error, @"Couldn't set decrypt transform input: %@", error);
506 decryptedData = (CFDataRef)SecTransformExecute(decrypt, &error);
507 STAssertNil((id)error, @"Couldn't execute decrypt: %@", error);
508 STAssertNotNil((id)decryptedData, @"Didn't get decrypt data");
510 STAssertEqualObjects((id)decryptedData, (id)sourceData, @"Decrypt output didn't match encrypt input for padding %@", paddings[i]);
514 static SecTransformInstanceBlock nopInstance(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref)
516 SecTransformInstanceBlock instanceBlock = ^{
517 return (CFErrorRef)NULL;
520 return Block_copy(instanceBlock);
524 -(void)test_manyregister
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);
535 -(void)test_emptyOAEP
537 SecKeychainRef tmp_keychain = NULL;
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)
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);
547 const char *pem_key_bytes[] = {
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",
553 SecKeyRef pubKey, privKey;
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));
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("");
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);
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);
587 CFErrorRef err = NULL;
589 SecTransformRef encryptor = SecEncryptTransformCreate(keys[0].pubKey, &err);
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);
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);
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);
623 // Give xcode a little time to parse all the output before the unit tests exit
627 -(void)test_multiOAEP
629 SecKeychainRef tmp_keychain = NULL;
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)
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);
639 const char *pem_key_bytes[] = {
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",
656 SecKeyRef pubKey, privKey;
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));
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("");
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);
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);
690 NSData *message, *seed, *encryptedMessage;
695 // This first one is from the spec
697 .message = [NSData dataWithHexString:@"d436e99569fd32a7c8a05bbc90d32c49"],
698 .seed = [NSData dataWithHexString:@"aafd12f659cae63489b479e5076ddec2f06cb58f"],
699 .encryptedMessage = [NSData dataWithHexString:@"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955"],
701 .label = @"From spec",
703 // The next 60 are from oaep-vect.txt
705 .message = [NSData dataWithHexString:@"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"],
706 .seed = [NSData dataWithHexString:@"18b776ea21069d69776a33e96bad48e1dda0a5ef"],
707 .encryptedMessage = [NSData dataWithHexString:@"354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"],
712 .message = [NSData dataWithHexString:@"750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"],
713 .seed = [NSData dataWithHexString:@"0cc742ce4a9b7f32f951bcb251efd925fe4fe35f"],
714 .encryptedMessage = [NSData dataWithHexString:@"640db1acc58e0568fe5407e5f9b701dff8c3c91e716c536fc7fcec6cb5b71c1165988d4a279e1577d730fc7a29932e3f00c81515236d8d8e31017a7a09df4352d904cdeb79aa583adcc31ea698a4c05283daba9089be5491f67c1a4ee48dc74bbbe6643aef846679b4cb395a352d5ed115912df696ffe0702932946d71492b44"],
719 .message = [NSData dataWithHexString:@"d94ae0832e6445ce42331cb06d531a82b1db4baad30f746dc916df24d4e3c2451fff59a6423eb0e1d02d4fe646cf699dfd818c6e97b051"],
720 .seed = [NSData dataWithHexString:@"2514df4695755a67b288eaf4905c36eec66fd2fd"],
721 .encryptedMessage = [NSData dataWithHexString:@"423736ed035f6026af276c35c0b3741b365e5f76ca091b4e8c29e2f0befee603595aa8322d602d2e625e95eb81b2f1c9724e822eca76db8618cf09c5343503a4360835b5903bc637e3879fb05e0ef32685d5aec5067cd7cc96fe4b2670b6eac3066b1fcf5686b68589aafb7d629b02d8f8625ca3833624d4800fb081b1cf94eb"],
726 .message = [NSData dataWithHexString:@"52e650d98e7f2a048b4f86852153b97e01dd316f346a19f67a85"],
727 .seed = [NSData dataWithHexString:@"c4435a3e1a18a68b6820436290a37cefb85db3fb"],
728 .encryptedMessage = [NSData dataWithHexString:@"45ead4ca551e662c9800f1aca8283b0525e6abae30be4b4aba762fa40fd3d38e22abefc69794f6ebbbc05ddbb11216247d2f412fd0fba87c6e3acd888813646fd0e48e785204f9c3f73d6d8239562722dddd8771fec48b83a31ee6f592c4cfd4bc88174f3b13a112aae3b9f7b80e0fc6f7255ba880dc7d8021e22ad6a85f0755"],
733 .message = [NSData dataWithHexString:@"8da89fd9e5f974a29feffb462b49180f6cf9e802"],
734 .seed = [NSData dataWithHexString:@"b318c42df3be0f83fea823f5a7b47ed5e425a3b5"],
735 .encryptedMessage = [NSData dataWithHexString:@"36f6e34d94a8d34daacba33a2139d00ad85a9345a86051e73071620056b920e219005855a213a0f23897cdcd731b45257c777fe908202befdd0b58386b1244ea0cf539a05d5d10329da44e13030fd760dcd644cfef2094d1910d3f433e1c7c6dd18bc1f2df7f643d662fb9dd37ead9059190f4fa66ca39e869c4eb449cbdc439"],
740 .message = [NSData dataWithHexString:@"26521050844271"],
741 .seed = [NSData dataWithHexString:@"e4ec0982c2336f3a677f6a356174eb0ce887abc2"],
742 .encryptedMessage = [NSData dataWithHexString:@"42cee2617b1ecea4db3f4829386fbd61dafbf038e180d837c96366df24c097b4ab0fac6bdf590d821c9f10642e681ad05b8d78b378c0f46ce2fad63f74e0ad3df06b075d7eb5f5636f8d403b9059ca761b5c62bb52aa45002ea70baace08ded243b9d8cbd62a68ade265832b56564e43a6fa42ed199a099769742df1539e8255"],
748 .message = [NSData dataWithHexString:@"8ff00caa605c702830634d9a6c3d42c652b58cf1d92fec570beee7"],
749 .seed = [NSData dataWithHexString:@"8c407b5ec2899e5099c53e8ce793bf94e71b1782"],
750 .encryptedMessage = [NSData dataWithHexString:@"0181af8922b9fcb4d79d92ebe19815992fc0c1439d8bcd491398a0f4ad3a329a5bd9385560db532683c8b7da04e4b12aed6aacdf471c34c9cda891addcc2df3456653aa6382e9ae59b54455257eb099d562bbe10453f2b6d13c59c02e10f1f8abb5da0d0570932dacf2d0901db729d0fefcc054e70968ea540c81b04bcaefe720e"],
755 .message = [NSData dataWithHexString:@"2d"],
756 .seed = [NSData dataWithHexString:@"b600cf3c2e506d7f16778c910d3a8b003eee61d5"],
757 .encryptedMessage = [NSData dataWithHexString:@"018759ff1df63b2792410562314416a8aeaf2ac634b46f940ab82d64dbf165eee33011da749d4bab6e2fcd18129c9e49277d8453112b429a222a8471b070993998e758861c4d3f6d749d91c4290d332c7a4ab3f7ea35ff3a07d497c955ff0ffc95006b62c6d296810d9bfab024196c7934012c2df978ef299aba239940cba10245"],
762 .message = [NSData dataWithHexString:@"74fc88c51bc90f77af9d5e9a4a70133d4b4e0b34da3c37c7ef8e"],
763 .seed = [NSData dataWithHexString:@"a73768aeeaa91f9d8c1ed6f9d2b63467f07ccae3"],
764 .encryptedMessage = [NSData dataWithHexString:@"018802bab04c60325e81c4962311f2be7c2adce93041a00719c88f957575f2c79f1b7bc8ced115c706b311c08a2d986ca3b6a9336b147c29c6f229409ddec651bd1fdd5a0b7f610c9937fdb4a3a762364b8b3206b4ea485fd098d08f63d4aa8bb2697d027b750c32d7f74eaf5180d2e9b66b17cb2fa55523bc280da10d14be2053"],
769 .message = [NSData dataWithHexString:@"a7eb2a5036931d27d4e891326d99692ffadda9bf7efd3e34e622c4adc085f721dfe885072c78a203b151739be540fa8c153a10f00a"],
770 .seed = [NSData dataWithHexString:@"9a7b3b0e708bd96f8190ecab4fb9b2b3805a8156"],
771 .encryptedMessage = [NSData dataWithHexString:@"00a4578cbc176318a638fba7d01df15746af44d4f6cd96d7e7c495cbf425b09c649d32bf886da48fbaf989a2117187cafb1fb580317690e3ccd446920b7af82b31db5804d87d01514acbfa9156e782f867f6bed9449e0e9a2c09bcecc6aa087636965e34b3ec766f2fe2e43018a2fddeb140616a0e9d82e5331024ee0652fc7641"],
776 .message = [NSData dataWithHexString:@"2ef2b066f854c33f3bdcbb5994a435e73d6c6c"],
777 .seed = [NSData dataWithHexString:@"eb3cebbc4adc16bb48e88c8aec0e34af7f427fd3"],
778 .encryptedMessage = [NSData dataWithHexString:@"00ebc5f5fda77cfdad3c83641a9025e77d72d8a6fb33a810f5950f8d74c73e8d931e8634d86ab1246256ae07b6005b71b7f2fb98351218331ce69b8ffbdc9da08bbc9c704f876deb9df9fc2ec065cad87f9090b07acc17aa7f997b27aca48806e897f771d95141fe4526d8a5301b678627efab707fd40fbebd6e792a25613e7aec"],
783 .message = [NSData dataWithHexString:@"8a7fb344c8b6cb2cf2ef1f643f9a3218f6e19bba89c0"],
784 .seed = [NSData dataWithHexString:@"4c45cf4d57c98e3d6d2095adc51c489eb50dff84"],
785 .encryptedMessage = [NSData dataWithHexString:@"010839ec20c27b9052e55befb9b77e6fc26e9075d7a54378c646abdf51e445bd5715de81789f56f1803d9170764a9e93cb78798694023ee7393ce04bc5d8f8c5a52c171d43837e3aca62f609eb0aa5ffb0960ef04198dd754f57f7fbe6abf765cf118b4ca443b23b5aab266f952326ac4581100644325f8b721acd5d04ff14ef3a"],
791 .message = [NSData dataWithHexString:@"087820b569e8fa8d"],
792 .seed = [NSData dataWithHexString:@"8ced6b196290805790e909074015e6a20b0c4894"],
793 .encryptedMessage = [NSData dataWithHexString:@"026a0485d96aebd96b4382085099b962e6a2bdec3d90c8db625e14372de85e2d5b7baab65c8faf91bb5504fb495afce5c988b3f6a52e20e1d6cbd3566c5cd1f2b8318bb542cc0ea25c4aab9932afa20760eaddec784396a07ea0ef24d4e6f4d37e5052a7a31e146aa480a111bbe926401307e00f410033842b6d82fe5ce4dfae80"],
798 .message = [NSData dataWithHexString:@"4653acaf171960b01f52a7be63a3ab21dc368ec43b50d82ec3781e04"],
799 .seed = [NSData dataWithHexString:@"b4291d6567550848cc156967c809baab6ca507f0"],
800 .encryptedMessage = [NSData dataWithHexString:@"024db89c7802989be0783847863084941bf209d761987e38f97cb5f6f1bc88da72a50b73ebaf11c879c4f95df37b850b8f65d7622e25b1b889e80fe80baca2069d6e0e1d829953fc459069de98ea9798b451e557e99abf8fe3d9ccf9096ebbf3e5255d3b4e1c6d2ecadf067a359eea86405acd47d5e165517ccafd47d6dbee4bf5"],
805 .message = [NSData dataWithHexString:@"d94cd0e08fa404ed89"],
806 .seed = [NSData dataWithHexString:@"ce8928f6059558254008badd9794fadcd2fd1f65"],
807 .encryptedMessage = [NSData dataWithHexString:@"0239bce681032441528877d6d1c8bb28aa3bc97f1df584563618995797683844ca86664732f4bed7a0aab083aaabfb7238f582e30958c2024e44e57043b97950fd543da977c90cdde5337d618442f99e60d7783ab59ce6dd9d69c47ad1e962bec22d05895cff8d3f64ed5261d92b2678510393484990ba3f7f06818ae6ffce8a3a"],
812 .message = [NSData dataWithHexString:@"6cc641b6b61e6f963974dad23a9013284ef1"],
813 .seed = [NSData dataWithHexString:@"6e2979f52d6814a57d83b090054888f119a5b9a3"],
814 .encryptedMessage = [NSData dataWithHexString:@"02994c62afd76f498ba1fd2cf642857fca81f4373cb08f1cbaee6f025c3b512b42c3e8779113476648039dbe0493f9246292fac28950600e7c0f32edf9c81b9dec45c3bde0cc8d8847590169907b7dc5991ceb29bb0714d613d96df0f12ec5d8d3507c8ee7ae78dd83f216fa61de100363aca48a7e914ae9f42ddfbe943b09d9a0"],
819 .message = [NSData dataWithHexString:@"df5151832b61f4f25891fb4172f328d2eddf8371ffcfdbe997939295f30eca6918017cfda1153bf7a6af87593223"],
820 .seed = [NSData dataWithHexString:@"2d760bfe38c59de34cdc8b8c78a38e66284a2d27"],
821 .encryptedMessage = [NSData dataWithHexString:@"0162042ff6969592a6167031811a239834ce638abf54fec8b99478122afe2ee67f8c5b18b0339805bfdbc5a4e6720b37c59cfba942464c597ff532a119821545fd2e59b114e61daf71820529f5029cf524954327c34ec5e6f5ba7efcc4de943ab8ad4ed787b1454329f70db798a3a8f4d92f8274e2b2948ade627ce8ee33e43c60"],
826 .message = [NSData dataWithHexString:@"3c3bad893c544a6d520ab022319188c8d504b7a788b850903b85972eaa18552e1134a7ad6098826254ff7ab672b3d8eb3158fac6d4cbaef1"],
827 .seed = [NSData dataWithHexString:@"f174779c5fd3cfe007badcb7a36c9b55bfcfbf0e"],
828 .encryptedMessage = [NSData dataWithHexString:@"00112051e75d064943bc4478075e43482fd59cee0679de6893eec3a943daa490b9691c93dfc0464b6623b9f3dbd3e70083264f034b374f74164e1a00763725e574744ba0b9db83434f31df96f6e2a26f6d8eba348bd4686c2238ac07c37aac3785d1c7eea2f819fd91491798ed8e9cef5e43b781b0e0276e37c43ff9492d005730"],
834 .message = [NSData dataWithHexString:@"4a86609534ee434a6cbca3f7e962e76d455e3264c19f605f6e5ff6137c65c56d7fb344cd52bc93374f3d166c9f0c6f9c506bad19330972d2"],
835 .seed = [NSData dataWithHexString:@"1cac19ce993def55f98203f6852896c95ccca1f3"],
836 .encryptedMessage = [NSData dataWithHexString:@"04cce19614845e094152a3fe18e54e3330c44e5efbc64ae16886cb1869014cc5781b1f8f9e045384d0112a135ca0d12e9c88a8e4063416deaae3844f60d6e96fe155145f4525b9a34431ca3766180f70e15a5e5d8e8b1a516ff870609f13f896935ced188279a58ed13d07114277d75c6568607e0ab092fd803a223e4a8ee0b1a8"],
841 .message = [NSData dataWithHexString:@"b0adc4f3fe11da59ce992773d9059943c03046497ee9d9f9a06df1166db46d98f58d27ec074c02eee6cbe2449c8b9fc5080c5c3f4433092512ec46aa793743c8"],
842 .seed = [NSData dataWithHexString:@"f545d5897585e3db71aa0cb8da76c51d032ae963"],
843 .encryptedMessage = [NSData dataWithHexString:@"0097b698c6165645b303486fbf5a2a4479c0ee85889b541a6f0b858d6b6597b13b854eb4f839af03399a80d79bda6578c841f90d645715b280d37143992dd186c80b949b775cae97370e4ec97443136c6da484e970ffdb1323a20847821d3b18381de13bb49aaea66530c4a4b8271f3eae172cd366e07e6636f1019d2a28aed15e"],
848 .message = [NSData dataWithHexString:@"bf6d42e701707b1d0206b0c8b45a1c72641ff12889219a82bdea965b5e79a96b0d0163ed9d578ec9ada20f2fbcf1ea3c4089d83419ba81b0c60f3606da99"],
849 .seed = [NSData dataWithHexString:@"ad997feef730d6ea7be60d0dc52e72eacbfdd275"],
850 .encryptedMessage = [NSData dataWithHexString:@"0301f935e9c47abcb48acbbe09895d9f5971af14839da4ff95417ee453d1fd77319072bb7297e1b55d7561cd9d1bb24c1a9a37c619864308242804879d86ebd001dce5183975e1506989b70e5a83434154d5cbfd6a24787e60eb0c658d2ac193302d1192c6e622d4a12ad4b53923bca246df31c6395e37702c6a78ae081fb9d065"],
855 .message = [NSData dataWithHexString:@"fb2ef112f5e766eb94019297934794f7be2f6fc1c58e"],
856 .seed = [NSData dataWithHexString:@"136454df5730f73c807a7e40d8c1a312ac5b9dd3"],
857 .encryptedMessage = [NSData dataWithHexString:@"02d110ad30afb727beb691dd0cf17d0af1a1e7fa0cc040ec1a4ba26a42c59d0a796a2e22c8f357ccc98b6519aceb682e945e62cb734614a529407cd452bee3e44fece8423cc19e55548b8b994b849c7ecde4933e76037e1d0ce44275b08710c68e430130b929730ed77e09b015642c5593f04e4ffb9410798102a8e96ffdfe11e4"],
862 .message = [NSData dataWithHexString:@"28ccd447bb9e85166dabb9e5b7d1adadc4b9d39f204e96d5e440ce9ad928bc1c2284"],
863 .seed = [NSData dataWithHexString:@"bca8057f824b2ea257f2861407eef63d33208681"],
864 .encryptedMessage = [NSData dataWithHexString:@"00dbb8a7439d90efd919a377c54fae8fe11ec58c3b858362e23ad1b8a44310799066b99347aa525691d2adc58d9b06e34f288c170390c5f0e11c0aa3645959f18ee79e8f2be8d7ac5c23d061f18dd74b8c5f2a58fcb5eb0c54f99f01a83247568292536583340948d7a8c97c4acd1e98d1e29dc320e97a260532a8aa7a758a1ec2"],
869 .message = [NSData dataWithHexString:@"f22242751ec6b1"],
870 .seed = [NSData dataWithHexString:@"2e7e1e17f647b5ddd033e15472f90f6812f3ac4e"],
871 .encryptedMessage = [NSData dataWithHexString:@"00a5ffa4768c8bbecaee2db77e8f2eec99595933545520835e5ba7db9493d3e17cddefe6a5f567624471908db4e2d83a0fbee60608fc84049503b2234a07dc83b27b22847ad8920ff42f674ef79b76280b00233d2b51b8cb2703a9d42bfbc8250c96ec32c051e57f1b4ba528db89c37e4c54e27e6e64ac69635ae887d9541619a9"],
877 .message = [NSData dataWithHexString:@"af71a901e3a61d3132f0fc1fdb474f9ea6579257ffc24d164170145b3dbde8"],
878 .seed = [NSData dataWithHexString:@"44c92e283f77b9499c603d963660c87d2f939461"],
879 .encryptedMessage = [NSData dataWithHexString:@"036046a4a47d9ed3ba9a89139c105038eb7492b05a5d68bfd53accff4597f7a68651b47b4a4627d927e485eed7b4566420e8b409879e5d606eae251d22a5df799f7920bfc117b992572a53b1263146bcea03385cc5e853c9a101c8c3e1bda31a519807496c6cb5e5efb408823a352b8fa0661fb664efadd593deb99fff5ed000e5"],
884 .message = [NSData dataWithHexString:@"a3b844a08239a8ac41605af17a6cfda4d350136585903a417a79268760519a4b4ac3303ec73f0f87cfb32399"],
885 .seed = [NSData dataWithHexString:@"cb28f5860659fceee49c3eeafce625a70803bd32"],
886 .encryptedMessage = [NSData dataWithHexString:@"03d6eb654edce615bc59f455265ed4e5a18223cbb9be4e4069b473804d5de96f54dcaaa603d049c5d94aa1470dfcd2254066b7c7b61ff1f6f6770e3215c51399fd4e34ec5082bc48f089840ad04354ae66dc0f1bd18e461a33cc1258b443a2837a6df26759aa2302334986f87380c9cc9d53be9f99605d2c9a97da7b0915a4a7ad"],
891 .message = [NSData dataWithHexString:@"308b0ecbd2c76cb77fc6f70c5edd233fd2f20929d629f026953bb62a8f4a3a314bde195de85b5f816da2aab074d26cb6acddf323ae3b9c678ac3cf12fbdde7"],
892 .seed = [NSData dataWithHexString:@"2285f40d770482f9a9efa2c72cb3ac55716dc0ca"],
893 .encryptedMessage = [NSData dataWithHexString:@"0770952181649f9f9f07ff626ff3a22c35c462443d905d456a9fd0bff43cac2ca7a9f554e9478b9acc3ac838b02040ffd3e1847de2e4253929f9dd9ee4044325a9b05cabb808b2ee840d34e15d105a3f1f7b27695a1a07a2d73fe08ecaaa3c9c9d4d5a89ff890d54727d7ae40c0ec1a8dd86165d8ee2c6368141016a48b55b6967"],
898 .message = [NSData dataWithHexString:@"15c5b9ee1185"],
899 .seed = [NSData dataWithHexString:@"49fa45d3a78dd10dfd577399d1eb00af7eed5513"],
900 .encryptedMessage = [NSData dataWithHexString:@"0812b76768ebcb642d040258e5f4441a018521bd96687e6c5e899fcd6c17588ff59a82cc8ae03a4b45b31299af1788c329f7dcd285f8cf4ced82606b97612671a45bedca133442144d1617d114f802857f0f9d739751c57a3f9ee400912c61e2e6992be031a43dd48fa6ba14eef7c422b5edc4e7afa04fdd38f402d1c8bb719abf"],
905 .message = [NSData dataWithHexString:@"21026e6800c7fa728fcaaba0d196ae28d7a2ac4ffd8abce794f0985f60c8a6737277365d3fea11db8923a2029a"],
906 .seed = [NSData dataWithHexString:@"f0287413234cc5034724a094c4586b87aff133fc"],
907 .encryptedMessage = [NSData dataWithHexString:@"07b60e14ec954bfd29e60d0047e789f51d57186c63589903306793ced3f68241c743529aba6a6374f92e19e0163efa33697e196f7661dfaaa47aac6bde5e51deb507c72c589a2ca1693d96b1460381249b2cdb9eac44769f2489c5d3d2f99f0ee3c7ee5bf64a5ac79c42bd433f149be8cb59548361640595513c97af7bc2509723"],
912 .message = [NSData dataWithHexString:@"541e37b68b6c8872b84c02"],
913 .seed = [NSData dataWithHexString:@"d9fba45c96f21e6e26d29eb2cdcb6585be9cb341"],
914 .encryptedMessage = [NSData dataWithHexString:@"08c36d4dda33423b2ed6830d85f6411ba1dcf470a1fae0ebefee7c089f256cef74cb96ea69c38f60f39abee44129bcb4c92de7f797623b20074e3d9c2899701ed9071e1efa0bdd84d4c3e5130302d8f0240baba4b84a71cc032f2235a5ff0fae277c3e8f9112bef44c9ae20d175fc9a4058bfc930ba31b02e2e4f444483710f24a"],
921 .message = [NSData dataWithHexString:@"4046ca8baa3347ca27f49e0d81f9cc1d71be9ba517d4"],
922 .seed = [NSData dataWithHexString:@"dd0f6cfe415e88e5a469a51fbba6dfd40adb4384"],
923 .encryptedMessage = [NSData dataWithHexString:@"0630eebcd2856c24f798806e41f9e67345eda9ceda386acc9facaea1eeed06ace583709718d9d169fadf414d5c76f92996833ef305b75b1e4b95f662a20faedc3bae0c4827a8bf8a88edbd57ec203a27a841f02e43a615bab1a8cac0701de34debdef62a088089b55ec36ea7522fd3ec8d06b6a073e6df833153bc0aefd93bd1a3"],
928 .message = [NSData dataWithHexString:@"5cc72c60231df03b3d40f9b57931bc31109f972527f28b19e7480c7288cb3c92b22512214e4be6c914792ddabdf57faa8aa7"],
929 .seed = [NSData dataWithHexString:@"8d14bd946a1351148f5cae2ed9a0c653e85ebd85"],
930 .encryptedMessage = [NSData dataWithHexString:@"0ebc37376173a4fd2f89cc55c2ca62b26b11d51c3c7ce49e8845f74e7607317c436bc8d23b9667dfeb9d087234b47bc6837175ae5c0559f6b81d7d22416d3e50f4ac533d8f0812f2db9e791fe9c775ac8b6ad0f535ad9ceb23a4a02014c58ab3f8d3161499a260f39348e714ae2a1d3443208fd8b722ccfdfb393e98011f99e63f"],
935 .message = [NSData dataWithHexString:@"b20e651303092f4bccb43070c0f86d23049362ed96642fc5632c27db4a52e3d831f2ab068b23b149879c002f6bf3feee97591112562c"],
936 .seed = [NSData dataWithHexString:@"6c075bc45520f165c0bf5ea4c5df191bc9ef0e44"],
937 .encryptedMessage = [NSData dataWithHexString:@"0a98bf1093619394436cf68d8f38e2f158fde8ea54f3435f239b8d06b8321844202476aeed96009492480ce3a8d705498c4c8c68f01501dc81db608f60087350c8c3b0bd2e9ef6a81458b7c801b89f2e4fe99d4900ba6a4b5e5a96d865dc676c7755928794130d6280a8160a190f2df3ea7cf9aa0271d88e9e6905ecf1c5152d65"],
942 .message = [NSData dataWithHexString:@"684e3038c5c041f7"],
943 .seed = [NSData dataWithHexString:@"3bbc3bd6637dfe12846901029bf5b0c07103439c"],
944 .encryptedMessage = [NSData dataWithHexString:@"008e7a67cacfb5c4e24bec7dee149117f19598ce8c45808fef88c608ff9cd6e695263b9a3c0ad4b8ba4c95238e96a8422b8535629c8d5382374479ad13fa39974b242f9a759eeaf9c83ad5a8ca18940a0162ba755876df263f4bd50c6525c56090267c1f0e09ce0899a0cf359e88120abd9bf893445b3cae77d3607359ae9a52f8"],
949 .message = [NSData dataWithHexString:@"32488cb262d041d6e4dd35f987bf3ca696db1f06ac29a44693"],
950 .seed = [NSData dataWithHexString:@"b46b41893e8bef326f6759383a83071dae7fcabc"],
951 .encryptedMessage = [NSData dataWithHexString:@"00003474416c7b68bdf961c385737944d7f1f40cb395343c693cc0b4fe63b31fedf1eaeeac9ccc0678b31dc32e0977489514c4f09085f6298a9653f01aea4045ff582ee887be26ae575b73eef7f3774921e375a3d19adda0ca31aa1849887c1f42cac9677f7a2f4e923f6e5a868b38c084ef187594dc9f7f048fea2e02955384ab"],
956 .message = [NSData dataWithHexString:@"50ba14be8462720279c306ba"],
957 .seed = [NSData dataWithHexString:@"0a2403312a41e3d52f060fbc13a67de5cf7609a7"],
958 .encryptedMessage = [NSData dataWithHexString:@"0a026dda5fc8785f7bd9bf75327b63e85e2c0fdee5dadb65ebdcac9ae1de95c92c672ab433aa7a8e69ce6a6d8897fac4ac4a54de841ae5e5bbce7687879d79634cea7a30684065c714d52409b928256bbf53eabcd5231eb7259504537399bd29164b726d33a46da701360a4168a091ccab72d44a62fed246c0ffea5b1348ab5470"],
963 .message = [NSData dataWithHexString:@"47aae909"],
964 .seed = [NSData dataWithHexString:@"43dd09a07ff4cac71caa4632ee5e1c1daee4cd8f"],
965 .encryptedMessage = [NSData dataWithHexString:@"1688e4ce7794bba6cb7014169ecd559cede2a30b56a52b68d9fe18cf1973ef97b2a03153951c755f6294aa49adbdb55845ab6875fb3986c93ecf927962840d282f9e54ce8b690f7c0cb8bbd73440d9571d1b16cd9260f9eab4783cc482e5223dc60973871783ec27b0ae0fd47732cbc286a173fc92b00fb4ba6824647cd93c85c1"],
970 .message = [NSData dataWithHexString:@"1d9b2e2223d9bc13bfb9f162ce735db48ba7c68f6822a0a1a7b6ae165834e7"],
971 .seed = [NSData dataWithHexString:@"3a9c3cec7b84f9bd3adecbc673ec99d54b22bc9b"],
972 .encryptedMessage = [NSData dataWithHexString:@"1052ed397b2e01e1d0ee1c50bf24363f95e504f4a03434a08fd822574ed6b9736edbb5f390db10321479a8a139350e2bd4977c3778ef331f3e78ae118b268451f20a2f01d471f5d53c566937171b2dbc2d4bde459a5799f0372d6574239b2323d245d0bb81c286b63c89a361017337e4902f88a467f4c7f244bfd5ab46437ff3b6"],
977 .message = [NSData dataWithHexString:@"d976fc"],
978 .seed = [NSData dataWithHexString:@"76a75e5b6157a556cf8884bb2e45c293dd545cf5"],
979 .encryptedMessage = [NSData dataWithHexString:@"2155cd843ff24a4ee8badb7694260028a490813ba8b369a4cbf106ec148e5298707f5965be7d101c1049ea8584c24cd63455ad9c104d686282d3fb803a4c11c1c2e9b91c7178801d1b6640f003f5728df007b8a4ccc92bce05e41a27278d7c85018c52414313a5077789001d4f01910b72aad05d220aa14a58733a7489bc54556b"],
984 .message = [NSData dataWithHexString:@"d4738623df223aa43843df8467534c41d013e0c803c624e263666b239bde40a5f29aeb8de79e3daa61dd0370f49bd4b013834b98212aef6b1c5ee373b3cb"],
985 .seed = [NSData dataWithHexString:@"7866314a6ad6f2b250a35941db28f5864b585859"],
986 .encryptedMessage = [NSData dataWithHexString:@"0ab14c373aeb7d4328d0aaad8c094d88b9eb098b95f21054a29082522be7c27a312878b637917e3d819e6c3c568db5d843802b06d51d9e98a2be0bf40c031423b00edfbff8320efb9171bd2044653a4cb9c5122f6c65e83cda2ec3c126027a9c1a56ba874d0fea23f380b82cf240b8cf540004758c4c77d934157a74f3fc12bfac"],
991 .message = [NSData dataWithHexString:@"bb47231ca5ea1d3ad46c99345d9a8a61"],
992 .seed = [NSData dataWithHexString:@"b2166ed472d58db10cab2c6b000cccf10a7dc509"],
993 .encryptedMessage = [NSData dataWithHexString:@"028387a318277434798b4d97f460068df5298faba5041ba11761a1cb7316b24184114ec500257e2589ed3b607a1ebbe97a6cc2e02bf1b681f42312a33b7a77d8e7855c4a6de03e3c04643f786b91a264a0d6805e2cea91e68177eb7a64d9255e4f27e713b7ccec00dc200ebd21c2ea2bb890feae4942df941dc3f97890ed347478"],
998 .message = [NSData dataWithHexString:@"2184827095d35c3f86f600e8e59754013296"],
999 .seed = [NSData dataWithHexString:@"52673bde2ca166c2aa46131ac1dc808d67d7d3b1"],
1000 .encryptedMessage = [NSData dataWithHexString:@"14c678a94ad60525ef39e959b2f3ba5c097a94ff912b67dbace80535c187abd47d075420b1872152bba08f7fc31f313bbf9273c912fc4c0149a9b0cfb79807e346eb332069611bec0ff9bcd168f1f7c33e77313cea454b94e2549eecf002e2acf7f6f2d2845d4fe0aab2e5a92ddf68c480ae11247935d1f62574842216ae674115"],
1005 .message = [NSData dataWithHexString:@"050b755e5e6880f7b9e9d692a74c37aae449b31bfea6deff83747a897f6c2c825bb1adbf850a3c96994b5de5b33cbc7d4a17913a7967"],
1006 .seed = [NSData dataWithHexString:@"7706ffca1ecfb1ebee2a55e5c6e24cd2797a4125"],
1007 .encryptedMessage = [NSData dataWithHexString:@"09b3683d8a2eb0fb295b62ed1fb9290b714457b7825319f4647872af889b30409472020ad12912bf19b11d4819f49614824ffd84d09c0a17e7d17309d12919790410aa2995699f6a86dbe3242b5acc23af45691080d6b1ae810fb3e3057087f0970092ce00be9562ff4053b6262ce0caa93e13723d2e3a5ba075d45f0d61b54b61"],
1012 .message = [NSData dataWithHexString:@"4eb68dcd93ca9b19df111bd43608f557026fe4aa1d5cfac227a3eb5ab9548c18a06dded23f81825986b2fcd71109ecef7eff88873f075c2aa0c469f69c92bc"],
1013 .seed = [NSData dataWithHexString:@"a3717da143b4dcffbc742665a8fa950585548343"],
1014 .encryptedMessage = [NSData dataWithHexString:@"2ecf15c97c5a15b1476ae986b371b57a24284f4a162a8d0c8182e7905e792256f1812ba5f83f1f7a130e42dcc02232844edc14a31a68ee97ae564a383a3411656424c5f62ddb646093c367be1fcda426cf00a06d8acb7e57776fbbd855ac3df506fc16b1d7c3f2110f3d8068e91e186363831c8409680d8da9ecd8cf1fa20ee39d"],
1019 .message = [NSData dataWithHexString:@"8604ac56328c1ab5ad917861"],
1020 .seed = [NSData dataWithHexString:@"ee06209073cca026bb264e5185bf8c68b7739f86"],
1021 .encryptedMessage = [NSData dataWithHexString:@"4bc89130a5b2dabb7c2fcf90eb5d0eaf9e681b7146a38f3173a3d9cfec52ea9e0a41932e648a9d69344c50da763f51a03c95762131e8052254dcd2248cba40fd31667786ce05a2b7b531ac9dac9ed584a59b677c1a8aed8c5d15d68c05569e2be780bf7db638fd2bfd2a85ab276860f3777338fca989ffd743d13ee08e0ca9893f"],
1026 .message = [NSData dataWithHexString:@"fdda5fbf6ec361a9d9a4ac68af216a0686f438b1e0e5c36b955f74e107f39c0dddcc"],
1027 .seed = [NSData dataWithHexString:@"990ad573dc48a973235b6d82543618f2e955105d"],
1028 .encryptedMessage = [NSData dataWithHexString:@"2e456847d8fc36ff0147d6993594b9397227d577752c79d0f904fcb039d4d812fea605a7b574dd82ca786f93752348438ee9f5b5454985d5f0e1699e3e7ad175a32e15f03deb042ab9fe1dd9db1bb86f8c089ccb45e7ef0c5ee7ca9b7290ca6b15bed47039788a8a93ff83e0e8d6244c71006362deef69b6f416fb3c684383fbd0"],
1033 .message = [NSData dataWithHexString:@"4a5f4914bee25de3c69341de07"],
1034 .seed = [NSData dataWithHexString:@"ecc63b28f0756f22f52ac8e6ec1251a6ec304718"],
1035 .encryptedMessage = [NSData dataWithHexString:@"1fb9356fd5c4b1796db2ebf7d0d393cc810adf6145defc2fce714f79d93800d5e2ac211ea8bbecca4b654b94c3b18b30dd576ce34dc95436ef57a09415645923359a5d7b4171ef22c24670f1b229d3603e91f76671b7df97e7317c97734476d5f3d17d21cf82b5ba9f83df2e588d36984fd1b584468bd23b2e875f32f68953f7b2"],
1040 .message = [NSData dataWithHexString:@"8e07d66f7b880a72563abcd3f35092bc33409fb7f88f2472be"],
1041 .seed = [NSData dataWithHexString:@"3925c71b362d40a0a6de42145579ba1e7dd459fc"],
1042 .encryptedMessage = [NSData dataWithHexString:@"3afd9c6600147b21798d818c655a0f4c9212db26d0b0dfdc2a7594ccb3d22f5bf1d7c3e112cd73fc7d509c7a8bafdd3c274d1399009f9609ec4be6477e453f075aa33db382870c1c3409aef392d7386ae3a696b99a94b4da0589447e955d16c98b17602a59bd736279fcd8fb280c4462d590bfa9bf13fed570eafde97330a2c210"],
1047 .message = [NSData dataWithHexString:@"f735fd55ba92592c3b52b8f9c4f69aaa1cbef8fe88add095595412467f9cf4ec0b896c59eda16210e7549c8abb10cdbc21a12ec9b6b5b8fd2f10399eb6"],
1048 .seed = [NSData dataWithHexString:@"8ec965f134a3ec9931e92a1ca0dc8169d5ea705c"],
1049 .encryptedMessage = [NSData dataWithHexString:@"267bcd118acab1fc8ba81c85d73003cb8610fa55c1d97da8d48a7c7f06896a4db751aa284255b9d36ad65f37653d829f1b37f97b8001942545b2fc2c55a7376ca7a1be4b1760c8e05a33e5aa2526b8d98e317088e7834c755b2a59b12631a182c05d5d43ab1779264f8456f515ce57dfdf512d5493dab7b7338dc4b7d78db9c091ac3baf537a69fc7f549d979f0eff9a94fda4169bd4d1d19a69c99e33c3b55490d501b39b1edae118ff6793a153261584d3a5f39f6e682e3d17c8cd1261fa72"],
1054 .message = [NSData dataWithHexString:@"81b906605015a63aabe42ddf11e1978912f5404c7474b26dce3ed482bf961ecc818bf420c54659"],
1055 .seed = [NSData dataWithHexString:@"ecb1b8b25fa50cdab08e56042867f4af5826d16c"],
1056 .encryptedMessage = [NSData dataWithHexString:@"93ac9f0671ec29acbb444effc1a5741351d60fdb0e393fbf754acf0de49761a14841df7772e9bc82773966a1584c4d72baea00118f83f35cca6e537cbd4d811f5583b29783d8a6d94cd31be70d6f526c10ff09c6fa7ce069795a3fcd0511fd5fcb564bcc80ea9c78f38b80012539d8a4ddf6fe81e9cddb7f50dbbbbcc7e5d86097ccf4ec49189fb8bf318be6d5a0715d516b49af191258cd32dc833ce6eb4673c03a19bbace88cc54895f636cc0c1ec89096d11ce235a265ca1764232a689ae8"],
1061 .message = [NSData dataWithHexString:@"fd326429df9b890e09b54b18b8f34f1e24"],
1062 .seed = [NSData dataWithHexString:@"e89bb032c6ce622cbdb53bc9466014ea77f777c0"],
1063 .encryptedMessage = [NSData dataWithHexString:@"81ebdd95054b0c822ef9ad7693f5a87adfb4b4c4ce70df2df84ed49c04da58ba5fc20a19e1a6e8b7a3900b22796dc4e869ee6b42792d15a8eceb56c09c69914e813cea8f6931e4b8ed6f421af298d595c97f4789c7caa612c7ef360984c21b93edc5401068b5af4c78a8771b984d53b8ea8adf2f6a7d4a0ba76c75e1dd9f658f20ded4a46071d46d7791b56803d8fea7f0b0f8e41ae3f09383a6f9585fe7753eaaffd2bf94563108beecc207bbb535f5fcc705f0dde9f708c62f49a9c90371d3"],
1068 .message = [NSData dataWithHexString:@"f1459b5f0c92f01a0f723a2e5662484d8f8c0a20fc29dad6acd43bb5f3effdf4e1b63e07fdfe6628d0d74ca19bf2d69e4a0abf86d293925a796772f8088e"],
1069 .seed = [NSData dataWithHexString:@"606f3b99c0b9ccd771eaa29ea0e4c884f3189ccc"],
1070 .encryptedMessage = [NSData dataWithHexString:@"bcc35f94cde66cb1136625d625b94432a35b22f3d2fa11a613ff0fca5bd57f87b902ccdc1cd0aebcb0715ee869d1d1fe395f6793003f5eca465059c88660d446ff5f0818552022557e38c08a67ead991262254f10682975ec56397768537f4977af6d5f6aaceb7fb25dec5937230231fd8978af49119a29f29e424ab8272b47562792d5c94f774b8829d0b0d9f1a8c9eddf37574d5fa248eefa9c5271fc5ec2579c81bdd61b410fa61fe36e424221c113addb275664c801d34ca8c6351e4a858"],
1075 .message = [NSData dataWithHexString:@"53e6e8c729d6f9c319dd317e74b0db8e4ccca25f3c8305746e137ac63a63ef3739e7b595abb96e8d55e54f7bd41ab433378ffb911d"],
1076 .seed = [NSData dataWithHexString:@"fcbc421402e9ecabc6082afa40ba5f26522c840e"],
1077 .encryptedMessage = [NSData dataWithHexString:@"232afbc927fa08c2f6a27b87d4a5cb09c07dc26fae73d73a90558839f4fd66d281b87ec734bce237ba166698ed829106a7de6942cd6cdce78fed8d2e4d81428e66490d036264cef92af941d3e35055fe3981e14d29cbb9a4f67473063baec79a1179f5a17c9c1832f2838fd7d5e59bb9659d56dce8a019edef1bb3accc697cc6cc7a778f60a064c7f6f5d529c6210262e003de583e81e3167b89971fb8c0e15d44fffef89b53d8d64dd797d159b56d2b08ea5307ea12c241bd58d4ee278a1f2e"],
1082 .message = [NSData dataWithHexString:@"b6b28ea2198d0c1008bc64"],
1083 .seed = [NSData dataWithHexString:@"23aade0e1e08bb9b9a78d2302a52f9c21b2e1ba2"],
1084 .encryptedMessage = [NSData dataWithHexString:@"438cc7dc08a68da249e42505f8573ba60e2c2773d5b290f4cf9dff718e842081c383e67024a0f29594ea987b9d25e4b738f285970d195abb3a8c8054e3d79d6b9c9a8327ba596f1259e27126674766907d8d582ff3a8476154929adb1e6d1235b2ccb4ec8f663ba9cc670a92bebd853c8dbf69c6436d016f61add836e94732450434207f9fd4c43dec2a12a958efa01efe2669899b5e604c255c55fb7166de5589e369597bb09168c06dd5db177e06a1740eb2d5c82faeca6d92fcee9931ba9f"],
1089 .message = [NSData dataWithHexString:@"8bba6bf82a6c0f86d5f1756e97956870b08953b06b4eb205bc1694ee"],
1090 .seed = [NSData dataWithHexString:@"47e1ab7119fee56c95ee5eaad86f40d0aa63bd33"],
1091 .encryptedMessage = [NSData dataWithHexString:@"53ea5dc08cd260fb3b858567287fa91552c30b2febfba213f0ae87702d068d19bab07fe574523dfb42139d68c3c5afeee0bfe4cb7969cbf382b804d6e61396144e2d0e60741f8993c3014b58b9b1957a8babcd23af854f4c356fb1662aa72bfcc7e586559dc4280d160c126785a723ebeebeff71f11594440aaef87d10793a8774a239d4a04c87fe1467b9daf85208ec6c7255794a96cc29142f9a8bd418e3c1fd67344b0cd0829df3b2bec60253196293c6b34d3f75d32f213dd45c6273d505adf4cced1057cb758fc26aeefa441255ed4e64c199ee075e7f16646182fdb464739b68ab5daff0e63e9552016824f054bf4d3c8c90a97bb6b6553284eb429fcc"],
1096 .message = [NSData dataWithHexString:@"e6ad181f053b58a904f2457510373e57"],
1097 .seed = [NSData dataWithHexString:@"6d17f5b4c1ffac351d195bf7b09d09f09a4079cf"],
1098 .encryptedMessage = [NSData dataWithHexString:@"a2b1a430a9d657e2fa1c2bb5ed43ffb25c05a308fe9093c01031795f5874400110828ae58fb9b581ce9dddd3e549ae04a0985459bde6c626594e7b05dc4278b2a1465c1368408823c85e96dc66c3a30983c639664fc4569a37fe21e5a195b5776eed2df8d8d361af686e750229bbd663f161868a50615e0c337bec0ca35fec0bb19c36eb2e0bbcc0582fa1d93aacdb061063f59f2ce1ee43605e5d89eca183d2acdfe9f81011022ad3b43a3dd417dac94b4e11ea81b192966e966b182082e71964607b4f8002f36299844a11f2ae0faeac2eae70f8f4f98088acdcd0ac556e9fccc511521908fad26f04c64201450305778758b0538bf8b5bb144a828e629795"],
1103 .message = [NSData dataWithHexString:@"510a2cf60e866fa2340553c94ea39fbc256311e83e94454b4124"],
1104 .seed = [NSData dataWithHexString:@"385387514deccc7c740dd8cdf9daee49a1cbfd54"],
1105 .encryptedMessage = [NSData dataWithHexString:@"9886c3e6764a8b9a84e84148ebd8c3b1aa8050381a78f668714c16d9cfd2a6edc56979c535d9dee3b44b85c18be8928992371711472216d95dda98d2ee8347c9b14dffdff84aa48d25ac06f7d7e65398ac967b1ce90925f67dce049b7f812db0742997a74d44fe81dbe0e7a3feaf2e5c40af888d550ddbbe3bc20657a29543f8fc2913b9bd1a61b2ab2256ec409bbd7dc0d17717ea25c43f42ed27df8738bf4afc6766ff7aff0859555ee283920f4c8a63c4a7340cbafddc339ecdb4b0515002f96c932b5b79167af699c0ad3fccfdf0f44e85a70262bf2e18fe34b850589975e867ff969d48eabf212271546cdc05a69ecb526e52870c836f307bd798780ede"],
1110 .message = [NSData dataWithHexString:@"bcdd190da3b7d300df9a06e22caae2a75f10c91ff667b7c16bde8b53064a2649a94045c9"],
1111 .seed = [NSData dataWithHexString:@"5caca6a0f764161a9684f85d92b6e0ef37ca8b65"],
1112 .encryptedMessage = [NSData dataWithHexString:@"6318e9fb5c0d05e5307e1683436e903293ac4642358aaa223d7163013aba87e2dfda8e60c6860e29a1e92686163ea0b9175f329ca3b131a1edd3a77759a8b97bad6a4f8f4396f28cf6f39ca58112e48160d6e203daa5856f3aca5ffed577af499408e3dfd233e3e604dbe34a9c4c9082de65527cac6331d29dc80e0508a0fa7122e7f329f6cca5cfa34d4d1da417805457e008bec549e478ff9e12a763c477d15bbb78f5b69bd57830fc2c4ed686d79bc72a95d85f88134c6b0afe56a8ccfbc855828bb339bd17909cf1d70de3335ae07039093e606d655365de6550b872cd6de1d440ee031b61945f629ad8a353b0d40939e96a3c450d2a8d5eee9f678093c8"],
1117 .message = [NSData dataWithHexString:@"a7dd6c7dc24b46f9dd5f1e91ada4c3b3df947e877232a9"],
1118 .seed = [NSData dataWithHexString:@"95bca9e3859894b3dd869fa7ecd5bbc6401bf3e4"],
1119 .encryptedMessage = [NSData dataWithHexString:@"75290872ccfd4a4505660d651f56da6daa09ca1301d890632f6a992f3d565cee464afded40ed3b5be9356714ea5aa7655f4a1366c2f17c728f6f2c5a5d1f8e28429bc4e6f8f2cff8da8dc0e0a9808e45fd09ea2fa40cb2b6ce6ffff5c0e159d11b68d90a85f7b84e103b09e682666480c657505c0929259468a314786d74eab131573cf234bf57db7d9e66cc6748192e002dc0deea930585f0831fdcd9bc33d51f79ed2ffc16bcf4d59812fcebcaa3f9069b0e445686d644c25ccf63b456ee5fa6ffe96f19cdf751fed9eaf35957754dbf4bfea5216aa1844dc507cb2d080e722eba150308c2b5ff1193620f1766ecf4481bafb943bd292877f2136ca494aba0"],
1124 .message = [NSData dataWithHexString:@"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac"],
1125 .seed = [NSData dataWithHexString:@"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32"],
1126 .encryptedMessage = [NSData dataWithHexString:@"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46"],
1131 int max_cycles = 100;
1132 if (!getenv("SUBMISSION_TEST")) {
1134 CFfprintf(stderr, "Running the far faster but far less reliable fast test.\nSet the SUBMISSION_TEST environment variable for full testing\n");
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;
1143 SecTransformRef encryptor = SecEncryptTransformCreate(tests[i].keys.pubKey, &err);
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);
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);
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);
1175 -(void)testNoSignKeyMakesError
1177 NSData *data = [NSData dataWithBytes:"" length:1];
1181 CFErrorRef createError;
1182 SecTransformRef transform;
1186 .createError = NULL,
1187 .transform = SecSignTransformCreate(NULL, &(test_cases[0].createError))
1191 .createError = NULL,
1192 .transform = SecVerifyTransformCreate(NULL, (CFDataRef)data, &(test_cases[1].createError))
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) {
1204 __block CFErrorRef err = NULL;
1205 SecTransformSetAttribute(test->transform, kSecTransformInputAttributeName, data, &err);
1206 STAssertNil((id)err, @"Error setting input for %@: %@", test->name, err);
1208 dispatch_group_t execute_done = dispatch_group_create();
1209 dispatch_group_enter(execute_done);
1211 SecTransformExecuteAsync(test->transform, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
1216 dispatch_group_leave(execute_done);
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);
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;
1236 CFDataRef rightAnswer;
1237 CFComparisonResult ok;
1239 // create the object
1240 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA1, 20, &error);
1241 STAssertNil((id) error, @"Unexpected error returned.");
1244 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error);
1245 STAssertNil((id) error, @"Unexpected error returned.");
1248 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error);
1249 STAssertNil((id) error, @"Unexpected error returned.");
1251 result = (CFDataRef) SecTransformExecute(hmacRef, &error);
1255 STAssertNil((id) error, @"Unexpected error returned.");
1259 STAssertNotNil((id) result, @"No data returned for SHA1");
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);
1273 STAssertTrue(ok, @"Digest returned incorrect HMACSHA1 result.");
1275 //+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
1277 // create the object
1278 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA2, 256, &error);
1279 STAssertNil((id) error, @"Unexpected error returned.");
1282 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error);
1283 STAssertNil((id) error, @"Unexpected error returned.");
1286 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error);
1287 STAssertNil((id) error, @"Unexpected error returned.");
1289 result = (CFDataRef) SecTransformExecute(hmacRef, &error);
1293 STAssertNil((id) error, @"Unexpected error returned.");
1297 STAssertNotNil((id) result, @"No data returned for SHA256");
1299 rightAnswer = CFDataCreate(NULL, gSHA256HMAC, sizeof(gSHA256HMAC));
1300 ok = CFEqual(result, rightAnswer);
1302 CFRelease(rightAnswer);
1305 CFRelease(hmacData);
1309 STAssertTrue(ok, @"Digest returned incorrect HMACSHA256 result.");
1314 -(void)echoParams:(NSString*)p1 p2:(NSString*)p2
1318 -(void)testReadStreamTransform
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");
1329 CFReadStreamRef readStreamRef = CFReadStreamCreateWithFile(NULL, url);
1330 SecTransformRef transform = SecTransformCreateReadTransformWithReadStream(readStreamRef);
1331 STAssertNotNil((id) transform, @"Returned transform should not be nil.");
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;
1337 SecTransformExecuteAsync(transform, queue,
1338 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
1342 bytes_presented += CFDataGetLength((CFDataRef)message);
1346 STAssertNil((id)error, @"Unexpected error!");
1347 dispatch_semaphore_signal(waitSemaphore);
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);
1356 dispatch_release(queue);
1357 dispatch_release(waitSemaphore);
1358 CFRelease(transform);
1359 CFRelease(readStreamRef);
1361 CFRelease(resolved_url);
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;
1372 SecTransformRef mgfTransform = SecCreateMaskGenerationFunctionTransform(NULL, 107, &err);
1373 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err);
1375 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, seed, &err);
1376 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err);
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");
1382 CFRelease(mgfTransform);
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};
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));
1392 mgfTransform = SecCreateMaskGenerationFunctionTransform(kSecDigestSHA1, 20, &err);
1393 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err);
1395 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, maskedDB, &err);
1396 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err);
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");
1403 -(void)testAbortParams
1405 // make a simple transform
1406 SecTransformRef a = SecNullTransformCreate();
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)
1414 CFRelease(errorRef);
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();
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);
1431 SecTransformSetAttribute(pass_through, kSecTransformInputAttributeName, dev_null_stream, NULL);
1432 SecTransformConnectTransforms(pass_through, kSecTransformOutputAttributeName, null_abort, kSecTransformAbortAttributeName, test_null_abort_via_connection, NULL);
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);
1439 CFErrorRef err = NULL;
1440 CFTypeRef not_null = SecTransformExecute(test_null_abort_via_connection, &err);
1442 STAssertNotNil((id)not_null, @"aborted via a NULL from a connection? err=%@", err);
1449 CFRelease(test_null_abort_via_connection);
1450 CFRelease(pass_through);
1451 CFRelease(null_abort);
1452 CFRelease(delay_null);
1454 CFReadStreamClose(dev_null_stream);
1455 CFRelease(dev_null_stream);
1459 -(void)testDisconnect
1461 SecTransformRef a = SecNullTransformCreate();
1462 SecTransformRef b = SecNullTransformCreate();
1463 SecTransformRef c = SecNullTransformCreate();
1464 SecGroupTransformRef g = SecTransformCreateGroupTransform();
1466 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, g, NULL);
1467 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName, g, NULL);
1469 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName);
1470 STAssertTrue(SecGroupTransformHasMember(g, a), @"A should still be in the group, but isn't");
1472 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName);
1473 STAssertFalse(SecGroupTransformHasMember(g, a), @"A should no longer be in the group, but is");
1484 CFStringRef abort_test_name = CFSTR("com.apple.security.unit-test.abortTest");
1486 SecTransformCreateBlock setupBlock =
1487 ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params)
1489 params->send(kSecTransformInputAttributeName, kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
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;
1501 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1503 // make two of these transforms and link them together
1504 a = custom_transform(abort_test_name, setupBlock);
1505 STAssertNotNil((id) a, @"SecCustomTransformCreate failed");
1507 dt = delay_transform(NSEC_PER_SEC / 10);
1508 STAssertNotNil((id) dt, @"SecCustomTransformCreate failed");
1510 // connect the two transforms
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.");
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.");
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};
1524 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, data, sizeof(data), kCFAllocatorNull);
1525 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, dataRef, NULL);
1527 CFStringRef str = CFStringCreateMutable(NULL, 0);
1528 SecTransformSetAttribute(a, CFSTR("PB"), str, NULL);
1530 CFTypeRef er = SecTransformExecute(a, &error);
1532 STAssertNil((id)er, @"Didn't expect an result from aborted transform");
1533 STAssertNotNil((id)error, @"Expected error from execute");
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.");
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");
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");
1569 -(void)testFireAndForget
1572 NSGarbageCollector* gc = [NSGarbageCollector defaultCollector];
1575 isGC = [gc isEnabled];
1578 CFIndex retCount = 0;
1581 SecNullTransformRef a = SecNullTransformCreate();
1582 SecNullTransformRef b = SecNullTransformCreate();
1583 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1584 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL);
1588 retCount = CFGetRetainCount(group);
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);
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);
1606 SecTransformExecuteAsync(group, queue,
1607 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
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()));
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);
1621 dispatch_semaphore_signal(semaphore2);
1622 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
1624 // no crash? Life is good.
1628 -(void)testExternalSource
1630 CFErrorRef err = NULL;
1631 SecTransformRef xs = SecExternalSourceTransformCreate(&err);
1632 SecTransformRef tee = SecNullTransformCreate();
1633 SecTransformRef group = SecTransformCreateGroupTransform();
1635 SecTransformConnectTransforms(xs, kSecTransformOutputAttributeName, tee, kSecTransformInputAttributeName, group, &err);
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;
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);
1646 if (CFEqual(message, CFSTR("PING"))) {
1649 STFail(@"expected ping, got: %@", message);
1654 STFail(@"unexpected error: %@", error);
1659 STFail(@"never got ping");
1661 dispatch_group_leave(dg);
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);
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);
1676 dispatch_release(dg);
1677 dispatch_release(q);
1683 -(void)testFindLastAndMonitor
1685 SecNullTransformRef a = delay_transform(NSEC_PER_SEC / 10);
1686 SecNullTransformRef b = SecNullTransformCreate();
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.");
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");
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)
1711 dispatch_semaphore_signal(last_block_run);
1712 dispatch_semaphore_wait(last_assert_run, DISPATCH_TIME_FOREVER);
1713 dispatch_release(last_assert_run);
1718 dispatch_semaphore_wait(last_block_run, DISPATCH_TIME_FOREVER);
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");
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");
1732 dispatch_semaphore_signal(last_assert_run);
1733 dispatch_release(queue);
1734 dispatch_release(last_block_run);
1737 CFRelease(groupRef);
1741 -(void)testConnectUnsetAttributes /* <rdar://problem/7769955> Can't connect transform attributes with no setting */
1743 SecNullTransformRef a = SecNullTransformCreate();
1744 SecNullTransformRef b = SecNullTransformCreate();
1746 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1747 CFErrorRef error = NULL;
1748 SecTransformConnectTransforms(a, CFSTR("RANDOM_NAME"), b, CFSTR("RANDOM_DESTINATION"), group, &error);
1752 STAssertNil((id) error, @"An error was returned when none was expected.");
1755 -(void)testNoDataFlowPriorToInit /* <rdar://problem/8163542> Monitor must be attached before the data flow becomes active */
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"));
1766 params->overrideTransform(kSecTransformActionStartingExecution, ^{
1767 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("x-start"));
1769 return (CFTypeRef)NULL;
1772 params->overrideTransform(kSecTransformActionCanExecute, ^{
1773 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("can-x"));
1774 return (CFTypeRef)NULL;
1777 params->overrideAttribute(kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef ah, CFTypeRef value) {
1781 saw_x_start = CFStringHasPrefix((CFStringRef)value, CFSTR("x-start"));
1784 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 88, "saw %@ after NULL", value));
1786 if (post_send_left--) {
1787 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("post-init"));
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)) {
1795 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "saw bogus x-start on FIRST flow transform"));
1797 params->send(out_ah, kSecTransformMetaAttributeValue, value);
1801 params->send(out_ah, kSecTransformMetaAttributeValue, value);
1803 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "never saw x-start before EOS"));
1804 return (CFTypeRef)kCFNull;
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;
1813 return (CFTypeRef)value;
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;
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");
1828 CFMutableArrayRef ta = CFArrayCreateMutable(NULL, n_transforms, &kCFTypeArrayCallBacks);
1829 CFErrorRef err = NULL;
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);
1840 STAssertNil((id)err, @"Can't set name %@", err);
1841 CFArrayAppendValue(ta, tr);
1842 assert(CFArrayGetCount(ta));
1843 assert(CFArrayGetCount(ta) == i+1);
1846 SecTransformRef prev_tr = NULL;
1847 SecTransformRef group = SecTransformCreateGroupTransform();
1850 while ((cnt = CFArrayGetCount(ta))) {
1851 CFIndex r = arc4random() % cnt;
1852 SecTransformRef tr = CFArrayGetValueAtIndex(ta, r);
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");
1860 CFArrayRemoveValueAtIndex(ta, r);
1862 if (0 == cnt % 1000) {
1863 CFfprintf(stderr, "%d left to hook up\n", cnt);
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");
1880 -(void)testNoDataDescription /* <rdar://problem/7791122> CFShow(SecCustomTransformNoData()) crashes */
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");
1887 static SecTransformInstanceBlock KnownProblemPlumbing(CFStringRef name,
1888 SecTransformRef newTransform,
1889 SecTransformImplementationRef ref)
1891 SecTransformInstanceBlock instanceBlock =
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);
1899 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName,
1900 ^(SecTransformAttributeRef ah, CFTypeRef value)
1902 return (CFTypeRef)CFErrorCreate(NULL, kCFErrorDomainPOSIX, EOPNOTSUPP, NULL);
1907 return Block_copy(instanceBlock);
1910 -(void)knownProblemPlumbing // note, this test has been disconnected!
1912 SecNullTransformRef a = SecNullTransformCreate();
1913 CFStringRef name = CFSTR("com.apple.security.unit-test.error+outputless");
1914 CFErrorRef err = NULL;
1916 SecTransformRegister(name, &KnownProblemPlumbing, &err);
1918 SecTransformRef b = SecTransformCreate(name, NULL);
1919 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1921 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL);
1922 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName);
1925 CFStringRef data = CFSTR("Test");
1927 SecTransformSetAttribute(a, kSecTransformInputAttributeName, data, NULL);
1928 CFTypeRef result = SecTransformExecute(a, &err);
1930 STAssertEqualObjects((id)data, (id)result, @"Plumbing disconnect failed.");
1931 STAssertNil((id)err, @"Unexpected error=%@", err);
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);
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);
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);
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);
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);
1972 STFail(@"Unable to run some tests");
1975 CFRelease(no_type_at_create);
1976 CFRelease(invalid_encode_type);
1979 -(void)testNoUnderscores
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);
1993 -(void)testCanFetchDigestSizes
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,
2002 NSData *zero = [NSData dataWithBytes:"" length:1];
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);
2014 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, zero, &err);
2015 STAssertNil((id)err, @"Unexpected error: %@", err);
2017 NSData *output = (NSData *)SecTransformExecute(digest, &err);
2018 STAssertNil((id)err, @"Unexpected error: %@", err);
2019 STAssertNotNil((id)output, @"No output");
2021 STAssertEquals([actualLength intValue], (int)[output length], @"Actual output not expected length");
2028 -(void)testBadTransformTypeNames
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);
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);
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);
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);
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);
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];
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;
2064 SecTransformExecuteAsync(zt, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
2065 // if ([empty length]) {
2066 // NSLog(@"Empty data not so empty");
2068 STAssertTrue(dispatch_get_current_queue() == q, @"block dispatched to proper queue");
2075 if (message == NULL) {
2076 dispatch_resume((dispatch_object_t)q_sync);
2080 //STAssertTrue(ecnt < [empty retainCount], @"SecTransformExecute retained block");
2081 dispatch_sync(q_sync, ^{ });
2082 STAssertTrue(ran_block, @"Block executed");
2084 dispatch_release(q_sync);
2085 dispatch_release(q);
2089 // STAssertTrue(ecnt == [empty retainCount], @"SecTransformExecute released block");
2092 static SecTransformInstanceBlock ConnectionCheck(CFStringRef name,
2093 SecTransformRef newTransform,
2094 SecTransformImplementationRef ref)
2096 SecTransformInstanceBlock instanceBlock =
2098 CFErrorRef result = NULL;
2099 __block SecTransformMetaAttributeType dir = kSecTransformMetaAttributeValue;
2101 SecTransformAttributeRef out_ah =
2102 SecTranformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef);
2104 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DIRECTION"),
2105 ^(SecTransformAttributeRef ah, CFTypeRef value)
2107 if (CFEqual(value, CFSTR("<")))
2109 dir = kSecTransformMetaAttributeHasInboundConnection;
2111 else if (CFEqual(value, CFSTR(">")))
2113 dir = kSecTransformMetaAttributeHasOutboundConnections;
2117 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unsupported direction %@, expected < or >", value);
2122 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2123 ^(SecTransformAttributeRef ah, CFTypeRef value)
2125 if (dir != kSecTransformMetaAttributeValue)
2129 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue,
2130 SecTranformCustomGetAttribute(ref, value, dir));
2134 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, NULL);
2139 SecTransformPushbackAttribute(ref, ah, value);
2148 return Block_copy(instanceBlock);
2151 -(void)testConnectionChecks {
2153 CFStringRef name = CFSTR("com.apple.security.unit-test.connection-checks");
2154 CFErrorRef error = NULL;
2155 SecTransformRegister(name, &*ConnectionCheck, &error);
2158 NSString *attr, *dir;
2159 CFBooleanRef expect;
2161 {@"INPUT", @"<", kCFBooleanTrue},
2162 {@"OUTPUT", @">", kCFBooleanTrue},
2163 {@"INPUT", @">", kCFBooleanFalse},
2164 {@"OUTPUT", @"<", kCFBooleanFalse},
2165 {@"DIRECTION", @"<", kCFBooleanFalse},
2166 {@"DIRECTION", @">", kCFBooleanFalse},
2169 CFIndex i, n = sizeof(cases)/sizeof(test_case);
2170 for(i = 0; i < n; ++i)
2172 test_case *t = cases + i;
2174 SecTransformRef cct = SecTransformCreate(name, NULL);
2175 SecTransformRef tee0 = SecNullTransformCreate();
2176 SecTransformRef tee1 = SecNullTransformCreate();
2177 SecTransformRef group = SecTransformCreateGroupTransform();
2179 SecTransformSetAttribute(cct, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2180 SecTransformSetAttribute(tee0, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2181 SecTransformSetAttribute(tee1, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2183 SecTransformSetAttribute(tee0, CFSTR("NAME"), CFSTR("tee0"), NULL);
2184 SecTransformSetAttribute(tee1, CFSTR("NAME"), CFSTR("tee1"), NULL);
2186 SecTransformConnectTransforms(cct, CFSTR("OUTPUT"), tee1, CFSTR("INPUT"), group, NULL);
2187 SecTransformConnectTransforms(tee0, CFSTR("OUTPUT"), cct, CFSTR("INPUT"), group, NULL);
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);
2205 static SecTransformInstanceBlock PushBackTest(CFStringRef name,
2206 SecTransformRef newTransform,
2207 SecTransformImplementationRef ref)
2209 SecTransformInstanceBlock instanceBlock =
2211 CFErrorRef result = NULL;
2212 __block CFStringRef input_d = NULL;
2213 __block CFStringRef data_d = NULL;
2215 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DATA"),
2216 ^(SecTransformAttributeRef ah, CFTypeRef value)
2220 SecTransformPushbackAttribute(ref, ah, value);
2228 data_d = (CFStringRef)CFRetain(value);
2233 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2234 ^(SecTransformAttributeRef ah, CFTypeRef value)
2242 input_d = (CFStringRef)CFRetain(value);
2245 SecTransformPushbackAttribute(ref, ah, value);
2253 SecTransformPushbackAttribute(ref, ah, NULL);
2258 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
2265 return Block_copy(instanceBlock);
2268 -(void)testPushback {
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");
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.
2280 CFErrorRef error = NULL;
2281 SecTransformRegister(name, &PushBackTest, &error);
2283 SecTransformRef pt = SecTransformCreate(name, NULL);
2285 SecTransformSetAttribute(pt, CFSTR("DATA"), two, NULL);
2286 SecTransformSetAttribute(pt, CFSTR("INPUT"), one, NULL);
2288 CFTypeRef result = SecTransformExecute(pt, NULL);
2290 STAssertEqualObjects((id)result, (id)expect, @"Testing pushback");
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
2298 static SecTransformInstanceBlock CustomExternalization(CFStringRef name,
2299 SecTransformRef newTransform,
2300 SecTransformImplementationRef ref)
2302 SecTransformInstanceBlock instanceBlock =
2304 CFErrorRef result = NULL;
2305 // Create a non-attribute 'instance' variable which will contain
2306 // the version number of this class
2308 __block float versionNumber = 1.0;
2310 // Register the custom externalize override
2311 SecTransformActionBlock ExternalizeExtraDataOverride =
2313 CFStringRef key = CFSTR("VersionNumber");
2314 CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &versionNumber);
2316 CFDictionaryRef result = CFDictionaryCreate(kCFAllocatorDefault,
2317 (const void **)&key, (const void **)&value,
2318 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2323 return (CFTypeRef)result;
2326 SecTransformSetTransformAction(ref, kSecTransformActionExternalizeExtraData, ExternalizeExtraDataOverride);
2328 // Register the custom internalize override
2329 SecTransformDataBlock InternalizeExtraDataOverride =
2332 CFTypeRef internalizeResult = NULL;
2333 //id testObj = (id)d;
2335 //STAssertNotNil(testObj, @"Internalize did NOT get a dictionary!");
2337 if (CFDictionaryGetTypeID() == CFGetTypeID(d))
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)
2346 Boolean numResult = CFNumberGetValue(varsNum, kCFNumberFloatType, &versionNumber);
2347 // STAssertTrue(numResult, @"Could not get the version number from the CFNumberRef");
2350 //float knownVersion = 1.0;
2351 // STAssertTrue(knownVersion == versionNumber, @"Versions do not Match!");
2355 return internalizeResult;
2357 SecTransformSetDataAction(ref, kSecTransformActionInternalizeExtraData,
2358 InternalizeExtraDataOverride);
2363 return Block_copy(instanceBlock);
2366 /* --------------------------------------------------------------------------
2367 method: testCustomExternalization
2368 description: Test the ability to write out custom external data
2369 -------------------------------------------------------------------------- */
2370 - (void)testCustomExternalization
2372 NSString* ctName = @"com.apple.security.unit-test-customExternalization";
2373 NSError* error = nil;
2375 CFStringRef aName = (CFStringRef)ctName;
2376 CFErrorRef* anError = (CFErrorRef *)&error;
2378 Boolean registerResult = SecTransformRegister(aName, &CustomExternalization, anError);
2379 STAssertTrue(registerResult, @"Unable to register the custom externalization transform");
2381 SecTransformRef externalTrans = SecTransformCreate((CFStringRef)ctName,
2382 (CFErrorRef *)&error);
2384 STAssertNotNil((id)externalTrans, @"Could not create the custom externalization transform");
2386 CFDictionaryRef externalData = SecTransformCopyExternalRepresentation(externalTrans);
2387 STAssertNotNil((NSDictionary *)externalData, @"Did not get a dictionary from SecTransformCopyExternalRepresentation");
2389 CFRelease(externalTrans);
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)
2397 CFRelease(externalTrans);
2401 static SecTransformInstanceBlock TestString(CFStringRef name,
2402 SecTransformRef newTransform,
2403 SecTransformImplementationRef ref)
2405 SecTransformInstanceBlock instanceBlock =
2407 CFErrorRef result = NULL;
2408 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
2411 CFDataRef d = (CFDataRef)value;
2413 return (CFTypeRef)CFStringCreateWithBytes(NULL, CFDataGetBytePtr(d), CFDataGetLength(d), kCFStringEncodingMacRoman, FALSE);
2415 return (CFTypeRef)d;
2421 return Block_copy(instanceBlock);
2424 -(void)testStringResults {
2425 CFStringRef name = CFSTR("com.apple.security.unit-test.string-converter");
2426 CFErrorRef error = NULL;
2427 SecTransformRegister(name, &TestString, &error);
2429 SecTransformRef sr = SecTransformCreate(name, NULL);
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];
2435 SecTransformRef er = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
2436 SecTransformRef dr = SecDecodeTransformCreate(kSecBase32Encoding, NULL);
2438 SecTransformSetAttribute(er, kSecTransformInputAttributeName, data, NULL);
2440 SecGroupTransformRef group = SecTransformCreateGroupTransform();
2441 SecTransformConnectTransforms(er, kSecTransformOutputAttributeName, dr, kSecTransformInputAttributeName, group, NULL);
2442 SecTransformConnectTransforms(dr, kSecTransformOutputAttributeName, sr, kSecTransformInputAttributeName, group, NULL);
2445 CFStringRef result = (CFStringRef)SecTransformExecute(sr, NULL);
2446 STAssertEqualObjects(ns_msg, (NSString *)result, @"string results");
2459 static CFNumberRef MakeNumber1(long n)
2461 return CFNumberCreate(NULL, kCFNumberLongType, &n);
2466 static SecTransformInstanceBlock TestRegisterCreate(CFStringRef name,
2467 SecTransformRef newTransform,
2468 SecTransformImplementationRef ref)
2472 SecTransformInstanceBlock instanceBlock =
2474 __block long count = 0;
2476 __block CFNumberRef countNum = MakeNumber1(count);;
2477 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum);
2478 CFRelease(countNum);
2479 fprintf(stderr, "countNum = %p\n", countNum);
2481 CFErrorRef result = NULL;
2482 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
2485 CFDataRef d = (CFDataRef)value;
2488 count += CFDataGetLength(d);
2490 CFNumberRef countNum2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &count);
2491 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum2);
2492 CFRelease(countNum2);
2493 fprintf(stderr, "countNum = %p\n", countNum);
2497 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, NULL);
2506 return Block_copy(instanceBlock);
2509 - (void)testRegisterCreate
2511 CFStringRef name = CFSTR("com.apple.security.unit-test.novel-unique-at-least-unusual-name");
2513 CFNumberRef countNum = NULL;
2514 CFErrorRef error = NULL;
2515 Boolean ok = SecTransformRegister(name, &TestRegisterCreate, &error);
2516 STAssertTrue(ok, @"Successful register");
2518 SecTransformRef tr = SecTransformCreate(name, NULL);
2519 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
2520 SecTransformSetAttribute(tr, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
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));
2525 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
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);
2534 SecTransformSetAttribute(nt, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2537 countNum = (CFNumberRef)SecTransformGetAttribute(tr, CFSTR("Count"));
2538 CFNumberGetValue(countNum, kCFNumberLongType, &count);
2539 CFRelease(countNum);
2540 STAssertTrue(count == 0, @"length unchanged before execute");
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);
2548 STAssertTrue(count == CFDataGetLength(data), @"Wrong data length");
2557 static SecTransformInstanceBlock CountTransformTest(CFStringRef name,
2558 SecTransformRef newTransform,
2559 SecTransformImplementationRef ref)
2561 SecTransformInstanceBlock instanceBlock =
2563 CFErrorRef result = NULL;
2564 SecTransformSetAttributeAction(ref,kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2565 ^(SecTransformAttributeRef ah, CFTypeRef value)
2568 if (CFGetTypeID(value) != CFNumberGetTypeID()) {
2569 SecTransformCustomSetAttribute(ref, CFSTR("ABORT"), kSecTransformMetaAttributeValue, CFSTR("Bad type"));
2572 CFNumberRef nr = (CFNumberRef)value;
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);
2581 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
2590 return Block_copy(instanceBlock);
2593 static SecTransformRef count_transform(int n) {
2594 CFStringRef name = CFSTR("com.apple.security.unit-test.count");
2595 static dispatch_once_t once;
2597 dispatch_once(&once,
2599 SecTransformRegister(name, &CountTransformTest, NULL);
2602 SecTransformRef ct = SecTransformCreate(name, NULL);
2603 CFNumberRef num = CFNumberCreate(NULL, kCFNumberIntType, &n);
2604 SecTransformSetAttribute(ct, CFSTR("INPUT"), num, NULL);
2611 static SecTransformInstanceBlock StallTest(CFStringRef name,
2612 SecTransformRef newTransform,
2613 SecTransformImplementationRef ref)
2615 SecTransformInstanceBlock instanceBlock =
2617 CFErrorRef result = NULL;
2618 __block bool go = false;
2620 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("GO"),
2621 ^(SecTransformAttributeRef ah, CFTypeRef value)
2627 SecTransformAttributeRef in_ah = SecTransformCustomGetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeRef);
2628 SecTransformAttributeRef out_ah = SecTransformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef);
2630 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL,
2631 ^(SecTransformAttributeRef ah, CFTypeRef value)
2634 SecTransformPushbackAttribute(ref, ah, value);
2637 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, value);
2646 return Block_copy(instanceBlock);
2650 CFStringRef name = CFSTR("com.apple.security.unit-test.stall");
2652 (void)SecTransformRegister(name, &StallTest, NULL);
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);
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);
2665 SecTransformSetAttribute(delay, CFSTR("INPUT"), (CFNumberRef)[NSNumber numberWithInt:42], NULL);
2667 CFErrorRef err = NULL;
2668 CFTypeRef r = SecTransformExecute(group, &err);
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");
2681 -(void)testInappropriateExecution
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.
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);
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();
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);
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)
2706 dispatch_group_enter(outstanding_executions);
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");
2714 dispatch_group_leave(outstanding_executions);
2718 // Give any pending executions time to get to the group_enter
2720 dispatch_group_wait(outstanding_executions, DISPATCH_TIME_FOREVER);
2721 dispatch_release(outstanding_executions);
2722 dispatch_group_leave(wait_for_async_to_complete);
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.
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);
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");
2740 no_result = SecTransformExecute(no_work_group, &err);
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);
2746 // Now we wait for that first batch of tests to finish, we don't want to call STFail after self goes away.
2748 dispatch_group_wait(wait_for_async_to_complete, DISPATCH_TIME_FOREVER);
2749 dispatch_release(wait_for_async_to_complete);
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);
2758 static SecTransformInstanceBlock ConnectionReqTest(CFStringRef name,
2759 SecTransformRef newTransform,
2760 SecTransformImplementationRef ref)
2762 SecTransformInstanceBlock instanceBlock =
2764 CFErrorRef result = NULL;
2765 SecTransformAttributeRef xah =
2766 (SecTransformAttributeRef)SecTranformCustomGetAttribute(ref, CFSTR("XYZZY"), kSecTransformMetaAttributeRef);
2768 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanTrue);
2769 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanFalse);
2770 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2771 ^(SecTransformAttributeRef ah, CFTypeRef value)
2773 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeValue, value);
2780 return Block_copy(instanceBlock);
2784 -(void)testConnectionReq {
2786 CFStringRef req_xyzzy_name = CFSTR("com.apple.security.unit-test.req_xyzzy");
2788 (void)SecTransformRegister(req_xyzzy_name, &ConnectionReqTest, NULL);
2790 SecTransformRef tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL);
2792 CFTypeRef in_value = (CFTypeRef)@"Fnord";
2793 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL);
2795 CFErrorRef err = NULL;
2796 CFTypeRef r = SecTransformExecute(tr_req_xyzzy, &err);
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);
2804 CFRelease(tr_req_xyzzy);
2805 if (r) CFRelease(r);
2811 To make this work we need Josh's fix for FindLastTransform!
2813 CFRelease(tr_req_xyzzy);
2814 tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL);
2815 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL);
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");
2829 static SecTransformInstanceBlock DeferredTest(CFStringRef name,
2830 SecTransformRef newTransform,
2831 SecTransformImplementationRef ref)
2833 SecTransformInstanceBlock instanceBlock =
2835 CFErrorRef result = NULL;
2836 SecTransformCustomSetAttribute(ref, CFSTR("LATE"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
2837 SecTransformCustomSetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeDeferred, kCFBooleanFalse);
2839 __block CFTypeRef in_v = NULL, late_v = NULL;
2841 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2842 ^(SecTransformAttributeRef ah, CFTypeRef value)
2844 if (NULL != late_v) {
2845 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue,
2846 CreateGenericErrorRef(CFSTR("FAIL"), 1, "LATE (%@) should process after INPUT (%@)", late_v, value));
2852 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("LATE"),
2853 ^(SecTransformAttributeRef ah, CFTypeRef value)
2856 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue,
2857 CreateGenericErrorRef(CFSTR("FAIL"), 1, "INPUT (%@) should process before LATE (%@)", in_v, value));
2861 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, NULL);
2868 return Block_copy(instanceBlock);
2872 -(void)testDeferred {
2873 CFStringRef deferred_name = CFSTR("com.apple.security.unit-test.deferred");
2875 (void)SecTransformRegister(deferred_name, &DeferredTest, NULL);
2877 SecTransformRef dt = SecTransformCreate(deferred_name, NULL);
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);
2886 if (err) CFRelease(err);
2890 static SecTransformInstanceBlock SaveRestoreTest(CFStringRef name,
2891 SecTransformRef newTransform,
2892 SecTransformImplementationRef ref)
2894 SecTransformInstanceBlock instanceBlock =
2896 CFErrorRef result = NULL;
2897 SecTransformCustomSetAttribute(ref, CFSTR("Needed"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
2898 SecTransformCustomSetAttribute(ref, CFSTR("NoSaves"), kSecTransformMetaAttributeExternalize, kCFBooleanFalse);
2903 return Block_copy(instanceBlock);
2906 -(void)testSaveRestore
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;
2913 CFStringRef name = CFSTR("com.apple.security.unit-test.SaveRestoreTest");
2915 (void)SecTransformRegister(name, &SaveRestoreTest, NULL);
2917 SecTransformRef tr1 = SecTransformCreate(name, NULL);
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);
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");
2932 CFDataRef d = (CFDataRef)SecTransformExecute((NSObject *)tr2, &err);
2934 STAssertNotNil((NSData * )d, @"execute result (err=%@)", err);
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);
2952 //tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL);
2953 SecTransformRef tga = SecTransformCreateGroupTransform();
2954 SecTransformSetAttribute(tr1, kSecTransformInputAttributeName, data, NULL);
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);
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);
2971 CFStringRef new_name2 = CFSTR("SaveRestoreTestThingie#2");
2972 CFStringRef fetched_name;
2975 for(attempts = 0; attempts < 20; ++attempts)
2977 SecTransformSetAttribute(tr2, CFSTR("NAME"), new_name2, &err);
2978 fetched_name = (CFStringRef)SecTransformGetAttribute(tr2, CFSTR("NAME"));
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))
2992 xr = SecTransformCopyExternalRepresentation(tr1);
2993 STAssertNotNil((NSDictionary *)xr, @"external rep for 2, take 2");
2994 NSLog(@"xr=%@", xr);
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);
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");
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");
3010 STAssertEqualObjects((id)has1, (id)has1b, @"has1 == has1b");
3011 STAssertEqualObjects((id)has2, (id)has2b, @"has2 == has2b");
3015 -(void)testRequiredAttributes
3017 CFStringRef name = CFSTR("com.apple.security.unit-test.requiresStuffThings");
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;
3023 __block state_t state = S_INITED;
3024 dispatch_group_t leave_on_finalize = dispatch_group_create();
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.
3031 STAssertTrue(state == S_STARTED, @"Init'ed for data (state=%d)", state);
3034 STAssertTrue(state == S_RUN, @"In run state at EOS (state=%d)", state);
3037 params->send(kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
3041 params->send(CFSTR("Stuff"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
3042 params->send(CFSTR("Things"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
3044 params->overrideTransform(kSecTransformActionStartingExecution, ^{
3045 STAssertTrue(state == S_INITED, @"Inited (state=%d)");
3047 return (CFTypeRef)NULL;
3050 params->overrideTransform(kSecTransformActionFinalize, ^{
3052 dispatch_group_leave(leave_on_finalize);
3053 return (CFTypeRef)NULL;
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");
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);
3065 STAssertTrue(state == S_INITED, @"not run yet");
3066 CFDataRef rdata = (CFDataRef)SecTransformExecute((NSObject *)tr, &error);
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);
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);
3082 dispatch_group_enter(leave_on_finalize);
3084 tr = custom_transform(name, required_attributes_create_block);
3085 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
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);
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");
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);
3106 static SecTransformInstanceBlock AttributeNotificationTest(CFStringRef name,
3107 SecTransformRef newTransform,
3108 SecTransformImplementationRef ref)
3110 SecTransformInstanceBlock instanceBlock =
3112 CFErrorRef result = NULL;
3115 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL,
3116 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3118 SecTransformCustomSetAttribute(ref, CFSTR("Generic"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3122 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("Specific"),
3123 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3125 SecTransformCustomSetAttribute(ref, CFSTR("Specific"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3130 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("AlsoSpecific"),
3131 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3133 SecTransformCustomSetAttribute(ref, CFSTR("AlsoSpecific"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3141 return Block_copy(instanceBlock);
3144 -(void)testAttributeNotifications
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;
3151 Boolean ok = SecTransformRegister((CFStringRef)name, &AttributeNotificationTest, NULL);
3153 STAssertTrue(ok, @"Successful register");
3155 SecTransformRef tr = SecTransformCreate((CFStringRef)name, NULL);
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);
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")));
3167 STAssertTrue(generic_called, @"generic called");
3168 STAssertTrue(specific_called, @"specific called");
3169 STAssertTrue(also_specific_called, @"also specific called");
3174 -(void)testEncryptAndDecryptTransforms
3176 NSAutoreleasePool *pool = [NSAutoreleasePool new];
3178 // generate a symmetrical key for testing
3179 OSStatus err = errSecSuccess;
3181 NSString* algNames[] =
3192 CSSM_ALGORITHMS symmetricalAlgos[] =
3198 CSSM_ALGID_3DES_3KEY_EDE,
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);
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.";
3234 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
3235 int numItems = (sizeof(symmetricalAlgos) / sizeof(CSSM_ALGORITHMS));
3238 for (iCnt = 0; iCnt < numItems; iCnt++)
3240 SecKeyRef testKey = NULL;
3241 CSSM_ALGORITHMS algoToUse = symmetricalAlgos[iCnt];
3242 uint32 keySizeInBits = keySizes[iCnt];
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)
3250 __block CFErrorRef error = NULL;
3252 SecTransformRef encryptSymRef = NULL;
3253 encryptSymRef = SecEncryptTransformCreate(testKey, &error);
3257 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key %@", algNames[iCnt]]);
3261 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error);
3265 CFRelease(encryptSymRef);
3266 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key %@", algNames[iCnt]]);
3270 // connect the output of the encryption to the input of the decryption transform
3272 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3273 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName,
3274 decryptSymRef, kSecTransformInputAttributeName,
3279 CFRelease(encryptSymRef);
3280 CFRelease(decryptSymRef);
3281 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key %@", algNames[iCnt]]);
3286 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3289 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3293 CFRelease(encryptSymRef);
3294 CFRelease(decryptSymRef);
3295 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to set the input for key %@", algNames[iCnt]]);
3299 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3301 CFRelease(encryptSymRef);
3302 CFRelease(decryptSymRef);
3306 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for algo %@", algNames[iCnt]]);
3311 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3313 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for %@", algNames[iCnt]]);
3317 NSData* resultData = nil;
3318 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3320 resultData = (NSData*)transformResult;
3321 [resultData autorelease];
3326 STAssertTrue([testData isEqualToData:resultData], @"The output of the decrypt transform does NOT match the original input!");
3330 SecKeyRef publicKey = NULL;
3331 SecKeyRef privateKey = NULL;
3333 keyAttrFlags = CSSM_KEYATTR_RETURN_REF;
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;
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;
3342 err = SecKeyCreatePair(NULL, CSSM_ALGID_RSA, 2048, ((CSSM_CC_HANDLE)0),
3343 pubKeyUse, publicKeyAttributes,
3344 privKeyUse, privateKeyAttributes,
3345 NULL, &publicKey, &privateKey);
3347 STAssertTrue(errSecSuccess == err, @"Unable to create a key pair");
3348 if (errSecSuccess != err)
3350 cssmPerror(NULL, err);
3354 CFErrorRef error = NULL;
3355 SecTransformRef encryptSymRef = SecEncryptTransformCreate(publicKey , &error);
3358 CFRelease(publicKey);
3359 CFRelease(privateKey);
3360 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key RSA"]);
3364 SecTransformRef decryptSymRef = SecDecryptTransformCreate(privateKey, &error);
3367 CFRelease(publicKey);
3368 CFRelease(privateKey);
3369 CFRelease(encryptSymRef);
3370 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key RSA"]);
3374 // connect the output of the encryption to the input of the decryption transform
3376 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3377 (void)SecTransformConnectTransforms( encryptSymRef, kSecTransformOutputAttributeName,
3378 decryptSymRef, kSecTransformInputAttributeName,
3382 CFRelease(publicKey);
3383 CFRelease(privateKey);
3384 CFRelease(encryptSymRef);
3385 CFRelease(decryptSymRef);
3386 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key RSA"]);
3390 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3393 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
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"]);
3403 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3406 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for RSA"]);
3411 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3413 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for RSA"]);
3417 NSData* resultData = nil;
3418 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3420 resultData = (NSData*)transformResult;
3421 [resultData autorelease];
3424 CFRelease(publicKey);
3425 CFRelease(privateKey);
3426 CFRelease(encryptSymRef);
3427 CFRelease(decryptSymRef);
3429 STAssertTrue([testData isEqualToData:resultData], @"(RSA)The output of the decrypt transform does NOT match the original input!");
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);
3444 NSString* dataStr = @"Reduce, reuse, recycle. No crashes please.";
3445 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
3447 SecKeyRef testKey = NULL;
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);
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;
3460 SecTransformRef encryptSymRef = NULL;
3461 encryptSymRef = SecEncryptTransformCreate(testKey, &error);
3464 STFail(@"Unable to create the encrypt transform iteration#%d error=%@", i, error);
3467 if (NULL == encryptSymRef) {
3468 STFail(@"Unable to create the encrypt transform iteration#%d, error=NULL", i);
3472 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error);
3475 CFRelease(encryptSymRef);
3476 STFail(@"Unable to create the decrypt transform iteration#%d error=%@", i, error);
3479 if (NULL == decryptSymRef) {
3480 CFRelease(encryptSymRef);
3481 STFail(@"Unable to create the decrypt transform iteration#%d, error=NULL", i);
3485 // connect the output of the encryption to the input of the decryption transform
3487 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3488 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName,
3489 decryptSymRef, kSecTransformInputAttributeName,
3493 CFRelease(encryptSymRef);
3494 CFRelease(decryptSymRef);
3495 STFail(@"Unable to connect transforms on iteration %d error=%@", i, error);
3500 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3503 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3506 CFRelease(encryptSymRef);
3507 CFRelease(decryptSymRef);
3508 STFail(@"Unable to set the input on iteration %d error=%@", i, error);
3512 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3517 STFail(@"returned an error on iteration %d error=%@", i, error);
3522 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3524 STFail(@"transformResult was NULL or empty for iteration %d", i);
3528 NSData* resultData = nil;
3529 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3531 resultData = (NSData*)transformResult;
3532 [resultData autorelease];
3535 CFRelease(encryptSymRef);
3536 CFRelease(decryptSymRef);
3538 STAssertEqualObjects(testData, resultData, @"The output of the decrypt transform does NOT match the original input iteration %d", i);
3544 static SecTransformInstanceBlock RoundTripCheck(CFStringRef name,
3545 SecTransformRef newTransform,
3546 SecTransformImplementationRef ref)
3548 SecTransformInstanceBlock instanceBlock =
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;
3556 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
3557 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeStream, kCFBooleanTrue);
3559 dispatch_block_t not_equal =
3562 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, kCFBooleanFalse);
3563 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL);
3567 SecTransformAttributeActionBlock action =
3568 ^(SecTransformAttributeRef ah, CFTypeRef value)
3572 return (CFTypeRef)NULL;
3577 SecTransformPushbackAttribute(ref, ah, value);
3581 CFDataRef d = (CFDataRef)value;
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;
3590 if (remainder_length == d_length)
3592 compare_length = d_length;
3594 else if (remainder_length < d_length)
3596 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(d) + remainder_length, d_length - remainder_length);
3597 compare_length = remainder_length;
3601 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(remainder) + d_length, remainder_length - d_length);
3602 compare_length = d_length;
3606 if (bcmp(CFDataGetBytePtr(d), CFDataGetBytePtr(remainder), compare_length)) {
3611 CFRelease(remainder);
3612 remainder = new_remainder;
3621 remainder = CFDataCreateCopy(NULL, d);
3625 if (CFDataGetLength(d))
3635 if (++eof_count == 2)
3639 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3640 kSecTransformMetaAttributeValue,
3641 CFDataGetLength(remainder) ? kCFBooleanFalse : kCFBooleanTrue);
3643 CFRelease(remainder);
3647 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3648 kSecTransformMetaAttributeValue, kCFBooleanTrue);
3651 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3652 kSecTransformMetaAttributeValue, NULL);
3656 return (CFTypeRef)NULL;
3659 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT2"), action);
3660 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, action);
3665 return Block_copy(instanceBlock);
3668 static BOOL RoundTrip(CFStringRef fname, SecTransformRef in, SecTransformRef out, BOOL share)
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
3674 dispatch_once(&once,
3676 SecTransformRegister(name, &RoundTripCheck, NULL);
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
3688 NSInputStream *is2 = nil;
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);
3698 is2 = [NSInputStream inputStreamWithFileAtPath:(NSString *)fname];
3700 SecTransformSetAttribute(in, kSecTransformInputAttributeName, (CFTypeRef)is, &err);
3701 SecTransformSetAttribute(cmp, CFSTR("INPUT2"), (CFTypeRef)is2, &err);
3704 assert(err == NULL);
3705 CFTypeRef r = SecTransformExecute(group, &err);
3727 return r == kCFBooleanTrue;
3731 CFfprintf(stderr, "round trip error: %@", err);
3736 static SecTransformInstanceBlock LineLengthCheck(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref)
3738 SecTransformInstanceBlock instanceBlock = ^{
3739 CFErrorRef result = NULL;
3740 __block int bytesPastLastEOL = 0;
3741 __block int max = 0;
3743 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("MAX"), ^(SecTransformAttributeRef ah, CFTypeRef value) {
3744 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &max);
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);
3754 for(int i = 0; i < len; i++) {
3755 if (bytes[i] == '\n') {
3756 bytesPastLastEOL = 0;
3759 if (bytesPastLastEOL > max) {
3760 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "MAX line length of %d exceeded", max));
3766 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
3773 return Block_copy(instanceBlock);
3776 -(void)testLargeChunkEncode
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};
3783 dispatch_group_t dg = dispatch_group_create();
3785 CFStringRef lengthCheckName = CFSTR("com.apple.security.unit-test.lineLengthCheck");
3786 SecTransformRegister(lengthCheckName, LineLengthCheck, (CFErrorRef *)&err);
3787 STAssertNil(err, @"Expected to register %@", lengthCheckName);
3789 for(int i = 0; types[i]; i++) {
3791 CFStringRef etype = types[i];
3793 void (^trial)(NSString *testName, id lineLength, int maxLineLength) = ^(NSString *testName, id lineLength, int maxLineLength) {
3794 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3796 SecTransformRef et = SecEncodeTransformCreate(etype, (CFErrorRef *)&err);
3797 SecTransformRef dt = SecDecodeTransformCreate(etype, (CFErrorRef *)&err);
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);
3803 SecTransformConnectTransforms(et, kSecTransformOutputAttributeName, lineLengthChecker, kSecTransformInputAttributeName, group, (CFErrorRef *)&err);
3804 SecTransformConnectTransforms(lineLengthChecker, kSecTransformOutputAttributeName, dt, kSecTransformInputAttributeName, group, (CFErrorRef *)&err);
3806 SecTransformSetAttribute(et, kSecTransformInputAttributeName, (CFDataRef)d, (CFErrorRef *)&err);
3807 SecTransformSetAttribute(et, kSecEncodeLineLengthAttribute, lineLength, (CFErrorRef *)&err);
3808 SecTransformSetAttribute(et, CFSTR("NAME"), (CFStringRef)testName, (CFErrorRef *)&err);
3810 dispatch_group_async(dg, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
3811 CFDataRef result = (CFDataRef)SecTransformExecute(group, (CFErrorRef *)&err);
3813 STAssertNil(err, @"execute for %@ got %@", testName, err);
3814 STAssertNotNil((id)result, @"No result from execute of %@", testName);
3817 STAssertEqualObjects(d, (id)result, @"test %@ failed", testName);
3822 for(int j = max_j; j > 70; --j) {
3823 if (etype == kSecZLibEncoding && j != max_j) {
3826 trial([NSString stringWithFormat:@"%@-%d", etype, j], [NSNumber numberWithInt:j], j);
3829 if (etype != kSecZLibEncoding) {
3830 trial([NSString stringWithFormat:@"%@-LL64", etype], (id)kSecLineLength64, 64);
3831 trial([NSString stringWithFormat:@"%@-LL76", etype], (id)kSecLineLength76, 76);
3835 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
3839 SecTransformRef et = SecEncodeTransformCreate(kSecZLibEncoding, NULL);
3840 SecTransformRef dt = SecDecodeTransformCreate(kSecZLibEncoding, NULL);
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");
3849 If we want this we need a 'new' custom transform that will get receive the ratio data and be able to
3852 CFNumberRef r1 = (CFNumberRef)SecTransformGetAttribute(et, kSecCompressionRatio);
3853 CFNumberRef r2 = (CFNumberRef)SecTransformGetAttribute(dt, kSecCompressionRatio);
3855 STAssertNotNil((NSNumber *)r1, @"encode ratio");
3856 STAssertNotNil((NSNumber *)r2, @"decode ratio");
3857 STAssertEqualObjects((NSNumber *)r1, (NSNumber *)r2, @"same ratios");
3861 static SecTransformInstanceBlock CycleCheckTest(CFStringRef name,
3862 SecTransformRef newTransform,
3863 SecTransformImplementationRef ref)
3865 SecTransformInstanceBlock instanceBlock =
3867 CFErrorRef result = NULL;
3869 __block CFNumberRef feedback = CFNumberCreate(NULL, kCFNumberIntType, &zero);
3871 SecTransformCustomSetAttribute(ref, CFSTR("FEEDBACK"), kSecTransformMetaAttributeCanCycle, kCFBooleanTrue);
3873 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
3874 ^(SecTransformAttributeRef ah, CFTypeRef value)
3876 if (value == NULL) {
3877 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
3880 if (feedback == NULL) {
3881 SecTransformPushbackAttribute(ref, ah, value);
3882 return (CFTypeRef)NULL;
3886 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &x);
3887 CFNumberGetValue(feedback, kCFNumberIntType, &y);
3889 CFNumberRef res = CFNumberCreate(NULL, kCFNumberIntType, &x);
3890 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, res);
3892 CFRelease(feedback);
3894 return (CFTypeRef)NULL;
3897 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("FEEDBACK"),
3898 ^(SecTransformAttributeRef ah, CFTypeRef value)
3902 SecTransformPushbackAttribute(ref, ah, value);
3904 feedback = (CFNumberRef)CFRetain(value);
3908 return (CFTypeRef)NULL;
3915 return Block_copy(instanceBlock);
3918 -(void)testCycleCheck {
3920 SecTransformRef cat = SecNullTransformCreate();
3921 SecTransformRef group = SecTransformCreateGroupTransform();
3922 CFErrorRef err = NULL;
3924 CFStringRef name = CFSTR("com.apple.examples.unit-test.loop-test");
3926 SecTransformRegister(name, &CycleCheckTest, NULL);
3928 SecTransformRef twenty = count_transform(20);
3930 // this is getting an internal error, but it's being ignored.
3931 SecTransformRef xxor = SecTransformCreate(name, &err);
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");
3940 //SecTransformSetAttribute(xxor, CFSTR("DEBUG"), kCFBooleanTrue, &err);
3942 CFTypeRef r = SecTransformExecute(group, &err);
3943 STAssertNil((id)err, @"execute err=%@", err);
3944 STAssertNotNil((id)r, @"no results from execute");
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);
3960 -(void)testValidate {
3961 SecTransformRef group = SecTransformCreateGroupTransform();
3962 CFErrorRef err = NULL;
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));
3970 SecTransformRef makes_numbers = count_transform(20);
3971 SecTransformRef wants_data = custom_transform(data_or_null_name, data_or_null);
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");
3986 CFRelease(wants_data);
3988 wants_data = custom_transform(data_or_null_name, data_or_null);
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);
3995 STAssertNil((id)err, @"unexpected set error: %@", err);
3996 r = SecTransformExecute(wants_data, &err);
3997 STAssertNotNil((id)r, @"Expected a result, got error: %@", err);
3999 STAssertEqualObjects((id)the_data, (id)r, @"Invalid result");
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));
4008 CFRelease(makes_numbers);
4009 CFRelease(wants_data);
4011 group = SecTransformCreateGroupTransform();
4012 makes_numbers = count_transform(20);
4013 SecTransformRef wants_numbers = custom_transform(numbers_only_name, numbers_only);
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");
4027 CFRelease(makes_numbers);
4028 CFRelease(wants_numbers);
4031 -(void)testCodeBase32 {
4032 struct base32_test_vector {
4033 const char *plain_text;
4034 const char *base32_rfc4648;
4035 const char *base32_fde;
4038 // RFC 4648 test vectors
4039 static base32_test_vector base32_test_vectors[] = {
4041 {"f", "MY======", "MY======"},
4042 {"fo", "MZXQ====", "MZXQ===="},
4043 {"foo", "MZXW6===", "MZXW6==="},
4044 {"foob", "MZXW6YQ=", "MZXW6YQ="},
4045 {"fooba", "MZXW6YTB", "MZXW6YTB"},
4046 {"foobar", "MZXW6YTBOI======", "MZXW6YTBO8======"}};
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)
4052 STFail(@"No transform for %@", test_name);
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);
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);
4072 CFRelease(transform);
4075 for(int idx = 0; idx < sizeof(base32_test_vectors)/sizeof(*base32_test_vectors); idx++)
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$@\"");
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$@\"");
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$@\"");
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$@\"");
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");
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");
4106 CFRelease(FDE_encode_transform);
4107 CFRelease(FDE_decode_transform);
4110 -(void)testCodeBase64 {
4111 CFErrorRef error = NULL;
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);
4120 SecTransformRef dt = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
4121 STAssertNotNil((id)dt, @"Got decoder");
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);
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");
4133 SecTransformRef et = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4134 STAssertNotNil((id)et, @"Got encoder");
4136 SecTransformSetAttribute(et, kSecTransformInputAttributeName, data1, NULL);
4138 CFDataRef encoded_data = (CFDataRef)SecTransformExecute(et, NULL);
4139 STAssertNotNil((NSData *)encoded_data, @"Got an encode result");
4141 STAssertEqualObjects((NSData *)encoded_data, (NSData *)data0, @"Proper encode results");
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 */
4151 SecTransformRef et_neg = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4152 STAssertNotNil((id)et_neg, @"Got encoder for negative testing");
4154 CFIndex *data1_length=(CFIndex*)((unsigned char *)data1 + sizeof(CFRuntimeBase));
4155 CFIndex data1_backup=*data1_length;
4156 if (sizeof(CFIndex)==8)
4158 *data1_length=0x5ffffffffffffff7;
4160 else if (sizeof(CFIndex)==4)
4162 *data1_length=0x5ffffff7;
4166 STAssertTrue(false, @"Test error, representation of CFIndex not supported. Sizeof(CFIndex)=%d. Only support 4 or 8",sizeof(CFIndex));
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;
4176 STAssertTrue((CFErrorGetCode(error)==kSecTransformErrorInvalidLength),
4177 @"Error for invalid length, got %lu expect %lu",CFErrorGetCode(error),kSecTransformErrorInvalidLength);
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.
4181 SecTransformRef dt2 = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
4182 SecTransformRef et2 = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4184 SecTransformSetAttribute(et2, kSecEncodeLineLengthAttribute, CFNumberCreate(NULL, kCFNumberIntType, &ll), NULL);
4186 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", et2, dt2, YES), @"Roundtrip base64 /usr/share/dict/words");
4195 static SecTransformInstanceBlock ErrorResultsTest(CFStringRef name,
4196 SecTransformRef newTransform,
4197 SecTransformImplementationRef ref)
4199 SecTransformInstanceBlock instanceBlock =
4201 CFErrorRef result = NULL;
4202 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
4207 return (CFTypeRef)CFErrorCreate(NULL, CFSTR("expected error"), 42, NULL);
4211 return SecTransformNoData();
4218 return Block_copy(instanceBlock);
4222 -(void)testErrorResults {
4223 CFStringRef name = CFSTR("com.apple.security.unit-test.error-results");
4224 SecTransformRegister(name, &ErrorResultsTest, NULL);
4226 SecTransformRef tr = SecTransformCreate(name, NULL);
4227 CFDataRef data = CFDataCreate(NULL, NULL, 0);
4228 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
4230 CFErrorRef err = NULL;
4231 CFTypeRef no_result = SecTransformExecute(tr, &err);
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");
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).
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;
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);
4257 dispatch_group_leave(got_final);
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)");
4265 CFRelease(unassigned_input);
4266 dispatch_group_notify(got_final, q, ^{
4267 dispatch_release(got_final);
4268 dispatch_release(q);
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;
4286 asprintf(&tmp_dir, "%s/sign-verify-test-keychain-", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
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));
4291 // when safe replace with a concurrent queue
4292 dispatch_queue_t key_q = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4294 dispatch_group_async(dg, key_q,
4296 NSAutoreleasePool *pool = [NSAutoreleasePool new];
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,
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);
4309 dispatch_group_async(dg, key_q,
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,
4319 gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &ecdsa_pub_key, &ecdsa_priv_key);
4322 SecKeychainRef tmp_keychain = NULL;
4323 gp_status = SecKeyCreatePair(tmp_keychain, CSSM_ALGID_ECDSA, 256, NULL,
4325 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT,
4327 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT,
4328 NULL, &ecdsa_pub_key, &ecdsa_priv_key);
4333 STAssertTrue(gp_status == 0, @"ECDSA (gp_status=0x%x)", gp_status);
4337 dispatch_group_async(dg, key_q,
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);
4347 const char *passwd = "this is not secret";
4348 SecKeychainRef tmp_keychain = NULL;
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)
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);
4365 STAssertTrue(gp_status == 0, @"DSA (gp_status=0x%x)", gp_status);
4370 SecKeyRef pub_key, priv_key;
4371 CFDataRef msg_sign, msg_verify;
4372 CFTypeRef dalgo_sign, dalgo_verify;
4373 int dlen_sign, dlen_verify;
4377 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
4379 struct sv_test sv_tests[] =
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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
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},
4443 for(i = 0; i < sizeof(sv_tests)/sizeof(sv_test); i++)
4445 CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest};
4446 //CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest, kSecInputIsRaw};
4447 const int ilim = sizeof(input_cases)/sizeof(input_cases[0]);
4449 for(; ii < ilim; ++ii)
4451 for(ij = 0; ij < ilim; ++ij)
4454 struct sv_test *tst = sv_tests + i;
4455 NSString *tname = [NSString stringWithFormat:@"%@ %@ %@", tst->name, input_cases[ii], input_cases[ij]];
4457 CFStringRef sign_input_is = input_cases[ii];
4458 CFStringRef verify_input_is = input_cases[ij];
4460 if (sign_input_is != kSecInputIsPlainText && tst->dalgo_sign == NULL) {
4463 if (verify_input_is != kSecInputIsPlainText && tst->dalgo_verify == NULL) {
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);
4473 STAssertNotNil((id)tst->pub_key, @"Have pub_key for %@", tname);
4474 STAssertNotNil((id)tst->priv_key, @"Have priv_key for %@", tname);
4476 if (tst->pub_key == nil || tst->priv_key == nil) {
4480 SecTransformRef sign = SecSignTransformCreate(tst->priv_key, &err);
4481 STAssertNil((NSError *)err, @"creating sign for %@", tname);
4482 STAssertNotNil((id)sign, @"Creating sign for %@", tname);
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);
4492 if (verify == NULL) {
4496 SecTransformRef sign_digest = NULL;
4497 SecTransformRef verify_digest = NULL;
4498 SecTransformRef sign2 = NULL;
4500 if (tst->dalgo_sign)
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);
4507 if (sign_input_is == kSecInputIsDigest)
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);
4513 SecTransformSetAttribute(sign, kSecInputIsAttributeName, sign_input_is, &err);
4514 STAssertNil((NSError *)err, @"Setting sign's InputIs (for %@) - err=%@", tname, err);
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);
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);
4529 SecTransformSetAttribute(verify, kSecInputIsAttributeName, verify_input_is, &err);
4530 STAssertNil((NSError *)err, @"Setting verify's InputIs (for %@) - err=%@", tname, err);
4534 SecGroupTransformRef group = SecTransformCreateGroupTransform();
4535 SecTransformSetAttribute(sign_digest ? sign_digest : sign, kSecTransformInputAttributeName, tst->msg_sign, (CFErrorRef *)&err);
4537 STAssertNil((NSError *)err, @"Setting sign's digest's input for %@", tname);
4538 SecTransformConnectTransforms(sign_digest, kSecTransformOutputAttributeName,
4539 sign, kSecTransformInputAttributeName, group, NULL);
4541 STAssertNil((NSError *)err, @"Setting sign's input for %@", tname);
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);
4551 STAssertNil((NSError *)err, @"Setting verify's input for %@", tname);
4554 SecTransformConnectTransforms(sign2 ? sign2 : sign, kSecTransformOutputAttributeName, verify, kSecSignatureAttributeName, group, NULL);
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)
4565 STAssertTrue(message == kCFBooleanTrue, @"Failed to verify proper signature %@; message = %@", tname, message);
4568 STAssertTrue(message == kCFBooleanFalse, @"Failed to detect tampering %@; message = %@", tname, message);
4572 STAssertNil((NSError *)err, @"Executed ok for %@ (err=%@)", tname, error);
4576 dispatch_group_leave(dg);
4588 SecKeyRef pub, priv;
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"},
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;
4603 SecTransformRef sign = SecSignTransformCreate(t->priv, &err);
4604 STAssertNil((id)err, @"%@ test sign create err=%@", t->name, err);
4606 SecTransformRef verify = SecVerifyTransformCreate(t->pub, NULL, &err);
4607 STAssertNil((id)err, @"%@ test verify create err=%@", t->name, err);
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);
4616 dispatch_group_async(dg, dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
4617 CFErrorRef xerr = NULL;
4618 CFTypeRef result = SecTransformExecute(group, &xerr);
4622 STAssertTrue(result == kCFBooleanTrue, @"%@ sign result=%@", t->name, result);
4624 STFail(@"%@ no result", t->name);
4626 STAssertNil((id)err, @"%@ execute error=%@", t->name, xerr);
4631 // Test some things we want to fail for:
4633 SecTransformRef tee = SecNullTransformCreate();
4634 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, message, NULL);
4635 SecTransformRef vrfy = SecVerifyTransformCreate(ecdsa_pub_key, NULL, NULL);
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);
4642 CFTypeRef no_result = SecTransformExecute(group, (CFErrorRef*)&err);
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);
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();
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);
4662 no_result = SecTransformExecute(group, (CFErrorRef*)&err);
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);
4670 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
4673 static BOOL keyWithBytes(CFDataRef keyData, SecKeyRef* key, CFTypeRef keyClass) {
4674 CFErrorRef errorRef=NULL;
4675 CFMutableDictionaryRef parameters;
4676 parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 10, NULL, NULL);
4679 kSecAttrKeyClass values:
4680 kSecAttrKeyClassPublic
4681 kSecAttrKeyClassPrivate
4682 kSecAttrKeyClassSymmetric
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);
4692 -(void)testVerifyWithKeyFromBytes {
4694 static const uint8_t original_pubKeyData[] =
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
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,
4714 static const uint8_t signatureData[] =
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
4722 const char *raw_data = "Data to verify";
4723 CFDataRef data = CFDataCreate(NULL, (UInt8*) raw_data, strlen(raw_data));
4726 CFDataRef cfkeybytes;
4728 cfkeybytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pubKeyData, sizeof(pubKeyData),kCFAllocatorNull);
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);
4739 CFRelease(signature);
4741 CFRelease(cfkeybytes);
4743 NSLog(@"STE result %@, err=%@", signature_ok, error);
4744 STAssertNil((id)error, @"Error from SecTransformExecute: %@", error);
4746 STFail(@"Can't get SecKeyCreateFromData to work");
4750 -(void)testAESAndCastKeysFromBytes {
4751 CFErrorRef err = NULL;
4757 const char *aes_kbytes = "0123456789012345";
4758 const char *cast_kbytes = "01234567";
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)]},
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,
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);
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);
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);
4786 BOOL rt_ok = RoundTrip(CFSTR("/usr/share/dict/propernames"), et, dt, YES);
4789 STAssertTrue(rt_ok, @"%s's round trip", cases[i].name);
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
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;
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);
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");
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.
4819 static 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();
4825 CFErrorRef err = NULL;
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);
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);
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);
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);
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);
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);
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);
4877 SecTransformSetAttribute(g1, kSecTransformInputAttributeName, input_data, &err);
4878 STAssertNil((id)err, @"Can't set g1's input: %@", err);
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));
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);
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);
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);
4920 // It can fail right away
4921 ErrorHas((NSError*)err, @"Unsupported decode type");
4923 // Or later (see below)
4924 STAssertNil((id)err, @"Expected to set decode type: %@", err);
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);
4937 SecTransformConnectTransforms(d64, any, e64, any, bad_outer, &err);
4938 STAssertNotNil((id)err, @"Expected error on cross group connect (in %@)", group_name);
4940 STAssertEquals(CFErrorGetCode(err), (CFIndex)kSecTransformErrorInvalidConnection, @"error code (in %@)", group_name);
4941 STAssertEqualObjects((id)CFErrorGetDomain(err), (id)kSecTransformErrorDomain, @"error domain (in %@)", group_name);
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");
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);
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");
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");
4986 CFRelease(bad_outer);
4987 CFRelease(appendix);
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));
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");
5003 CFDictionaryRef freezeDriedNestedGroups = SecTransformCopyExternalRepresentation(d64);
5004 STAssertNotNil((id)freezeDriedNestedGroups, @"Expected to externalize group");
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));
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");
5016 static NSString *CopyLeakLine()
5018 static char os_build[16];
5019 static dispatch_once_t get_os_build_once;
5020 static BOOL broken_leaks_command = NO;
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);
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
5031 broken_leaks_command = YES;
5035 if (broken_leaks_command) {
5036 return [NSString stringWithFormat:@"Leaks command is broken in %s", os_build];
5039 NSRegularExpression *matchLeaksLine = [NSRegularExpression regularExpressionWithPattern:@"^Process \\d+: \\d+ leaks for \\d+ total leaked bytes.$" options:NSRegularExpressionAnchorsMatchLines error:NULL];
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);
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) {
5051 NSRange matchRange = result.range;
5052 return [output substringWithRange:matchRange];
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());
5062 NSString *current_leaks = NULL;
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]) {
5075 STAssertNotNil(current_leaks, @"Found current leaks");
5076 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks");
5079 -(void)testAAASimpleishLeakTest {
5080 NSLog(@"pid=%d", getpid());
5081 NSString *starting_leaks = CopyLeakLine();
5082 STAssertNotNil(starting_leaks, @"Found initial leaks");
5083 CFErrorRef err = NULL;
5085 // Derived from Matt Wright's 10242560 test.c
5086 SecTransformRef b64encode = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
5087 const int buffer_size = 1024;
5088 void *buffer = malloc(buffer_size);
5089 STAssert(SecRandomCopyBytes(kSecRandomDefault, buffer_size, buffer) == noErr), @"Random failed");
5091 CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, (UInt8*)buffer, buffer_size, kCFAllocatorMalloc);
5092 SecTransformSetAttribute(b64encode, kSecTransformInputAttributeName, data, &err);
5093 STAssertNil((id)err, @"Expected no SecTransformSetAttribute error, got: %@", err);
5095 CFTypeRef output = SecTransformExecute(b64encode, &err);
5096 STAssertNotNil((id)output, @"Expected result");
5097 STAssertNil((id)err, @"Expected no execute error, got: %@", err);
5099 CFRelease(b64encode);
5101 NSString *current_leaks = NULL;
5103 // Some of the destruction is async, so if they don't pan out the same, a little sleep and retry
5104 // can legitimately fix it.
5105 for(int i = 0; i < 10; i++) {
5106 current_leaks = CopyLeakLine();
5107 if ([current_leaks isEqualToString:starting_leaks]) {
5114 STAssertNotNil(current_leaks, @"Found current leaks");
5115 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks");