3 // libsecurity_transform
5 // Created by JOsborne on 2/18/10.
6 // Copyright 2010 Apple. All rights reserved.
10 #import "SecTransform.h"
11 #import "SecCustomTransform.h"
12 #import "SecDigestTransform.h"
13 #import "SecEncryptTransform.h"
14 #import "SecEncodeTransform.h"
15 #import "SecDecodeTransform.h"
16 #import "SecSignVerifyTransform.h"
17 #import "SecNullTransform.h"
18 #import "SecExternalSourceTransform.h"
19 #import <Security/SecItem.h>
22 #import "SecNullTransform.h"
24 #include <dispatch/dispatch.h>
25 #import "SecMaskGenerationFunctionTransform.h"
26 #import "SecTransformInternal.h"
28 #include "SecTransformReadTransform.h"
29 #import "SecTransformValidator.h"
30 #include <sys/types.h>
31 #include <sys/sysctl.h>
36 #include <CommonCrypto/CommonCryptor.h>
38 #import "NSData+HexString.h"
40 // compatibility layer
41 struct SecTransformCreateBlockParameters {
42 CFTypeRef (^send)(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value);
43 CFTypeRef (^get)(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type);
44 CFTypeRef (^pushback)(SecTransformStringOrAttributeRef attribute, CFTypeRef value);
45 CFErrorRef (^overrideTransform)(CFStringRef action, SecTransformActionBlock newAction);
46 CFErrorRef (^overrideAttribute)(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock newAction);
49 typedef void (^SecTransformCreateBlock)(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params);
51 SecTransformCreateBlock global_create_block;
53 static SecTransformInstanceBlock block_for_custom_transform(CFStringRef name, SecTransformRef tr, SecTransformImplementationRef ir)
55 SecTransformInstanceBlock b = ^{
56 // XXX: leak, need to override Finalize and clean up… (and need to handle caller overriding finalize…)
57 SecTransformCreateBlockParameters *params = static_cast<SecTransformCreateBlockParameters *>(malloc(sizeof(SecTransformCreateBlockParameters)));
59 params->overrideAttribute = ^(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock newAction) {
60 // We don't need to special case ProcessData to call SecTransformSetDataAction as there are no longer any uses of it
61 return SecTransformSetAttributeAction(ir, action, attribute, newAction);
64 params->overrideTransform = ^(CFStringRef action, SecTransformActionBlock newAction) {
65 return SecTransformSetTransformAction(ir, action, newAction);
68 params->get = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type) {
69 return SecTranformCustomGetAttribute(ir, attribute, type);
72 params->send = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value) {
73 return SecTransformCustomSetAttribute(ir, attribute, type, value);
76 params->pushback = ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) {
77 return SecTransformPushbackAttribute(ir, attribute, value);
80 params->overrideAttribute = Block_copy(params->overrideAttribute);
81 params->overrideTransform = Block_copy(params->overrideTransform);
82 params->get = Block_copy(params->get);
83 params->send = Block_copy(params->send);
84 params->pushback = Block_copy(params->pushback);
86 global_create_block(name, tr, params);
88 return (CFErrorRef)NULL;
94 // Sort of a bridge from the old Custom SPI to the new API, but is also
95 // useful when you REALLY need to access stack locals as __block variables,
96 // but don't need multithreading, or generic internalizing.
97 SecTransformRef custom_transform(CFStringRef base_name, SecTransformCreateBlock cb)
99 static int ct_cnt = 0;
100 static dispatch_queue_t cnt_q = dispatch_queue_create("com.apple.security.custom_trasnform-cnt", 0);
101 __block CFStringRef name = NULL;
102 __block SecTransformRef ret = NULL;
104 dispatch_sync(cnt_q, ^{
105 CFErrorRef err = NULL;
107 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.%d"), base_name, ct_cnt++);
108 global_create_block = cb;
109 if (SecTransformRegister(name, block_for_custom_transform, &err)) {
110 ret = SecTransformCreate(name, &err);
112 CFfprintf(stderr, "Error %@ creating %@\n", err, base_name);
116 CFfprintf(stderr, "Error %@ registering %@\n", err, base_name);
119 global_create_block = NULL;
127 #define STAssertErrorHas(err, rx, msg...) STAssertTrue(ErrorHas(err, rx), ##msg);
129 BOOL ErrorHas(NSError *error, NSString *rx) {
133 if (![error isKindOfClass:[NSError class]]) {
137 NSString *es = [error description];
141 return [es rangeOfString:rx options:NSRegularExpressionSearch].location != NSNotFound;
145 static SecTransformInstanceBlock DelayTransformBlock(CFStringRef name,
146 SecTransformRef newTransform,
147 SecTransformImplementationRef ref)
149 SecTransformInstanceBlock instanceBlock =
151 CFErrorRef result = NULL;
154 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
158 if (NULL != value && CFNumberGetTypeID() == CFGetTypeID(value))
161 CFNumberGetValue((CFNumberRef)value, kCFNumberLongLongType, &n);
162 usleep(n / NSEC_PER_USEC);
170 return Block_copy(instanceBlock);
173 SecTransformRef delay_transform(long long nsec) {
174 CFStringRef name = CFSTR("com.apple.security.unit-test.delay");
178 static dispatch_once_t once;
179 __block Boolean ok = TRUE;
181 dispatch_block_t aBlock = ^
183 ok = SecTransformRegister(name, &DelayTransformBlock, NULL);
186 dispatch_once(&once, aBlock);
193 SecTransformRef ct = SecTransformCreate(name, NULL);
194 CFNumberRef nr = CFNumberCreate(NULL, kCFNumberLongLongType, &nsec);
195 SecTransformSetAttribute(ct, CFSTR("DELAY"), nr, NULL);
201 @implementation custom
208 size_t mStringLength;
211 char *mCurrentString;
214 BufferStream(const char* buffer, size_t length) : mBuffer(buffer), mLength(length), mStringLength(0), mPos(0), mCurrentString(NULL) {}
217 const char* GetNextString();
218 void SplitString(const char*& stringA, const char*& stringB);
223 BufferStream::~BufferStream()
225 if (NULL != mCurrentString)
227 free(mCurrentString);
233 const char* BufferStream::GetNextString()
241 // run to either the end of the buffer or a return
242 while (p < mLength && mBuffer[p] != '\n')
249 // handle the end of the buffer specially, since it doesn't point
254 // p now points to the last character in the string
255 // allocate memory for our buffer
256 mStringLength = p - mPos + 1;
257 mCurrentString = (char*) realloc(mCurrentString, mStringLength + 1);
258 memmove(mCurrentString, mBuffer + mPos, mStringLength);
259 mCurrentString[mStringLength] = 0;
262 return mCurrentString;
267 void BufferStream::SplitString(const char*& a, const char*& b)
269 // scan the buffer, looking for a ':'
271 while (mCurrentString[p] != 0 && mCurrentString[p] != ':')
276 // the first string is always our buffer pointer
279 if (mCurrentString[p] == ':')
281 mCurrentString[p] = 0;
283 // look for the beginning of the next string
285 while (p < mLength && isspace(mCurrentString[p]))
290 b = mCurrentString + p;
300 -(void)disabledtestzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
302 // open leaks and make a connection to it.
305 const int kChunkSize = 16384;
306 char buffer[kChunkSize];
307 pid_t thePid = getpid();
308 asprintf(&name, "/tmp/leaks%d.txt", thePid);
309 sprintf(buffer, "/usr/bin/leaks %d >%s", thePid, name);
315 char* rBuffer = (char*) malloc(st.st_size);
316 FILE* f = fopen(name, "r");
317 fread(rBuffer, 1, st.st_size, f);
320 // set up our output parser
321 BufferStream bStream(rBuffer, st.st_size);
322 const char* s = bStream.GetNextString();
324 bool didError = true;
328 // we have our string, split it and see what it means
332 bStream.SplitString(key, value);
333 if (strcmp(key, "leaks Report Version") != 0 || strcmp(value, "2.0") != 0)
348 // figure out what our target line will look like
350 asprintf(&target, "Process %d", thePid);
352 const char* nextString = bStream.GetNextString();
355 bStream.SplitString(key, value);
356 if (strcmp(key, target) == 0) // we found our target!!!
359 bStream.GetNextString();
360 bStream.SplitString(key, value);
362 if (value[0] != '0') // we have a non-zero result... :(
368 nextString = bStream.GetNextString();
374 STAssertFalse(didError, @"You have leaks!");
378 // dump to our output file
379 // make a file name for the leaks output
380 FILE* f = fopen(name, "w");
381 fwrite(rBuffer, 1, st.st_size, f);
394 static const char* gHMACText = "The judicial Power shall extend to all Cases, in "
395 "Law and Equity, arising under this Constitution, "
396 "the Laws of the United States, and Treaties made, "
397 "or which shall be made, under their Authority;--to "
398 "all Cases affecting Ambassadors, other public "
399 "Ministers and Consuls;--to all Cases of admiralty "
400 "and maritime Jurisdiction;--to Controversies to "
401 "which the United States shall be a Party;--to "
402 "Controversies between two or more States;-- "
403 "between a State and Citizens of another State, "
404 "--between Citizens of different States,-- "
405 "between Citizens of the same State claiming Lands "
406 "under Grants of different States, and between a "
407 "State, or the Citizens thereof, and foreign "
408 "States, Citizens or Subjects";
410 const NSString* gAbortTransformName = (NSString*) kSecTransformAbortAttributeName;
412 static const char* gHMACKey = "No person shall be held to answer for a capital, or "
413 "otherwise infamous crime, unless on a presentment "
414 "or indictment of a Grand Jury, except in cases "
415 "arising in the land or naval forces, or in the "
416 "Militia, when in actual service in time of War or "
417 "public danger; nor shall any person be subject for "
418 "the same offence to be twice put in jeopardy of life "
419 "or limb; nor shall be compelled in any criminal case "
420 "to be a witness against himself, nor be deprived of "
421 "life, liberty, or property, without due process of "
422 "law; nor shall private property be taken for public "
423 "use, without just compensation.";
425 static const u_int8_t gSHA1HMAC[] = {0x2f, 0x68, 0x4b, 0x6b, 0x4f,
426 0xf7, 0x41, 0xc3, 0x76, 0x3d,
427 0x0b, 0xc3, 0x25, 0x02, 0x99,
428 0x03, 0xfa, 0xa5, 0xe9, 0xde};
430 static const u_int8_t gSHA256HMAC[] = {0xc2, 0x5c, 0x9a, 0x65, 0x08, 0x9e, 0x61, 0xb5,
431 0x03, 0xfe, 0xcb, 0x57, 0xb7, 0x55, 0x4f, 0x69,
432 0xdb, 0xef, 0xdb, 0xe7, 0x0d, 0xe2, 0x78, 0x2e,
433 0xf9, 0x48, 0xbd, 0xf6, 0x4f, 0x4b, 0x94, 0x0c};
436 CFStringRef paddings[] = {kSecPaddingNoneKey, kSecPaddingPKCS7Key, kSecPaddingPKCS5Key, kSecPaddingPKCS1Key};
438 for(int i = 0; i < sizeof(paddings) / sizeof(*paddings); i++) {
439 CFErrorRef error = NULL;
440 SecKeyRef cryptokey = NULL;
441 SecTransformRef encrypt = NULL, decrypt = NULL;
442 CFDataRef cfdatacryptokey = NULL, sourceData = NULL, encryptedData = NULL, decryptedData = NULL;
443 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.
444 const char *sourceCString = "All these worlds are yours except Europa."; // I'm not so sure about that Earth one either
446 CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
447 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
448 &kCFTypeDictionaryValueCallBacks);
450 CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
452 cfdatacryptokey = CFDataCreate(kCFAllocatorDefault, rawcryptokey,
453 sizeof(rawcryptokey));
454 cryptokey = SecKeyCreateFromData(parameters,
455 cfdatacryptokey, &error);
456 STAssertNil((id)error, @"Unexpected SecKeyCreateFromData error: %@", error);
458 size_t len = strlen(sourceCString) +1;
459 if (paddings[i] == kSecPaddingNoneKey) {
460 STAssertTrue(len >= kCCBlockSizeAES128, @"Had at least one block");
461 // Get to an AES block multiple, discarding bytes wildly.
462 len -= len % kCCBlockSizeAES128;
464 sourceData = (CFDataRef)[NSData dataWithBytes:sourceCString length:len];
466 encrypt = SecEncryptTransformCreate(cryptokey, &error);
467 STAssertNil((id)error, @"Unexpected error creating encrypt transform: %@", error);
468 decrypt = SecDecryptTransformCreate(cryptokey, &error);
469 STAssertNil((id)error, @"Unexpected error creating decrypt transform: %@", error);
471 /* Set the padding on the transforms */
472 SecTransformSetAttribute(encrypt, kSecPaddingKey, paddings[i], &error);
473 STAssertNil((id)error, @"Couldn't set encrypt padding to %@: %@", paddings[i], error);
474 SecTransformSetAttribute(decrypt, kSecPaddingKey, paddings[i], &error);
475 STAssertNil((id)error, @"Couldn't set decrypt padding to %@: %@", paddings[i], error);
477 SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName, sourceData, &error);
478 STAssertNil((id)error, @"Couldn't set encrypt transform input: %@", error);
480 encryptedData = (CFDataRef)SecTransformExecute(encrypt, &error);
481 STAssertNil((id)error, @"Couldn't execute encrypt: %@ (padding %@)", paddings[i], error);
482 STAssertNotNil((id)encryptedData, @"Didn't get encrypted data");
484 SecTransformSetAttribute(decrypt, kSecTransformInputAttributeName, encryptedData, &error);
485 STAssertNil((id)error, @"Couldn't set decrypt transform input: %@", error);
487 decryptedData = (CFDataRef)SecTransformExecute(decrypt, &error);
488 STAssertNil((id)error, @"Couldn't execute decrypt: %@", error);
489 STAssertNotNil((id)decryptedData, @"Didn't get decrypt data");
491 STAssertEqualObjects((id)decryptedData, (id)sourceData, @"Decrypt output didn't match encrypt input for padding %@", paddings[i]);
495 static SecTransformInstanceBlock nopInstance(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref)
497 SecTransformInstanceBlock instanceBlock = ^{
498 return (CFErrorRef)NULL;
501 return Block_copy(instanceBlock);
505 -(void)test_manyregister
507 dispatch_apply(4000, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(size_t i) {
508 NSString *name = [NSString stringWithFormat:@"many%dregister", i];
509 CFErrorRef err = NULL;
510 BOOL ok = SecTransformRegister((CFStringRef)name, nopInstance, &err);
511 STAssertTrue(ok, @"register not ok");
512 STAssertNil((id)err, @"register error: %@", err);
516 -(void)test_emptyOAEP
518 SecKeychainRef tmp_keychain = NULL;
520 asprintf(&kcfname, "%s-OAEP-XXXXXXXXXX", "/tmp/");
521 const char *passwd = "sekret";
522 // NOTE: "mktemp" isn't as safe as you might think...but this is test code and doesn't have to be, but
523 // if you copy it elsewhere you may well need to rewrite it. (use mkstemp)
525 OSStatus status = SecKeychainCreate(kcfname, strlen(passwd), passwd, NO, NULL, &tmp_keychain);
526 STAssertTrue(status == 0, @"Expected to make keychain, but got error 0x%x", status);
528 const char *pem_key_bytes[] = {
530 "-----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",
534 SecKeyRef pubKey, privKey;
539 for(i = 0; i < sizeof(keys)/sizeof(key_pair); i++) {
540 NSAssert(pem_key_bytes[i] != NULL, @"Expected a key");
541 NSLog(@"Importing: %s", pem_key_bytes[i]);
542 CFDataRef pem_data = CFDataCreate(NULL, (UInt8*)(pem_key_bytes[i]), strlen(pem_key_bytes[i]));
543 SecKeyImportExportParameters import_params;
544 bzero(&import_params, sizeof(import_params));
546 import_params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
547 import_params.keyUsage = CSSM_KEYUSE_ANY;
548 import_params.keyAttributes = CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_SENSITIVE;
549 import_params.accessRef = NULL;
550 import_params.passphrase = CFSTR("");
551 import_params.alertPrompt = CFSTR("");
553 CFArrayRef keypair = NULL;
554 SecExternalFormat key_format = kSecFormatOpenSSL;
555 SecExternalItemType itemType = kSecItemTypeUnknown;
556 status = SecKeychainItemImport(pem_data, CFSTR(".pem"), &key_format, &itemType, 0, &import_params, tmp_keychain, &keypair);
557 STAssertTrue(status == 0, @"Expected pubkey import to be ok, got err=0x%x", status);
558 NSAssert(keypair != NULL, @"Expected to get some keys back");
559 STAssertNotNil((id)keypair, @"Expected to get some keys back");
560 STAssertTrue(CFArrayGetCount(keypair) == 2, @"Expected 2 keys, got %@", keypair);
561 keys[i].pubKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 0);
562 keys[i].privKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 1);
564 STAssertNil((id)pem_key_bytes[i], @"Expected to convert all pem keys, but found at least: %s", pem_key_bytes[i]);
565 CFDataRef encoding_parameters = CFDataCreate(NULL, NULL, 0);
568 CFErrorRef err = NULL;
570 SecTransformRef encryptor = SecEncryptTransformCreate(keys[0].pubKey, &err);
572 CFReadStreamRef empty_stream = CFReadStreamCreateWithBytesNoCopy(NULL, (UInt8*)"", 0, kCFAllocatorNull);
573 SecTransformSetAttribute(encryptor, kSecTransformInputAttributeName, empty_stream, &err);
574 SecTransformSetAttribute(encryptor, kSecPaddingKey, kSecPaddingOAEPKey, &err);
575 SecTransformSetAttribute(encryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, &err);
577 CFTypeRef encryptedData = SecTransformExecute(encryptor, &err);
578 STAssertNotNil((id)encryptedData, @"Expected to get encrypted data");
579 STAssertNil((NSError*)err, @"Expected no error, got err=%@", err);
580 // Can't support "seed" with commoncrypto, just check round trip.
581 //STAssertEqualObjects((id)encryptedData, (id)tests[i].encryptedMessage, @"encrypted data should have matched test vector (%@) data", tests[i].label);
582 CFRelease(encryptor);
584 SecTransformRef decryptor = SecDecryptTransformCreate(keys[0].privKey, NULL);
585 // XXX: totally round trip, not even partial KAT (KAT can't really be done on OAEP
586 // without supporitng settign the seed externally)
587 SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, encryptedData, NULL);
588 SecTransformSetAttribute(decryptor, kSecPaddingKey, kSecPaddingOAEPKey, NULL);
589 SecTransformSetAttribute(decryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, NULL);
590 CFTypeRef decryptedData = SecTransformExecute(decryptor, &err);
591 STAssertNil((id)err, @"Expected no error, got: %@", err);
592 STAssertNotNil((id)decryptedData, @"Expected to get decrypted data");
593 // What do we expect an empty enc/dec to look like? Mostly "not a crash"
594 CFDataRef empty_data = CFDataCreate(NULL, (UInt8*)"", 0);
595 STAssertEqualObjects((id)decryptedData, (id)empty_data, @"Expected decrypted data to match original message");
596 CFRelease(decryptor);
604 // Give xcode a little time to parse all the output before the unit tests exit
608 -(void)test_multiOAEP
610 SecKeychainRef tmp_keychain = NULL;
612 asprintf(&kcfname, "%s-OAEP-XXXXXXXXXX", "/tmp/");
613 const char *passwd = "sekret";
614 // NOTE: "mktemp" isn't as safe as you might think...but this is test code and doesn't have to be, but
615 // if you copy it elsewhere you may well need to rewrite it. (use mkstemp)
617 OSStatus status = SecKeychainCreate(kcfname, strlen(passwd), passwd, NO, NULL, &tmp_keychain);
618 STAssertTrue(status == 0, @"Expected to make keychain, but got error 0x%x", status);
620 const char *pem_key_bytes[] = {
622 "-----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",
623 // The next 10 are from oaep-vect.txt (via a lot of OpenSSL higgerdy-jiggerdey)
624 "-----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",
625 "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",
626 "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",
627 "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",
628 "-----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",
629 "-----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",
630 "-----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",
631 "-----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",
632 "-----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",
633 "-----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",
637 SecKeyRef pubKey, privKey;
642 for(i = 0; i < sizeof(keys)/sizeof(key_pair); i++) {
643 NSAssert(pem_key_bytes[i] != NULL, @"Expected a key");
644 NSLog(@"Importing: %s", pem_key_bytes[i]);
645 CFDataRef pem_data = CFDataCreate(NULL, (UInt8*)(pem_key_bytes[i]), strlen(pem_key_bytes[i]));
646 SecKeyImportExportParameters import_params;
647 bzero(&import_params, sizeof(import_params));
649 import_params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
650 import_params.keyUsage = CSSM_KEYUSE_ANY;
651 import_params.keyAttributes = CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_SENSITIVE;
652 import_params.accessRef = NULL;
653 import_params.passphrase = CFSTR("");
654 import_params.alertPrompt = CFSTR("");
656 CFArrayRef keypair = NULL;
657 SecExternalFormat key_format = kSecFormatOpenSSL;
658 SecExternalItemType itemType = kSecItemTypeUnknown;
659 status = SecKeychainItemImport(pem_data, CFSTR(".pem"), &key_format, &itemType, 0, &import_params, tmp_keychain, &keypair);
660 STAssertTrue(status == 0, @"Expected pubkey import to be ok, got err=0x%x", status);
661 NSAssert(keypair != NULL, @"Expected to get some keys back");
662 STAssertNotNil((id)keypair, @"Expected to get some keys back");
663 STAssertTrue(CFArrayGetCount(keypair) == 2, @"Expected 2 keys, got %@", keypair);
664 keys[i].pubKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 0);
665 keys[i].privKey = (SecKeyRef)CFArrayGetValueAtIndex(keypair, 1);
667 STAssertNil((id)pem_key_bytes[i], @"Expected to convert all pem keys, but found at least: %s", pem_key_bytes[i]);
668 CFDataRef encoding_parameters = CFDataCreate(NULL, NULL, 0);
671 NSData *message, *seed, *encryptedMessage;
676 // This first one is from the spec
678 .message = [NSData dataWithHexString:@"d436e99569fd32a7c8a05bbc90d32c49"],
679 .seed = [NSData dataWithHexString:@"aafd12f659cae63489b479e5076ddec2f06cb58f"],
680 .encryptedMessage = [NSData dataWithHexString:@"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955"],
682 .label = @"From spec",
684 // The next 60 are from oaep-vect.txt
686 .message = [NSData dataWithHexString:@"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"],
687 .seed = [NSData dataWithHexString:@"18b776ea21069d69776a33e96bad48e1dda0a5ef"],
688 .encryptedMessage = [NSData dataWithHexString:@"354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"],
693 .message = [NSData dataWithHexString:@"750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"],
694 .seed = [NSData dataWithHexString:@"0cc742ce4a9b7f32f951bcb251efd925fe4fe35f"],
695 .encryptedMessage = [NSData dataWithHexString:@"640db1acc58e0568fe5407e5f9b701dff8c3c91e716c536fc7fcec6cb5b71c1165988d4a279e1577d730fc7a29932e3f00c81515236d8d8e31017a7a09df4352d904cdeb79aa583adcc31ea698a4c05283daba9089be5491f67c1a4ee48dc74bbbe6643aef846679b4cb395a352d5ed115912df696ffe0702932946d71492b44"],
700 .message = [NSData dataWithHexString:@"d94ae0832e6445ce42331cb06d531a82b1db4baad30f746dc916df24d4e3c2451fff59a6423eb0e1d02d4fe646cf699dfd818c6e97b051"],
701 .seed = [NSData dataWithHexString:@"2514df4695755a67b288eaf4905c36eec66fd2fd"],
702 .encryptedMessage = [NSData dataWithHexString:@"423736ed035f6026af276c35c0b3741b365e5f76ca091b4e8c29e2f0befee603595aa8322d602d2e625e95eb81b2f1c9724e822eca76db8618cf09c5343503a4360835b5903bc637e3879fb05e0ef32685d5aec5067cd7cc96fe4b2670b6eac3066b1fcf5686b68589aafb7d629b02d8f8625ca3833624d4800fb081b1cf94eb"],
707 .message = [NSData dataWithHexString:@"52e650d98e7f2a048b4f86852153b97e01dd316f346a19f67a85"],
708 .seed = [NSData dataWithHexString:@"c4435a3e1a18a68b6820436290a37cefb85db3fb"],
709 .encryptedMessage = [NSData dataWithHexString:@"45ead4ca551e662c9800f1aca8283b0525e6abae30be4b4aba762fa40fd3d38e22abefc69794f6ebbbc05ddbb11216247d2f412fd0fba87c6e3acd888813646fd0e48e785204f9c3f73d6d8239562722dddd8771fec48b83a31ee6f592c4cfd4bc88174f3b13a112aae3b9f7b80e0fc6f7255ba880dc7d8021e22ad6a85f0755"],
714 .message = [NSData dataWithHexString:@"8da89fd9e5f974a29feffb462b49180f6cf9e802"],
715 .seed = [NSData dataWithHexString:@"b318c42df3be0f83fea823f5a7b47ed5e425a3b5"],
716 .encryptedMessage = [NSData dataWithHexString:@"36f6e34d94a8d34daacba33a2139d00ad85a9345a86051e73071620056b920e219005855a213a0f23897cdcd731b45257c777fe908202befdd0b58386b1244ea0cf539a05d5d10329da44e13030fd760dcd644cfef2094d1910d3f433e1c7c6dd18bc1f2df7f643d662fb9dd37ead9059190f4fa66ca39e869c4eb449cbdc439"],
721 .message = [NSData dataWithHexString:@"26521050844271"],
722 .seed = [NSData dataWithHexString:@"e4ec0982c2336f3a677f6a356174eb0ce887abc2"],
723 .encryptedMessage = [NSData dataWithHexString:@"42cee2617b1ecea4db3f4829386fbd61dafbf038e180d837c96366df24c097b4ab0fac6bdf590d821c9f10642e681ad05b8d78b378c0f46ce2fad63f74e0ad3df06b075d7eb5f5636f8d403b9059ca761b5c62bb52aa45002ea70baace08ded243b9d8cbd62a68ade265832b56564e43a6fa42ed199a099769742df1539e8255"],
729 .message = [NSData dataWithHexString:@"8ff00caa605c702830634d9a6c3d42c652b58cf1d92fec570beee7"],
730 .seed = [NSData dataWithHexString:@"8c407b5ec2899e5099c53e8ce793bf94e71b1782"],
731 .encryptedMessage = [NSData dataWithHexString:@"0181af8922b9fcb4d79d92ebe19815992fc0c1439d8bcd491398a0f4ad3a329a5bd9385560db532683c8b7da04e4b12aed6aacdf471c34c9cda891addcc2df3456653aa6382e9ae59b54455257eb099d562bbe10453f2b6d13c59c02e10f1f8abb5da0d0570932dacf2d0901db729d0fefcc054e70968ea540c81b04bcaefe720e"],
736 .message = [NSData dataWithHexString:@"2d"],
737 .seed = [NSData dataWithHexString:@"b600cf3c2e506d7f16778c910d3a8b003eee61d5"],
738 .encryptedMessage = [NSData dataWithHexString:@"018759ff1df63b2792410562314416a8aeaf2ac634b46f940ab82d64dbf165eee33011da749d4bab6e2fcd18129c9e49277d8453112b429a222a8471b070993998e758861c4d3f6d749d91c4290d332c7a4ab3f7ea35ff3a07d497c955ff0ffc95006b62c6d296810d9bfab024196c7934012c2df978ef299aba239940cba10245"],
743 .message = [NSData dataWithHexString:@"74fc88c51bc90f77af9d5e9a4a70133d4b4e0b34da3c37c7ef8e"],
744 .seed = [NSData dataWithHexString:@"a73768aeeaa91f9d8c1ed6f9d2b63467f07ccae3"],
745 .encryptedMessage = [NSData dataWithHexString:@"018802bab04c60325e81c4962311f2be7c2adce93041a00719c88f957575f2c79f1b7bc8ced115c706b311c08a2d986ca3b6a9336b147c29c6f229409ddec651bd1fdd5a0b7f610c9937fdb4a3a762364b8b3206b4ea485fd098d08f63d4aa8bb2697d027b750c32d7f74eaf5180d2e9b66b17cb2fa55523bc280da10d14be2053"],
750 .message = [NSData dataWithHexString:@"a7eb2a5036931d27d4e891326d99692ffadda9bf7efd3e34e622c4adc085f721dfe885072c78a203b151739be540fa8c153a10f00a"],
751 .seed = [NSData dataWithHexString:@"9a7b3b0e708bd96f8190ecab4fb9b2b3805a8156"],
752 .encryptedMessage = [NSData dataWithHexString:@"00a4578cbc176318a638fba7d01df15746af44d4f6cd96d7e7c495cbf425b09c649d32bf886da48fbaf989a2117187cafb1fb580317690e3ccd446920b7af82b31db5804d87d01514acbfa9156e782f867f6bed9449e0e9a2c09bcecc6aa087636965e34b3ec766f2fe2e43018a2fddeb140616a0e9d82e5331024ee0652fc7641"],
757 .message = [NSData dataWithHexString:@"2ef2b066f854c33f3bdcbb5994a435e73d6c6c"],
758 .seed = [NSData dataWithHexString:@"eb3cebbc4adc16bb48e88c8aec0e34af7f427fd3"],
759 .encryptedMessage = [NSData dataWithHexString:@"00ebc5f5fda77cfdad3c83641a9025e77d72d8a6fb33a810f5950f8d74c73e8d931e8634d86ab1246256ae07b6005b71b7f2fb98351218331ce69b8ffbdc9da08bbc9c704f876deb9df9fc2ec065cad87f9090b07acc17aa7f997b27aca48806e897f771d95141fe4526d8a5301b678627efab707fd40fbebd6e792a25613e7aec"],
764 .message = [NSData dataWithHexString:@"8a7fb344c8b6cb2cf2ef1f643f9a3218f6e19bba89c0"],
765 .seed = [NSData dataWithHexString:@"4c45cf4d57c98e3d6d2095adc51c489eb50dff84"],
766 .encryptedMessage = [NSData dataWithHexString:@"010839ec20c27b9052e55befb9b77e6fc26e9075d7a54378c646abdf51e445bd5715de81789f56f1803d9170764a9e93cb78798694023ee7393ce04bc5d8f8c5a52c171d43837e3aca62f609eb0aa5ffb0960ef04198dd754f57f7fbe6abf765cf118b4ca443b23b5aab266f952326ac4581100644325f8b721acd5d04ff14ef3a"],
772 .message = [NSData dataWithHexString:@"087820b569e8fa8d"],
773 .seed = [NSData dataWithHexString:@"8ced6b196290805790e909074015e6a20b0c4894"],
774 .encryptedMessage = [NSData dataWithHexString:@"026a0485d96aebd96b4382085099b962e6a2bdec3d90c8db625e14372de85e2d5b7baab65c8faf91bb5504fb495afce5c988b3f6a52e20e1d6cbd3566c5cd1f2b8318bb542cc0ea25c4aab9932afa20760eaddec784396a07ea0ef24d4e6f4d37e5052a7a31e146aa480a111bbe926401307e00f410033842b6d82fe5ce4dfae80"],
779 .message = [NSData dataWithHexString:@"4653acaf171960b01f52a7be63a3ab21dc368ec43b50d82ec3781e04"],
780 .seed = [NSData dataWithHexString:@"b4291d6567550848cc156967c809baab6ca507f0"],
781 .encryptedMessage = [NSData dataWithHexString:@"024db89c7802989be0783847863084941bf209d761987e38f97cb5f6f1bc88da72a50b73ebaf11c879c4f95df37b850b8f65d7622e25b1b889e80fe80baca2069d6e0e1d829953fc459069de98ea9798b451e557e99abf8fe3d9ccf9096ebbf3e5255d3b4e1c6d2ecadf067a359eea86405acd47d5e165517ccafd47d6dbee4bf5"],
786 .message = [NSData dataWithHexString:@"d94cd0e08fa404ed89"],
787 .seed = [NSData dataWithHexString:@"ce8928f6059558254008badd9794fadcd2fd1f65"],
788 .encryptedMessage = [NSData dataWithHexString:@"0239bce681032441528877d6d1c8bb28aa3bc97f1df584563618995797683844ca86664732f4bed7a0aab083aaabfb7238f582e30958c2024e44e57043b97950fd543da977c90cdde5337d618442f99e60d7783ab59ce6dd9d69c47ad1e962bec22d05895cff8d3f64ed5261d92b2678510393484990ba3f7f06818ae6ffce8a3a"],
793 .message = [NSData dataWithHexString:@"6cc641b6b61e6f963974dad23a9013284ef1"],
794 .seed = [NSData dataWithHexString:@"6e2979f52d6814a57d83b090054888f119a5b9a3"],
795 .encryptedMessage = [NSData dataWithHexString:@"02994c62afd76f498ba1fd2cf642857fca81f4373cb08f1cbaee6f025c3b512b42c3e8779113476648039dbe0493f9246292fac28950600e7c0f32edf9c81b9dec45c3bde0cc8d8847590169907b7dc5991ceb29bb0714d613d96df0f12ec5d8d3507c8ee7ae78dd83f216fa61de100363aca48a7e914ae9f42ddfbe943b09d9a0"],
800 .message = [NSData dataWithHexString:@"df5151832b61f4f25891fb4172f328d2eddf8371ffcfdbe997939295f30eca6918017cfda1153bf7a6af87593223"],
801 .seed = [NSData dataWithHexString:@"2d760bfe38c59de34cdc8b8c78a38e66284a2d27"],
802 .encryptedMessage = [NSData dataWithHexString:@"0162042ff6969592a6167031811a239834ce638abf54fec8b99478122afe2ee67f8c5b18b0339805bfdbc5a4e6720b37c59cfba942464c597ff532a119821545fd2e59b114e61daf71820529f5029cf524954327c34ec5e6f5ba7efcc4de943ab8ad4ed787b1454329f70db798a3a8f4d92f8274e2b2948ade627ce8ee33e43c60"],
807 .message = [NSData dataWithHexString:@"3c3bad893c544a6d520ab022319188c8d504b7a788b850903b85972eaa18552e1134a7ad6098826254ff7ab672b3d8eb3158fac6d4cbaef1"],
808 .seed = [NSData dataWithHexString:@"f174779c5fd3cfe007badcb7a36c9b55bfcfbf0e"],
809 .encryptedMessage = [NSData dataWithHexString:@"00112051e75d064943bc4478075e43482fd59cee0679de6893eec3a943daa490b9691c93dfc0464b6623b9f3dbd3e70083264f034b374f74164e1a00763725e574744ba0b9db83434f31df96f6e2a26f6d8eba348bd4686c2238ac07c37aac3785d1c7eea2f819fd91491798ed8e9cef5e43b781b0e0276e37c43ff9492d005730"],
815 .message = [NSData dataWithHexString:@"4a86609534ee434a6cbca3f7e962e76d455e3264c19f605f6e5ff6137c65c56d7fb344cd52bc93374f3d166c9f0c6f9c506bad19330972d2"],
816 .seed = [NSData dataWithHexString:@"1cac19ce993def55f98203f6852896c95ccca1f3"],
817 .encryptedMessage = [NSData dataWithHexString:@"04cce19614845e094152a3fe18e54e3330c44e5efbc64ae16886cb1869014cc5781b1f8f9e045384d0112a135ca0d12e9c88a8e4063416deaae3844f60d6e96fe155145f4525b9a34431ca3766180f70e15a5e5d8e8b1a516ff870609f13f896935ced188279a58ed13d07114277d75c6568607e0ab092fd803a223e4a8ee0b1a8"],
822 .message = [NSData dataWithHexString:@"b0adc4f3fe11da59ce992773d9059943c03046497ee9d9f9a06df1166db46d98f58d27ec074c02eee6cbe2449c8b9fc5080c5c3f4433092512ec46aa793743c8"],
823 .seed = [NSData dataWithHexString:@"f545d5897585e3db71aa0cb8da76c51d032ae963"],
824 .encryptedMessage = [NSData dataWithHexString:@"0097b698c6165645b303486fbf5a2a4479c0ee85889b541a6f0b858d6b6597b13b854eb4f839af03399a80d79bda6578c841f90d645715b280d37143992dd186c80b949b775cae97370e4ec97443136c6da484e970ffdb1323a20847821d3b18381de13bb49aaea66530c4a4b8271f3eae172cd366e07e6636f1019d2a28aed15e"],
829 .message = [NSData dataWithHexString:@"bf6d42e701707b1d0206b0c8b45a1c72641ff12889219a82bdea965b5e79a96b0d0163ed9d578ec9ada20f2fbcf1ea3c4089d83419ba81b0c60f3606da99"],
830 .seed = [NSData dataWithHexString:@"ad997feef730d6ea7be60d0dc52e72eacbfdd275"],
831 .encryptedMessage = [NSData dataWithHexString:@"0301f935e9c47abcb48acbbe09895d9f5971af14839da4ff95417ee453d1fd77319072bb7297e1b55d7561cd9d1bb24c1a9a37c619864308242804879d86ebd001dce5183975e1506989b70e5a83434154d5cbfd6a24787e60eb0c658d2ac193302d1192c6e622d4a12ad4b53923bca246df31c6395e37702c6a78ae081fb9d065"],
836 .message = [NSData dataWithHexString:@"fb2ef112f5e766eb94019297934794f7be2f6fc1c58e"],
837 .seed = [NSData dataWithHexString:@"136454df5730f73c807a7e40d8c1a312ac5b9dd3"],
838 .encryptedMessage = [NSData dataWithHexString:@"02d110ad30afb727beb691dd0cf17d0af1a1e7fa0cc040ec1a4ba26a42c59d0a796a2e22c8f357ccc98b6519aceb682e945e62cb734614a529407cd452bee3e44fece8423cc19e55548b8b994b849c7ecde4933e76037e1d0ce44275b08710c68e430130b929730ed77e09b015642c5593f04e4ffb9410798102a8e96ffdfe11e4"],
843 .message = [NSData dataWithHexString:@"28ccd447bb9e85166dabb9e5b7d1adadc4b9d39f204e96d5e440ce9ad928bc1c2284"],
844 .seed = [NSData dataWithHexString:@"bca8057f824b2ea257f2861407eef63d33208681"],
845 .encryptedMessage = [NSData dataWithHexString:@"00dbb8a7439d90efd919a377c54fae8fe11ec58c3b858362e23ad1b8a44310799066b99347aa525691d2adc58d9b06e34f288c170390c5f0e11c0aa3645959f18ee79e8f2be8d7ac5c23d061f18dd74b8c5f2a58fcb5eb0c54f99f01a83247568292536583340948d7a8c97c4acd1e98d1e29dc320e97a260532a8aa7a758a1ec2"],
850 .message = [NSData dataWithHexString:@"f22242751ec6b1"],
851 .seed = [NSData dataWithHexString:@"2e7e1e17f647b5ddd033e15472f90f6812f3ac4e"],
852 .encryptedMessage = [NSData dataWithHexString:@"00a5ffa4768c8bbecaee2db77e8f2eec99595933545520835e5ba7db9493d3e17cddefe6a5f567624471908db4e2d83a0fbee60608fc84049503b2234a07dc83b27b22847ad8920ff42f674ef79b76280b00233d2b51b8cb2703a9d42bfbc8250c96ec32c051e57f1b4ba528db89c37e4c54e27e6e64ac69635ae887d9541619a9"],
858 .message = [NSData dataWithHexString:@"af71a901e3a61d3132f0fc1fdb474f9ea6579257ffc24d164170145b3dbde8"],
859 .seed = [NSData dataWithHexString:@"44c92e283f77b9499c603d963660c87d2f939461"],
860 .encryptedMessage = [NSData dataWithHexString:@"036046a4a47d9ed3ba9a89139c105038eb7492b05a5d68bfd53accff4597f7a68651b47b4a4627d927e485eed7b4566420e8b409879e5d606eae251d22a5df799f7920bfc117b992572a53b1263146bcea03385cc5e853c9a101c8c3e1bda31a519807496c6cb5e5efb408823a352b8fa0661fb664efadd593deb99fff5ed000e5"],
865 .message = [NSData dataWithHexString:@"a3b844a08239a8ac41605af17a6cfda4d350136585903a417a79268760519a4b4ac3303ec73f0f87cfb32399"],
866 .seed = [NSData dataWithHexString:@"cb28f5860659fceee49c3eeafce625a70803bd32"],
867 .encryptedMessage = [NSData dataWithHexString:@"03d6eb654edce615bc59f455265ed4e5a18223cbb9be4e4069b473804d5de96f54dcaaa603d049c5d94aa1470dfcd2254066b7c7b61ff1f6f6770e3215c51399fd4e34ec5082bc48f089840ad04354ae66dc0f1bd18e461a33cc1258b443a2837a6df26759aa2302334986f87380c9cc9d53be9f99605d2c9a97da7b0915a4a7ad"],
872 .message = [NSData dataWithHexString:@"308b0ecbd2c76cb77fc6f70c5edd233fd2f20929d629f026953bb62a8f4a3a314bde195de85b5f816da2aab074d26cb6acddf323ae3b9c678ac3cf12fbdde7"],
873 .seed = [NSData dataWithHexString:@"2285f40d770482f9a9efa2c72cb3ac55716dc0ca"],
874 .encryptedMessage = [NSData dataWithHexString:@"0770952181649f9f9f07ff626ff3a22c35c462443d905d456a9fd0bff43cac2ca7a9f554e9478b9acc3ac838b02040ffd3e1847de2e4253929f9dd9ee4044325a9b05cabb808b2ee840d34e15d105a3f1f7b27695a1a07a2d73fe08ecaaa3c9c9d4d5a89ff890d54727d7ae40c0ec1a8dd86165d8ee2c6368141016a48b55b6967"],
879 .message = [NSData dataWithHexString:@"15c5b9ee1185"],
880 .seed = [NSData dataWithHexString:@"49fa45d3a78dd10dfd577399d1eb00af7eed5513"],
881 .encryptedMessage = [NSData dataWithHexString:@"0812b76768ebcb642d040258e5f4441a018521bd96687e6c5e899fcd6c17588ff59a82cc8ae03a4b45b31299af1788c329f7dcd285f8cf4ced82606b97612671a45bedca133442144d1617d114f802857f0f9d739751c57a3f9ee400912c61e2e6992be031a43dd48fa6ba14eef7c422b5edc4e7afa04fdd38f402d1c8bb719abf"],
886 .message = [NSData dataWithHexString:@"21026e6800c7fa728fcaaba0d196ae28d7a2ac4ffd8abce794f0985f60c8a6737277365d3fea11db8923a2029a"],
887 .seed = [NSData dataWithHexString:@"f0287413234cc5034724a094c4586b87aff133fc"],
888 .encryptedMessage = [NSData dataWithHexString:@"07b60e14ec954bfd29e60d0047e789f51d57186c63589903306793ced3f68241c743529aba6a6374f92e19e0163efa33697e196f7661dfaaa47aac6bde5e51deb507c72c589a2ca1693d96b1460381249b2cdb9eac44769f2489c5d3d2f99f0ee3c7ee5bf64a5ac79c42bd433f149be8cb59548361640595513c97af7bc2509723"],
893 .message = [NSData dataWithHexString:@"541e37b68b6c8872b84c02"],
894 .seed = [NSData dataWithHexString:@"d9fba45c96f21e6e26d29eb2cdcb6585be9cb341"],
895 .encryptedMessage = [NSData dataWithHexString:@"08c36d4dda33423b2ed6830d85f6411ba1dcf470a1fae0ebefee7c089f256cef74cb96ea69c38f60f39abee44129bcb4c92de7f797623b20074e3d9c2899701ed9071e1efa0bdd84d4c3e5130302d8f0240baba4b84a71cc032f2235a5ff0fae277c3e8f9112bef44c9ae20d175fc9a4058bfc930ba31b02e2e4f444483710f24a"],
902 .message = [NSData dataWithHexString:@"4046ca8baa3347ca27f49e0d81f9cc1d71be9ba517d4"],
903 .seed = [NSData dataWithHexString:@"dd0f6cfe415e88e5a469a51fbba6dfd40adb4384"],
904 .encryptedMessage = [NSData dataWithHexString:@"0630eebcd2856c24f798806e41f9e67345eda9ceda386acc9facaea1eeed06ace583709718d9d169fadf414d5c76f92996833ef305b75b1e4b95f662a20faedc3bae0c4827a8bf8a88edbd57ec203a27a841f02e43a615bab1a8cac0701de34debdef62a088089b55ec36ea7522fd3ec8d06b6a073e6df833153bc0aefd93bd1a3"],
909 .message = [NSData dataWithHexString:@"5cc72c60231df03b3d40f9b57931bc31109f972527f28b19e7480c7288cb3c92b22512214e4be6c914792ddabdf57faa8aa7"],
910 .seed = [NSData dataWithHexString:@"8d14bd946a1351148f5cae2ed9a0c653e85ebd85"],
911 .encryptedMessage = [NSData dataWithHexString:@"0ebc37376173a4fd2f89cc55c2ca62b26b11d51c3c7ce49e8845f74e7607317c436bc8d23b9667dfeb9d087234b47bc6837175ae5c0559f6b81d7d22416d3e50f4ac533d8f0812f2db9e791fe9c775ac8b6ad0f535ad9ceb23a4a02014c58ab3f8d3161499a260f39348e714ae2a1d3443208fd8b722ccfdfb393e98011f99e63f"],
916 .message = [NSData dataWithHexString:@"b20e651303092f4bccb43070c0f86d23049362ed96642fc5632c27db4a52e3d831f2ab068b23b149879c002f6bf3feee97591112562c"],
917 .seed = [NSData dataWithHexString:@"6c075bc45520f165c0bf5ea4c5df191bc9ef0e44"],
918 .encryptedMessage = [NSData dataWithHexString:@"0a98bf1093619394436cf68d8f38e2f158fde8ea54f3435f239b8d06b8321844202476aeed96009492480ce3a8d705498c4c8c68f01501dc81db608f60087350c8c3b0bd2e9ef6a81458b7c801b89f2e4fe99d4900ba6a4b5e5a96d865dc676c7755928794130d6280a8160a190f2df3ea7cf9aa0271d88e9e6905ecf1c5152d65"],
923 .message = [NSData dataWithHexString:@"684e3038c5c041f7"],
924 .seed = [NSData dataWithHexString:@"3bbc3bd6637dfe12846901029bf5b0c07103439c"],
925 .encryptedMessage = [NSData dataWithHexString:@"008e7a67cacfb5c4e24bec7dee149117f19598ce8c45808fef88c608ff9cd6e695263b9a3c0ad4b8ba4c95238e96a8422b8535629c8d5382374479ad13fa39974b242f9a759eeaf9c83ad5a8ca18940a0162ba755876df263f4bd50c6525c56090267c1f0e09ce0899a0cf359e88120abd9bf893445b3cae77d3607359ae9a52f8"],
930 .message = [NSData dataWithHexString:@"32488cb262d041d6e4dd35f987bf3ca696db1f06ac29a44693"],
931 .seed = [NSData dataWithHexString:@"b46b41893e8bef326f6759383a83071dae7fcabc"],
932 .encryptedMessage = [NSData dataWithHexString:@"00003474416c7b68bdf961c385737944d7f1f40cb395343c693cc0b4fe63b31fedf1eaeeac9ccc0678b31dc32e0977489514c4f09085f6298a9653f01aea4045ff582ee887be26ae575b73eef7f3774921e375a3d19adda0ca31aa1849887c1f42cac9677f7a2f4e923f6e5a868b38c084ef187594dc9f7f048fea2e02955384ab"],
937 .message = [NSData dataWithHexString:@"50ba14be8462720279c306ba"],
938 .seed = [NSData dataWithHexString:@"0a2403312a41e3d52f060fbc13a67de5cf7609a7"],
939 .encryptedMessage = [NSData dataWithHexString:@"0a026dda5fc8785f7bd9bf75327b63e85e2c0fdee5dadb65ebdcac9ae1de95c92c672ab433aa7a8e69ce6a6d8897fac4ac4a54de841ae5e5bbce7687879d79634cea7a30684065c714d52409b928256bbf53eabcd5231eb7259504537399bd29164b726d33a46da701360a4168a091ccab72d44a62fed246c0ffea5b1348ab5470"],
944 .message = [NSData dataWithHexString:@"47aae909"],
945 .seed = [NSData dataWithHexString:@"43dd09a07ff4cac71caa4632ee5e1c1daee4cd8f"],
946 .encryptedMessage = [NSData dataWithHexString:@"1688e4ce7794bba6cb7014169ecd559cede2a30b56a52b68d9fe18cf1973ef97b2a03153951c755f6294aa49adbdb55845ab6875fb3986c93ecf927962840d282f9e54ce8b690f7c0cb8bbd73440d9571d1b16cd9260f9eab4783cc482e5223dc60973871783ec27b0ae0fd47732cbc286a173fc92b00fb4ba6824647cd93c85c1"],
951 .message = [NSData dataWithHexString:@"1d9b2e2223d9bc13bfb9f162ce735db48ba7c68f6822a0a1a7b6ae165834e7"],
952 .seed = [NSData dataWithHexString:@"3a9c3cec7b84f9bd3adecbc673ec99d54b22bc9b"],
953 .encryptedMessage = [NSData dataWithHexString:@"1052ed397b2e01e1d0ee1c50bf24363f95e504f4a03434a08fd822574ed6b9736edbb5f390db10321479a8a139350e2bd4977c3778ef331f3e78ae118b268451f20a2f01d471f5d53c566937171b2dbc2d4bde459a5799f0372d6574239b2323d245d0bb81c286b63c89a361017337e4902f88a467f4c7f244bfd5ab46437ff3b6"],
958 .message = [NSData dataWithHexString:@"d976fc"],
959 .seed = [NSData dataWithHexString:@"76a75e5b6157a556cf8884bb2e45c293dd545cf5"],
960 .encryptedMessage = [NSData dataWithHexString:@"2155cd843ff24a4ee8badb7694260028a490813ba8b369a4cbf106ec148e5298707f5965be7d101c1049ea8584c24cd63455ad9c104d686282d3fb803a4c11c1c2e9b91c7178801d1b6640f003f5728df007b8a4ccc92bce05e41a27278d7c85018c52414313a5077789001d4f01910b72aad05d220aa14a58733a7489bc54556b"],
965 .message = [NSData dataWithHexString:@"d4738623df223aa43843df8467534c41d013e0c803c624e263666b239bde40a5f29aeb8de79e3daa61dd0370f49bd4b013834b98212aef6b1c5ee373b3cb"],
966 .seed = [NSData dataWithHexString:@"7866314a6ad6f2b250a35941db28f5864b585859"],
967 .encryptedMessage = [NSData dataWithHexString:@"0ab14c373aeb7d4328d0aaad8c094d88b9eb098b95f21054a29082522be7c27a312878b637917e3d819e6c3c568db5d843802b06d51d9e98a2be0bf40c031423b00edfbff8320efb9171bd2044653a4cb9c5122f6c65e83cda2ec3c126027a9c1a56ba874d0fea23f380b82cf240b8cf540004758c4c77d934157a74f3fc12bfac"],
972 .message = [NSData dataWithHexString:@"bb47231ca5ea1d3ad46c99345d9a8a61"],
973 .seed = [NSData dataWithHexString:@"b2166ed472d58db10cab2c6b000cccf10a7dc509"],
974 .encryptedMessage = [NSData dataWithHexString:@"028387a318277434798b4d97f460068df5298faba5041ba11761a1cb7316b24184114ec500257e2589ed3b607a1ebbe97a6cc2e02bf1b681f42312a33b7a77d8e7855c4a6de03e3c04643f786b91a264a0d6805e2cea91e68177eb7a64d9255e4f27e713b7ccec00dc200ebd21c2ea2bb890feae4942df941dc3f97890ed347478"],
979 .message = [NSData dataWithHexString:@"2184827095d35c3f86f600e8e59754013296"],
980 .seed = [NSData dataWithHexString:@"52673bde2ca166c2aa46131ac1dc808d67d7d3b1"],
981 .encryptedMessage = [NSData dataWithHexString:@"14c678a94ad60525ef39e959b2f3ba5c097a94ff912b67dbace80535c187abd47d075420b1872152bba08f7fc31f313bbf9273c912fc4c0149a9b0cfb79807e346eb332069611bec0ff9bcd168f1f7c33e77313cea454b94e2549eecf002e2acf7f6f2d2845d4fe0aab2e5a92ddf68c480ae11247935d1f62574842216ae674115"],
986 .message = [NSData dataWithHexString:@"050b755e5e6880f7b9e9d692a74c37aae449b31bfea6deff83747a897f6c2c825bb1adbf850a3c96994b5de5b33cbc7d4a17913a7967"],
987 .seed = [NSData dataWithHexString:@"7706ffca1ecfb1ebee2a55e5c6e24cd2797a4125"],
988 .encryptedMessage = [NSData dataWithHexString:@"09b3683d8a2eb0fb295b62ed1fb9290b714457b7825319f4647872af889b30409472020ad12912bf19b11d4819f49614824ffd84d09c0a17e7d17309d12919790410aa2995699f6a86dbe3242b5acc23af45691080d6b1ae810fb3e3057087f0970092ce00be9562ff4053b6262ce0caa93e13723d2e3a5ba075d45f0d61b54b61"],
993 .message = [NSData dataWithHexString:@"4eb68dcd93ca9b19df111bd43608f557026fe4aa1d5cfac227a3eb5ab9548c18a06dded23f81825986b2fcd71109ecef7eff88873f075c2aa0c469f69c92bc"],
994 .seed = [NSData dataWithHexString:@"a3717da143b4dcffbc742665a8fa950585548343"],
995 .encryptedMessage = [NSData dataWithHexString:@"2ecf15c97c5a15b1476ae986b371b57a24284f4a162a8d0c8182e7905e792256f1812ba5f83f1f7a130e42dcc02232844edc14a31a68ee97ae564a383a3411656424c5f62ddb646093c367be1fcda426cf00a06d8acb7e57776fbbd855ac3df506fc16b1d7c3f2110f3d8068e91e186363831c8409680d8da9ecd8cf1fa20ee39d"],
1000 .message = [NSData dataWithHexString:@"8604ac56328c1ab5ad917861"],
1001 .seed = [NSData dataWithHexString:@"ee06209073cca026bb264e5185bf8c68b7739f86"],
1002 .encryptedMessage = [NSData dataWithHexString:@"4bc89130a5b2dabb7c2fcf90eb5d0eaf9e681b7146a38f3173a3d9cfec52ea9e0a41932e648a9d69344c50da763f51a03c95762131e8052254dcd2248cba40fd31667786ce05a2b7b531ac9dac9ed584a59b677c1a8aed8c5d15d68c05569e2be780bf7db638fd2bfd2a85ab276860f3777338fca989ffd743d13ee08e0ca9893f"],
1007 .message = [NSData dataWithHexString:@"fdda5fbf6ec361a9d9a4ac68af216a0686f438b1e0e5c36b955f74e107f39c0dddcc"],
1008 .seed = [NSData dataWithHexString:@"990ad573dc48a973235b6d82543618f2e955105d"],
1009 .encryptedMessage = [NSData dataWithHexString:@"2e456847d8fc36ff0147d6993594b9397227d577752c79d0f904fcb039d4d812fea605a7b574dd82ca786f93752348438ee9f5b5454985d5f0e1699e3e7ad175a32e15f03deb042ab9fe1dd9db1bb86f8c089ccb45e7ef0c5ee7ca9b7290ca6b15bed47039788a8a93ff83e0e8d6244c71006362deef69b6f416fb3c684383fbd0"],
1014 .message = [NSData dataWithHexString:@"4a5f4914bee25de3c69341de07"],
1015 .seed = [NSData dataWithHexString:@"ecc63b28f0756f22f52ac8e6ec1251a6ec304718"],
1016 .encryptedMessage = [NSData dataWithHexString:@"1fb9356fd5c4b1796db2ebf7d0d393cc810adf6145defc2fce714f79d93800d5e2ac211ea8bbecca4b654b94c3b18b30dd576ce34dc95436ef57a09415645923359a5d7b4171ef22c24670f1b229d3603e91f76671b7df97e7317c97734476d5f3d17d21cf82b5ba9f83df2e588d36984fd1b584468bd23b2e875f32f68953f7b2"],
1021 .message = [NSData dataWithHexString:@"8e07d66f7b880a72563abcd3f35092bc33409fb7f88f2472be"],
1022 .seed = [NSData dataWithHexString:@"3925c71b362d40a0a6de42145579ba1e7dd459fc"],
1023 .encryptedMessage = [NSData dataWithHexString:@"3afd9c6600147b21798d818c655a0f4c9212db26d0b0dfdc2a7594ccb3d22f5bf1d7c3e112cd73fc7d509c7a8bafdd3c274d1399009f9609ec4be6477e453f075aa33db382870c1c3409aef392d7386ae3a696b99a94b4da0589447e955d16c98b17602a59bd736279fcd8fb280c4462d590bfa9bf13fed570eafde97330a2c210"],
1028 .message = [NSData dataWithHexString:@"f735fd55ba92592c3b52b8f9c4f69aaa1cbef8fe88add095595412467f9cf4ec0b896c59eda16210e7549c8abb10cdbc21a12ec9b6b5b8fd2f10399eb6"],
1029 .seed = [NSData dataWithHexString:@"8ec965f134a3ec9931e92a1ca0dc8169d5ea705c"],
1030 .encryptedMessage = [NSData dataWithHexString:@"267bcd118acab1fc8ba81c85d73003cb8610fa55c1d97da8d48a7c7f06896a4db751aa284255b9d36ad65f37653d829f1b37f97b8001942545b2fc2c55a7376ca7a1be4b1760c8e05a33e5aa2526b8d98e317088e7834c755b2a59b12631a182c05d5d43ab1779264f8456f515ce57dfdf512d5493dab7b7338dc4b7d78db9c091ac3baf537a69fc7f549d979f0eff9a94fda4169bd4d1d19a69c99e33c3b55490d501b39b1edae118ff6793a153261584d3a5f39f6e682e3d17c8cd1261fa72"],
1035 .message = [NSData dataWithHexString:@"81b906605015a63aabe42ddf11e1978912f5404c7474b26dce3ed482bf961ecc818bf420c54659"],
1036 .seed = [NSData dataWithHexString:@"ecb1b8b25fa50cdab08e56042867f4af5826d16c"],
1037 .encryptedMessage = [NSData dataWithHexString:@"93ac9f0671ec29acbb444effc1a5741351d60fdb0e393fbf754acf0de49761a14841df7772e9bc82773966a1584c4d72baea00118f83f35cca6e537cbd4d811f5583b29783d8a6d94cd31be70d6f526c10ff09c6fa7ce069795a3fcd0511fd5fcb564bcc80ea9c78f38b80012539d8a4ddf6fe81e9cddb7f50dbbbbcc7e5d86097ccf4ec49189fb8bf318be6d5a0715d516b49af191258cd32dc833ce6eb4673c03a19bbace88cc54895f636cc0c1ec89096d11ce235a265ca1764232a689ae8"],
1042 .message = [NSData dataWithHexString:@"fd326429df9b890e09b54b18b8f34f1e24"],
1043 .seed = [NSData dataWithHexString:@"e89bb032c6ce622cbdb53bc9466014ea77f777c0"],
1044 .encryptedMessage = [NSData dataWithHexString:@"81ebdd95054b0c822ef9ad7693f5a87adfb4b4c4ce70df2df84ed49c04da58ba5fc20a19e1a6e8b7a3900b22796dc4e869ee6b42792d15a8eceb56c09c69914e813cea8f6931e4b8ed6f421af298d595c97f4789c7caa612c7ef360984c21b93edc5401068b5af4c78a8771b984d53b8ea8adf2f6a7d4a0ba76c75e1dd9f658f20ded4a46071d46d7791b56803d8fea7f0b0f8e41ae3f09383a6f9585fe7753eaaffd2bf94563108beecc207bbb535f5fcc705f0dde9f708c62f49a9c90371d3"],
1049 .message = [NSData dataWithHexString:@"f1459b5f0c92f01a0f723a2e5662484d8f8c0a20fc29dad6acd43bb5f3effdf4e1b63e07fdfe6628d0d74ca19bf2d69e4a0abf86d293925a796772f8088e"],
1050 .seed = [NSData dataWithHexString:@"606f3b99c0b9ccd771eaa29ea0e4c884f3189ccc"],
1051 .encryptedMessage = [NSData dataWithHexString:@"bcc35f94cde66cb1136625d625b94432a35b22f3d2fa11a613ff0fca5bd57f87b902ccdc1cd0aebcb0715ee869d1d1fe395f6793003f5eca465059c88660d446ff5f0818552022557e38c08a67ead991262254f10682975ec56397768537f4977af6d5f6aaceb7fb25dec5937230231fd8978af49119a29f29e424ab8272b47562792d5c94f774b8829d0b0d9f1a8c9eddf37574d5fa248eefa9c5271fc5ec2579c81bdd61b410fa61fe36e424221c113addb275664c801d34ca8c6351e4a858"],
1056 .message = [NSData dataWithHexString:@"53e6e8c729d6f9c319dd317e74b0db8e4ccca25f3c8305746e137ac63a63ef3739e7b595abb96e8d55e54f7bd41ab433378ffb911d"],
1057 .seed = [NSData dataWithHexString:@"fcbc421402e9ecabc6082afa40ba5f26522c840e"],
1058 .encryptedMessage = [NSData dataWithHexString:@"232afbc927fa08c2f6a27b87d4a5cb09c07dc26fae73d73a90558839f4fd66d281b87ec734bce237ba166698ed829106a7de6942cd6cdce78fed8d2e4d81428e66490d036264cef92af941d3e35055fe3981e14d29cbb9a4f67473063baec79a1179f5a17c9c1832f2838fd7d5e59bb9659d56dce8a019edef1bb3accc697cc6cc7a778f60a064c7f6f5d529c6210262e003de583e81e3167b89971fb8c0e15d44fffef89b53d8d64dd797d159b56d2b08ea5307ea12c241bd58d4ee278a1f2e"],
1063 .message = [NSData dataWithHexString:@"b6b28ea2198d0c1008bc64"],
1064 .seed = [NSData dataWithHexString:@"23aade0e1e08bb9b9a78d2302a52f9c21b2e1ba2"],
1065 .encryptedMessage = [NSData dataWithHexString:@"438cc7dc08a68da249e42505f8573ba60e2c2773d5b290f4cf9dff718e842081c383e67024a0f29594ea987b9d25e4b738f285970d195abb3a8c8054e3d79d6b9c9a8327ba596f1259e27126674766907d8d582ff3a8476154929adb1e6d1235b2ccb4ec8f663ba9cc670a92bebd853c8dbf69c6436d016f61add836e94732450434207f9fd4c43dec2a12a958efa01efe2669899b5e604c255c55fb7166de5589e369597bb09168c06dd5db177e06a1740eb2d5c82faeca6d92fcee9931ba9f"],
1070 .message = [NSData dataWithHexString:@"8bba6bf82a6c0f86d5f1756e97956870b08953b06b4eb205bc1694ee"],
1071 .seed = [NSData dataWithHexString:@"47e1ab7119fee56c95ee5eaad86f40d0aa63bd33"],
1072 .encryptedMessage = [NSData dataWithHexString:@"53ea5dc08cd260fb3b858567287fa91552c30b2febfba213f0ae87702d068d19bab07fe574523dfb42139d68c3c5afeee0bfe4cb7969cbf382b804d6e61396144e2d0e60741f8993c3014b58b9b1957a8babcd23af854f4c356fb1662aa72bfcc7e586559dc4280d160c126785a723ebeebeff71f11594440aaef87d10793a8774a239d4a04c87fe1467b9daf85208ec6c7255794a96cc29142f9a8bd418e3c1fd67344b0cd0829df3b2bec60253196293c6b34d3f75d32f213dd45c6273d505adf4cced1057cb758fc26aeefa441255ed4e64c199ee075e7f16646182fdb464739b68ab5daff0e63e9552016824f054bf4d3c8c90a97bb6b6553284eb429fcc"],
1077 .message = [NSData dataWithHexString:@"e6ad181f053b58a904f2457510373e57"],
1078 .seed = [NSData dataWithHexString:@"6d17f5b4c1ffac351d195bf7b09d09f09a4079cf"],
1079 .encryptedMessage = [NSData dataWithHexString:@"a2b1a430a9d657e2fa1c2bb5ed43ffb25c05a308fe9093c01031795f5874400110828ae58fb9b581ce9dddd3e549ae04a0985459bde6c626594e7b05dc4278b2a1465c1368408823c85e96dc66c3a30983c639664fc4569a37fe21e5a195b5776eed2df8d8d361af686e750229bbd663f161868a50615e0c337bec0ca35fec0bb19c36eb2e0bbcc0582fa1d93aacdb061063f59f2ce1ee43605e5d89eca183d2acdfe9f81011022ad3b43a3dd417dac94b4e11ea81b192966e966b182082e71964607b4f8002f36299844a11f2ae0faeac2eae70f8f4f98088acdcd0ac556e9fccc511521908fad26f04c64201450305778758b0538bf8b5bb144a828e629795"],
1084 .message = [NSData dataWithHexString:@"510a2cf60e866fa2340553c94ea39fbc256311e83e94454b4124"],
1085 .seed = [NSData dataWithHexString:@"385387514deccc7c740dd8cdf9daee49a1cbfd54"],
1086 .encryptedMessage = [NSData dataWithHexString:@"9886c3e6764a8b9a84e84148ebd8c3b1aa8050381a78f668714c16d9cfd2a6edc56979c535d9dee3b44b85c18be8928992371711472216d95dda98d2ee8347c9b14dffdff84aa48d25ac06f7d7e65398ac967b1ce90925f67dce049b7f812db0742997a74d44fe81dbe0e7a3feaf2e5c40af888d550ddbbe3bc20657a29543f8fc2913b9bd1a61b2ab2256ec409bbd7dc0d17717ea25c43f42ed27df8738bf4afc6766ff7aff0859555ee283920f4c8a63c4a7340cbafddc339ecdb4b0515002f96c932b5b79167af699c0ad3fccfdf0f44e85a70262bf2e18fe34b850589975e867ff969d48eabf212271546cdc05a69ecb526e52870c836f307bd798780ede"],
1091 .message = [NSData dataWithHexString:@"bcdd190da3b7d300df9a06e22caae2a75f10c91ff667b7c16bde8b53064a2649a94045c9"],
1092 .seed = [NSData dataWithHexString:@"5caca6a0f764161a9684f85d92b6e0ef37ca8b65"],
1093 .encryptedMessage = [NSData dataWithHexString:@"6318e9fb5c0d05e5307e1683436e903293ac4642358aaa223d7163013aba87e2dfda8e60c6860e29a1e92686163ea0b9175f329ca3b131a1edd3a77759a8b97bad6a4f8f4396f28cf6f39ca58112e48160d6e203daa5856f3aca5ffed577af499408e3dfd233e3e604dbe34a9c4c9082de65527cac6331d29dc80e0508a0fa7122e7f329f6cca5cfa34d4d1da417805457e008bec549e478ff9e12a763c477d15bbb78f5b69bd57830fc2c4ed686d79bc72a95d85f88134c6b0afe56a8ccfbc855828bb339bd17909cf1d70de3335ae07039093e606d655365de6550b872cd6de1d440ee031b61945f629ad8a353b0d40939e96a3c450d2a8d5eee9f678093c8"],
1098 .message = [NSData dataWithHexString:@"a7dd6c7dc24b46f9dd5f1e91ada4c3b3df947e877232a9"],
1099 .seed = [NSData dataWithHexString:@"95bca9e3859894b3dd869fa7ecd5bbc6401bf3e4"],
1100 .encryptedMessage = [NSData dataWithHexString:@"75290872ccfd4a4505660d651f56da6daa09ca1301d890632f6a992f3d565cee464afded40ed3b5be9356714ea5aa7655f4a1366c2f17c728f6f2c5a5d1f8e28429bc4e6f8f2cff8da8dc0e0a9808e45fd09ea2fa40cb2b6ce6ffff5c0e159d11b68d90a85f7b84e103b09e682666480c657505c0929259468a314786d74eab131573cf234bf57db7d9e66cc6748192e002dc0deea930585f0831fdcd9bc33d51f79ed2ffc16bcf4d59812fcebcaa3f9069b0e445686d644c25ccf63b456ee5fa6ffe96f19cdf751fed9eaf35957754dbf4bfea5216aa1844dc507cb2d080e722eba150308c2b5ff1193620f1766ecf4481bafb943bd292877f2136ca494aba0"],
1105 .message = [NSData dataWithHexString:@"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac"],
1106 .seed = [NSData dataWithHexString:@"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32"],
1107 .encryptedMessage = [NSData dataWithHexString:@"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46"],
1112 int max_cycles = 100;
1113 if (!getenv("SUBMISSION_TEST")) {
1115 CFfprintf(stderr, "Running the far faster but far less reliable fast test.\nSet the SUBMISSION_TEST environment variable for full testing\n");
1118 for (int j = 0; j < max_cycles; j++) {
1119 NSLog(@"Cycle %d", j);
1120 for (i = 0; i < sizeof(tests)/sizeof(KAT); i++) {
1121 NSLog(@"test#%d %@ L(IN)=%lu, L(OUT)=%lu", i, tests[i].label, [tests[i].message length], [tests[i].encryptedMessage length]);
1122 CFErrorRef err = NULL;
1124 SecTransformRef encryptor = SecEncryptTransformCreate(tests[i].keys.pubKey, &err);
1126 SecTransformSetAttribute(encryptor, kSecTransformInputAttributeName, tests[i].message, &err);
1127 SecTransformSetAttribute(encryptor, kSecPaddingKey, kSecPaddingOAEPKey, &err);
1128 SecTransformSetAttribute(encryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, &err);
1129 SecTransformSetAttribute(encryptor, CFSTR("FixedSeedForOAEPTesting"), tests[i].seed, &err);
1131 CFTypeRef encryptedData = SecTransformExecute(encryptor, &err);
1132 STAssertNotNil((id)encryptedData, @"Expected to get encrypted data");
1133 STAssertNil((NSError*)err, @"Expected no error, got err=%@", err);
1134 // Can't support "seed" with commoncrypto, just check round trip.
1135 //STAssertEqualObjects((id)encryptedData, (id)tests[i].encryptedMessage, @"encrypted data should have matched test vector (%@) data", tests[i].label);
1136 CFRelease(encryptor);
1138 SecTransformRef decryptor = SecDecryptTransformCreate(tests[i].keys.privKey, NULL);
1139 SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, tests[i].encryptedMessage, NULL);
1140 // XXX: totally round trip, not even partial KAT (KAT can't really be done on OAEP
1141 // without supporitng settign the seed externally)
1142 SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, encryptedData, NULL);
1143 SecTransformSetAttribute(decryptor, kSecPaddingKey, kSecPaddingOAEPKey, NULL);
1144 SecTransformSetAttribute(decryptor, kSecOAEPEncodingParametersAttributeName, encoding_parameters, NULL);
1145 CFTypeRef decryptedData = SecTransformExecute(decryptor, &err);
1146 STAssertNil((id)err, @"Expected no error, got: %@", err);
1147 STAssertNotNil((id)decryptedData, @"Expected to get decrypted data");
1148 STAssertEqualObjects((id)decryptedData, tests[i].message, @"Expected decrypted data to match original message (%@)", tests[i].label);
1149 CFRelease(decryptor);
1156 -(void)testNoSignKeyMakesError
1158 NSData *data = [NSData dataWithBytes:"" length:1];
1162 CFErrorRef createError;
1163 SecTransformRef transform;
1167 .createError = NULL,
1168 .transform = SecSignTransformCreate(NULL, &(test_cases[0].createError))
1172 .createError = NULL,
1173 .transform = SecVerifyTransformCreate(NULL, (CFDataRef)data, &(test_cases[1].createError))
1177 for(int i = 0; i < sizeof(test_cases) / sizeof(test_case); i++) {
1178 struct test_case *test = test_cases + i;
1179 STAssertNil((id)test->createError, @"Testing %@, unexpected error: %@", test->name, test->createError);
1180 STAssertNotNil((id)test->transform, @"Didn't manage to create transform for %@", test->name);
1181 if (!test->transform) {
1185 __block CFErrorRef err = NULL;
1186 SecTransformSetAttribute(test->transform, kSecTransformInputAttributeName, data, &err);
1187 STAssertNil((id)err, @"Error setting input for %@: %@", test->name, err);
1189 dispatch_group_t execute_done = dispatch_group_create();
1190 dispatch_group_enter(execute_done);
1192 SecTransformExecuteAsync(test->transform, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
1197 dispatch_group_leave(execute_done);
1201 STAssertFalse(dispatch_group_wait(execute_done, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)), @"Timeout waiting for %@ transform", test->name);
1202 STAssertErrorHas((id)err, @"missing required attributes?:.*KEY", @"Unexpected error during %@ test, expected one about missing keys: %@", test->name, err);
1203 dispatch_group_notify(execute_done, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(void) {
1204 dispatch_release(execute_done);
1211 // make the data for the key and the data to be HMAC'd
1212 CFDataRef hmacData = CFDataCreate(NULL, (u_int8_t*) gHMACText, strlen(gHMACText));
1213 CFDataRef hmacKey = CFDataCreate(NULL, (u_int8_t*) gHMACKey, strlen(gHMACKey));
1214 SecTransformRef hmacRef;
1215 CFErrorRef error = NULL;
1217 CFDataRef rightAnswer;
1218 CFComparisonResult ok;
1220 // create the object
1221 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA1, 20, &error);
1222 STAssertNil((id) error, @"Unexpected error returned.");
1225 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error);
1226 STAssertNil((id) error, @"Unexpected error returned.");
1229 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error);
1230 STAssertNil((id) error, @"Unexpected error returned.");
1232 result = (CFDataRef) SecTransformExecute(hmacRef, &error);
1236 STAssertNil((id) error, @"Unexpected error returned.");
1240 STAssertNotNil((id) result, @"No data returned for SHA1");
1242 // check to make sure we got the right answer
1243 rightAnswer = CFDataCreate(NULL, gSHA1HMAC, sizeof(gSHA1HMAC));
1244 ok = CFEqual(rightAnswer, result);
1245 CFRelease(rightAnswer);
1254 STAssertTrue(ok, @"Digest returned incorrect HMACSHA1 result.");
1256 //+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
1258 // create the object
1259 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA2, 256, &error);
1260 STAssertNil((id) error, @"Unexpected error returned.");
1263 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error);
1264 STAssertNil((id) error, @"Unexpected error returned.");
1267 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error);
1268 STAssertNil((id) error, @"Unexpected error returned.");
1270 result = (CFDataRef) SecTransformExecute(hmacRef, &error);
1274 STAssertNil((id) error, @"Unexpected error returned.");
1278 STAssertNotNil((id) result, @"No data returned for SHA256");
1280 rightAnswer = CFDataCreate(NULL, gSHA256HMAC, sizeof(gSHA256HMAC));
1281 ok = CFEqual(result, rightAnswer);
1283 CFRelease(rightAnswer);
1286 CFRelease(hmacData);
1290 STAssertTrue(ok, @"Digest returned incorrect HMACSHA256 result.");
1295 -(void)echoParams:(NSString*)p1 p2:(NSString*)p2
1299 -(void)testReadStreamTransform
1301 // point to our test data
1302 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/usr/share/dict/words"), kCFURLPOSIXPathStyle, false);
1303 FSRef force_resolve;
1304 STAssertTrue(CFURLGetFSRef(url, &force_resolve), @"Expected to create FSRef from %@", url);
1305 CFURLRef resolved_url = CFURLCreateFromFSRef(NULL, &force_resolve);
1306 CFNumberRef size_on_disk = NULL;
1307 CFURLCopyResourcePropertyForKey(resolved_url, kCFURLFileSizeKey, &size_on_disk, NULL);
1308 STAssertNotNil((id)size_on_disk, @"Expected to fetch size");
1310 CFReadStreamRef readStreamRef = CFReadStreamCreateWithFile(NULL, url);
1311 SecTransformRef transform = SecTransformCreateReadTransformWithReadStream(readStreamRef);
1312 STAssertNotNil((id) transform, @"Returned transform should not be nil.");
1314 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
1315 dispatch_queue_t queue = dispatch_queue_create("ReadStream queue", NULL);
1316 __block ssize_t bytes_presented = 0;
1318 SecTransformExecuteAsync(transform, queue,
1319 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
1323 bytes_presented += CFDataGetLength((CFDataRef)message);
1327 STAssertNil((id)error, @"Unexpected error!");
1328 dispatch_semaphore_signal(waitSemaphore);
1332 dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER);
1333 NSNumber *size_via_stream = [NSNumber numberWithLongLong:bytes_presented];
1334 STAssertEqualObjects(size_via_stream, (NSNumber*)size_on_disk, @"Expected sizes to match");
1335 CFRelease(size_on_disk);
1337 dispatch_release(queue);
1338 dispatch_release(waitSemaphore);
1339 CFRelease(transform);
1340 CFRelease(readStreamRef);
1342 CFRelease(resolved_url);
1347 UInt8 raw_seed[] = {0xaa, 0xfd, 0x12, 0xf6, 0x59, 0xca, 0xe6, 0x34, 0x89, 0xb4, 0x79, 0xe5, 0x07, 0x6d, 0xde, 0xc2, 0xf0, 0x6c, 0xb5, 0x8f};
1348 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};
1349 CFDataRef seed = CFDataCreate(NULL, raw_seed, sizeof(raw_seed));
1350 CFDataRef mgf107 = CFDataCreate(NULL, raw_mgf107, sizeof(raw_mgf107));
1351 CFErrorRef err = NULL;
1353 SecTransformRef mgfTransform = SecCreateMaskGenerationFunctionTransform(NULL, 107, &err);
1354 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err);
1356 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, seed, &err);
1357 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err);
1359 CFDataRef mgfOutput = (CFDataRef)SecTransformExecute(mgfTransform, &err);
1360 STAssertNotNil((id)mgfOutput, @"Expected output from mgf, got error %@", err);
1361 STAssertEqualObjects((id)mgfOutput, (id)mgf107, @"Expected matching output");
1363 CFRelease(mgfTransform);
1366 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};
1368 UInt8 raw_mgf20[] = {0x41, 0x87, 0x0b, 0x5a, 0xb0, 0x29, 0xe6, 0x57, 0xd9, 0x57, 0x50, 0xb5, 0x4c, 0x28, 0x3c, 0x08, 0x72, 0x5d, 0xbe, 0xa9};
1369 CFDataRef maskedDB = CFDataCreate(NULL, raw_maskedDB, sizeof(raw_maskedDB));
1370 CFDataRef mgf20 = CFDataCreate(NULL, raw_mgf20, sizeof(raw_mgf20));
1373 mgfTransform = SecCreateMaskGenerationFunctionTransform(kSecDigestSHA1, 20, &err);
1374 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err);
1376 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, maskedDB, &err);
1377 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err);
1379 mgfOutput = (CFDataRef)SecTransformExecute(mgfTransform, &err);
1380 STAssertNotNil((id)mgfOutput, @"Expected output from mgf, got error %@", err);
1381 STAssertEqualObjects((id)mgfOutput, (id)mgf20, @"Expected matching output");
1384 -(void)testAbortParams
1386 // make a simple transform
1387 SecTransformRef a = SecNullTransformCreate();
1389 // try to abort the transform
1390 CFErrorRef errorRef = NULL;
1391 STAssertFalse(SecTransformSetAttribute(a, CFSTR("ABORT"), NULL, &errorRef), @"SecTransformSetAttribute should have returned FALSE");
1392 STAssertNotNil((id) errorRef, @"SecTransformSetAttribute should have had an error.");
1393 if (errorRef != NULL)
1395 CFRelease(errorRef);
1400 // 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
1401 // 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
1402 // triggered off of a NULL value.
1403 SecGroupTransformRef test_null_abort_via_connection = SecTransformCreateGroupTransform();
1404 SecTransformRef pass_through = SecNullTransformCreate();
1405 SecTransformRef null_abort = SecNullTransformCreate();
1407 CFURLRef dev_null_url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/dev/null"), kCFURLPOSIXPathStyle, NO);
1408 CFReadStreamRef dev_null_stream = CFReadStreamCreateWithFile(NULL, dev_null_url);
1409 CFReadStreamOpen(dev_null_stream);
1410 CFRelease(dev_null_url);
1412 SecTransformSetAttribute(pass_through, kSecTransformInputAttributeName, dev_null_stream, NULL);
1413 SecTransformConnectTransforms(pass_through, kSecTransformOutputAttributeName, null_abort, kSecTransformAbortAttributeName, test_null_abort_via_connection, NULL);
1415 SecTransformRef delay_null = delay_transform(NSEC_PER_SEC / 10);
1416 SecTransformConnectTransforms(pass_through, kSecTransformOutputAttributeName, delay_null, kSecTransformInputAttributeName, test_null_abort_via_connection, NULL);
1417 SecTransformConnectTransforms(delay_null, kSecTransformOutputAttributeName, null_abort, kSecTransformInputAttributeName, test_null_abort_via_connection, NULL);
1420 CFErrorRef err = NULL;
1421 CFTypeRef not_null = SecTransformExecute(test_null_abort_via_connection, &err);
1423 STAssertNotNil((id)not_null, @"aborted via a NULL from a connection? err=%@", err);
1430 CFRelease(test_null_abort_via_connection);
1431 CFRelease(pass_through);
1432 CFRelease(null_abort);
1433 CFRelease(delay_null);
1435 CFReadStreamClose(dev_null_stream);
1436 CFRelease(dev_null_stream);
1440 -(void)testDisconnect
1442 SecTransformRef a = SecNullTransformCreate();
1443 SecTransformRef b = SecNullTransformCreate();
1444 SecTransformRef c = SecNullTransformCreate();
1445 SecGroupTransformRef g = SecTransformCreateGroupTransform();
1447 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, g, NULL);
1448 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName, g, NULL);
1450 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName);
1451 STAssertTrue(SecGroupTransformHasMember(g, a), @"A should still be in the group, but isn't");
1453 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName);
1454 STAssertFalse(SecGroupTransformHasMember(g, a), @"A should no longer be in the group, but is");
1465 CFStringRef abort_test_name = CFSTR("com.apple.security.unit-test.abortTest");
1467 SecTransformCreateBlock setupBlock =
1468 ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params)
1470 params->send(kSecTransformInputAttributeName, kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
1472 params->overrideAttribute(kSecTransformActionAttributeNotification, CFSTR("PB"), ^(SecTransformAttributeRef ah, CFTypeRef value) {
1473 // Makes sure we can shut down (via ABORT) a transform that has a pending pushback
1474 params->pushback(ah, value);
1475 return (CFTypeRef)NULL;
1482 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1484 // make two of these transforms and link them together
1485 a = custom_transform(abort_test_name, setupBlock);
1486 STAssertNotNil((id) a, @"SecCustomTransformCreate failed");
1488 dt = delay_transform(NSEC_PER_SEC / 10);
1489 STAssertNotNil((id) dt, @"SecCustomTransformCreate failed");
1491 // connect the two transforms
1494 // hook the output up so that the abort automatically fires.
1495 SecTransformConnectTransforms(dt, kSecTransformOutputAttributeName, a, CFSTR("ABORT"), group, &error);
1496 STAssertNil((id) error, @"SecTransformConnectTransforms failed.");
1498 // also hook it up to the input because the input attribute is required on a null transform
1499 SecTransformConnectTransforms(dt, CFSTR("NOVALUES"), a, kSecTransformInputAttributeName, group, &error);
1500 STAssertNil((id) error, @"SecTransformConnectTransforms failed.");
1502 // pass a plain piece of data down the transform just for fun...
1503 const u_int8_t data[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
1505 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, data, sizeof(data), kCFAllocatorNull);
1506 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, dataRef, NULL);
1508 CFStringRef str = CFStringCreateMutable(NULL, 0);
1509 SecTransformSetAttribute(a, CFSTR("PB"), str, NULL);
1511 CFTypeRef er = SecTransformExecute(a, &error);
1513 STAssertNil((id)er, @"Didn't expect an result from aborted transform");
1514 STAssertNotNil((id)error, @"Expected error from execute");
1520 // while we are at it, make sure that the user dictionary has the originating transform
1521 CFDictionaryRef userDictionary = CFErrorCopyUserInfo(error);
1522 STAssertNotNil((id) CFDictionaryGetValue(userDictionary, kSecTransformAbortOriginatorKey), @"Originating transform not listed.");
1532 // XXX: these should both be 1, not 3 or 4. WTF? Is this an abort issue, or a generic leak?
1533 // STAssertEquals(rc0, CFGetRetainCount(str), @"The value we sent to PB hasn't been released (value retained by pushback)");
1534 // STAssertEquals(rc0, CFGetRetainCount(dataRef), @"The value we sent to INPUT hasn't been released");
1538 -(void)testPreAbort {
1539 CFErrorRef error = NULL;
1540 SecTransformRef prebort = SecNullTransformCreate();
1541 SecTransformSetAttribute(prebort, kSecTransformInputAttributeName, CFSTR("quux"), NULL);
1542 SecTransformSetAttribute(prebort, CFSTR("ABORT"), CFSTR("OOPS"), NULL);
1543 CFTypeRef er = SecTransformExecute(prebort, &error);
1544 STAssertNil((id)er, @"Didn't expect an result from pre-aborted transform");
1545 STAssertNotNil((id)error, @"Expected error from execute of pre-aborted transform");
1550 -(void)testFireAndForget
1553 NSGarbageCollector* gc = [NSGarbageCollector defaultCollector];
1556 isGC = [gc isEnabled];
1559 CFIndex retCount = 0;
1562 SecNullTransformRef a = SecNullTransformCreate();
1563 SecNullTransformRef b = SecNullTransformCreate();
1564 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1565 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL);
1569 retCount = CFGetRetainCount(group);
1572 // set up a blob of data to fire
1573 const u_int8_t data[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
1574 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, data, sizeof(data), kCFAllocatorNull);
1575 SecTransformSetAttribute(a, kSecTransformInputAttributeName, dataRef, NULL);
1578 // make dispatch related stuff
1579 dispatch_queue_t queue = dispatch_queue_create("ffqueue", NULL);
1580 // semaphore0's job is to be signaled when we know ExecuteAsync is actually executing (so we don't sample the retain
1581 // count too soone), semaphore signals when we are about done with ExecuteAsync (I'm not sure why we need to know),
1582 // and semaphore2 is signaled to let the execute block know we are done sampling retain counts.
1583 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
1584 dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);
1587 SecTransformExecuteAsync(group, queue,
1588 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
1590 CFfprintf(stderr, "message %p, final %d\n", message, isFinal ? 1 : 0);
1591 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()));
1594 fprintf(stderr, "Final message received.\n");
1595 dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER); // make sure that the other chain has released its material
1596 dispatch_semaphore_signal(semaphore);
1602 dispatch_semaphore_signal(semaphore2);
1603 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
1605 // no crash? Life is good.
1609 -(void)testExternalSource
1611 CFErrorRef err = NULL;
1612 SecTransformRef xs = SecExternalSourceTransformCreate(&err);
1613 SecTransformRef tee = SecNullTransformCreate();
1614 SecTransformRef group = SecTransformCreateGroupTransform();
1616 SecTransformConnectTransforms(xs, kSecTransformOutputAttributeName, tee, kSecTransformInputAttributeName, group, &err);
1618 dispatch_queue_t q = dispatch_queue_create("com.apple.security.unit-tests.test-external-source", 0);
1619 dispatch_group_t dg = dispatch_group_create();
1620 dispatch_group_enter(dg);
1621 __block bool got_ping = false;
1623 SecTransformExecuteAsync(group, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
1624 CFfprintf(stderr, "B: message %@, e %p, f %d\n", message ? message : (CFTypeRef)CFSTR("(NULL)"), error, isFinal);
1627 if (CFEqual(message, CFSTR("PING"))) {
1630 STFail(@"expected ping, got: %@", message);
1635 STFail(@"unexpected error: %@", error);
1640 STFail(@"never got ping");
1642 dispatch_group_leave(dg);
1646 SecExternalSourceSetValue(tee, CFSTR("PONG"), &err);
1647 STAssertNotNil((id)err, @"Expected error setting tee");
1648 STAssertErrorHas((id)err, @"ExternalSource", @"Error should note what should be passed in: %@", err);
1651 SecExternalSourceSetValue(xs, CFSTR("PING"), &err);
1652 STAssertNil((id)err, @"unexpected error setting xs: %@", err);
1653 SecExternalSourceSetValue(xs, NULL, &err);
1654 STAssertNil((id)err, @"unexpected error setting xs: %@", err);
1655 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
1657 dispatch_release(dg);
1658 dispatch_release(q);
1664 -(void)testFindLastAndMonitor
1666 SecNullTransformRef a = delay_transform(NSEC_PER_SEC / 10);
1667 SecNullTransformRef b = SecNullTransformCreate();
1669 SecGroupTransformRef groupRef = SecTransformCreateGroupTransform();
1670 CFErrorRef error = NULL;
1671 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, groupRef, &error);
1672 STAssertNil((id)error, @"An error was returned when none was expected.");
1673 SecTransformSetAttribute(a, kSecTransformInputAttributeName, kCFNull, &error);
1674 STAssertNil((id)error, @"An error was returned when none was expected.");
1677 // get the last transform in the chain (unexecuted). It had better be b...
1678 SecTransformRef tr = SecGroupTransformFindLastTransform(groupRef);
1679 STAssertNotNil((id)tr, @"FindLastTransform returned NULL");
1680 STAssertTrue(tr == b, @"FindLastTransform returned incorrect result");
1681 STAssertFalse(tr == a, @"FindLastTransform returned the head of the chain");
1683 // execute the transform. This should attach an output monitor
1684 dispatch_queue_t queue = dispatch_queue_create("test delivery queue", NULL);
1685 dispatch_semaphore_t last_block_run = dispatch_semaphore_create(0L);
1686 dispatch_semaphore_t last_assert_run = dispatch_semaphore_create(0L);
1687 SecTransformExecuteAsync(groupRef, queue,
1688 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
1692 dispatch_semaphore_signal(last_block_run);
1693 dispatch_semaphore_wait(last_assert_run, DISPATCH_TIME_FOREVER);
1694 dispatch_release(last_assert_run);
1699 dispatch_semaphore_wait(last_block_run, DISPATCH_TIME_FOREVER);
1701 // see if the returned transform is the same now
1702 tr = SecGroupTransformFindLastTransform(groupRef);
1703 STAssertNotNil((id) tr, @"FindLastTransform returned NULL");
1704 STAssertTrue(tr == b, @"FindLastTransform returned incorrect result");
1705 STAssertFalse(tr == a, @"FindLastTransform returned the head of the chain");
1707 // get the monitor, it had better not be a or b
1708 tr = SecGroupTransformFindMonitor(groupRef);
1709 STAssertNotNil((id) tr, @"FindMonitor returned NULL");
1710 STAssertFalse(tr == a, @"FindLastTransform returned the head of the chain");
1711 STAssertFalse(tr == b, @"FindLastTransform returned the head of the chain");
1713 dispatch_semaphore_signal(last_assert_run);
1714 dispatch_release(queue);
1715 dispatch_release(last_block_run);
1718 CFRelease(groupRef);
1722 -(void)testConnectUnsetAttributes /* <rdar://problem/7769955> Can't connect transform attributes with no setting */
1724 SecNullTransformRef a = SecNullTransformCreate();
1725 SecNullTransformRef b = SecNullTransformCreate();
1727 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1728 CFErrorRef error = NULL;
1729 SecTransformConnectTransforms(a, CFSTR("RANDOM_NAME"), b, CFSTR("RANDOM_DESTINATION"), group, &error);
1733 STAssertNil((id) error, @"An error was returned when none was expected.");
1736 -(void)testNoDataFlowPriorToInit /* <rdar://problem/8163542> Monitor must be attached before the data flow becomes active */
1738 CFStringRef name = CFSTR("com.apple.security.unit-test.flow-check");
1739 SecTransformCreateBlock cb = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) {
1740 __block bool inited = false;
1741 __block bool saw_x_start = false;
1742 __block bool saw_null = false;
1743 __block int post_send_left = 8;
1744 SecTransformAttributeRef out_ah = params->get(kSecTransformOutputAttributeName, kSecTransformMetaAttributeRef);
1745 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("create"));
1747 params->overrideTransform(kSecTransformActionStartingExecution, ^{
1748 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("x-start"));
1750 return (CFTypeRef)NULL;
1753 params->overrideTransform(kSecTransformActionCanExecute, ^{
1754 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("can-x"));
1755 return (CFTypeRef)NULL;
1758 params->overrideAttribute(kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef ah, CFTypeRef value) {
1762 saw_x_start = CFStringHasPrefix((CFStringRef)value, CFSTR("x-start"));
1765 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 88, "saw %@ after NULL", value));
1767 if (post_send_left--) {
1768 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("post-init"));
1772 // The FIRST flow transform should not see x-start (it is the OUTPUT of the flow transform
1773 // before you in the chain), but all the other transforms should see it.
1774 if (params->get(CFSTR("FIRST"), kSecTransformMetaAttributeValue)) {
1776 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "saw bogus x-start on FIRST flow transform"));
1778 params->send(out_ah, kSecTransformMetaAttributeValue, value);
1782 params->send(out_ah, kSecTransformMetaAttributeValue, value);
1784 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "never saw x-start before EOS"));
1785 return (CFTypeRef)kCFNull;
1790 // attempting to put the value in the error string sometimes blows up, so I've left it out.
1791 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "got: value before init"));
1792 return (CFTypeRef)kCFNull;
1794 return (CFTypeRef)value;
1798 // Reliably reproduces with 100000 transforms in our group, but
1799 // not at 1000...doesn't even seem to do it at 50000.
1800 // Likely a timing issue triggered by heavy swapping.
1801 int n_transforms = 100000;
1803 if (!getenv("SUBMISSION_TEST")) {
1804 n_transforms = 10000;
1805 CFfprintf(stderr, "Running the far faster but far less reliable fast test.\nSet the SUBMISSION_TEST environment variable for full testing\n");
1809 CFMutableArrayRef ta = CFArrayCreateMutable(NULL, n_transforms, &kCFTypeArrayCallBacks);
1810 CFErrorRef err = NULL;
1812 for(i = 0; i < n_transforms; ++i) {
1813 SecTransformRef tr = custom_transform(name, cb);
1814 STAssertNil((id)err, @"Failure %@ creating %@ transform", err, name);
1815 CFStringRef l = CFStringCreateWithFormat(NULL, NULL, CFSTR("flow-%d"), i);
1816 SecTransformSetAttribute(tr, kSecTransformTransformName, l, &err);
1817 if (0 == i % 1000) {
1818 CFfprintf(stderr, "Created %@ of %d\n", l, n_transforms);
1821 STAssertNil((id)err, @"Can't set name %@", err);
1822 CFArrayAppendValue(ta, tr);
1823 assert(CFArrayGetCount(ta));
1824 assert(CFArrayGetCount(ta) == i+1);
1827 SecTransformRef prev_tr = NULL;
1828 SecTransformRef group = SecTransformCreateGroupTransform();
1831 while ((cnt = CFArrayGetCount(ta))) {
1832 CFIndex r = arc4random() % cnt;
1833 SecTransformRef tr = CFArrayGetValueAtIndex(ta, r);
1835 SecTransformConnectTransforms(tr, kSecTransformOutputAttributeName, prev_tr, kSecTransformInputAttributeName, group, &err);
1836 STAssertNil((id)err, @"Can't connect %@ to %@", tr, prev_tr);
1837 STAssertNotNil((id)group, @"nil group after connect");
1841 CFArrayRemoveValueAtIndex(ta, r);
1843 if (0 == cnt % 1000) {
1844 CFfprintf(stderr, "%d left to hook up\n", cnt);
1848 CFTypeRef ptl = SecTransformGetAttribute(prev_tr, kSecTransformTransformName);
1849 CFfprintf(stderr, "Setting INPUT for %@\n", ptl);
1850 SecTransformSetAttribute(prev_tr, kSecTransformInputAttributeName, CFSTR("First!"), &err);
1851 STAssertNil((id)err, @"Can't set first's input? %@", err);
1852 SecTransformSetAttribute(prev_tr, CFSTR("FIRST"), kCFBooleanTrue, &err);
1853 STAssertNil((id)err, @"Can't set FIRST? %@", err);
1854 CFTypeRef r = SecTransformExecute(group, &err);
1855 STAssertNil((id)err, @"execution error: %@", err);
1856 STAssertNotNil((id)r, @"result expected from execute");
1861 -(void)testNoDataDescription /* <rdar://problem/7791122> CFShow(SecCustomTransformNoData()) crashes */
1863 CFStringRef result = CFCopyDescription(SecTransformNoData()); // this is called under the hood in CFShow, and it doesn't dump output
1864 STAssertNotNil((id)result, @"SecTransformNoData can be formatted");
1868 static SecTransformInstanceBlock KnownProblemPlumbing(CFStringRef name,
1869 SecTransformRef newTransform,
1870 SecTransformImplementationRef ref)
1872 SecTransformInstanceBlock instanceBlock =
1874 CFErrorRef result = NULL;
1875 // At the moment fully disconnecting a transform from a group leaves it in the group, so it can't have any
1876 // kSecTransformMetaAttributeRequiresOutboundConnection=TRUE attributes (by default OUTPUT requires an outbound connection)
1877 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
1878 kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanFalse);
1880 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName,
1881 ^(SecTransformAttributeRef ah, CFTypeRef value)
1883 return (CFTypeRef)CFErrorCreate(NULL, kCFErrorDomainPOSIX, EOPNOTSUPP, NULL);
1888 return Block_copy(instanceBlock);
1891 -(void)knownProblemPlumbing // note, this test has been disconnected!
1893 SecNullTransformRef a = SecNullTransformCreate();
1894 CFStringRef name = CFSTR("com.apple.security.unit-test.error+outputless");
1895 CFErrorRef err = NULL;
1897 SecTransformRegister(name, &KnownProblemPlumbing, &err);
1899 SecTransformRef b = SecTransformCreate(name, NULL);
1900 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1902 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL);
1903 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName);
1906 CFStringRef data = CFSTR("Test");
1908 SecTransformSetAttribute(a, kSecTransformInputAttributeName, data, NULL);
1909 CFTypeRef result = SecTransformExecute(a, &err);
1911 STAssertEqualObjects((id)data, (id)result, @"Plumbing disconnect failed.");
1912 STAssertNil((id)err, @"Unexpected error=%@", err);
1918 -(void)testUnknownEncodeType {
1919 CFErrorRef err1 = NULL;
1920 CFStringRef invalid_encode_type = CFSTR("no such encoding type ☃✪");
1921 SecTransformRef not_created = SecEncodeTransformCreate(invalid_encode_type, &err1);
1922 STAssertNil((id)not_created, @"Created encode transform with bad type");
1923 STAssertErrorHas((NSError*)err1, @"☃✪", @"Error mentions bad encoding type: %@", err1);
1924 fprintf(stderr, "Err1 = %p\n", err1);
1925 if (err1) CFRelease(err1);
1928 CFErrorRef err2 = NULL;
1929 SecTransformRef no_type_at_create = SecEncodeTransformCreate(NULL, &err2);
1930 fprintf(stderr, "Err2 = %p\n", err2);
1931 STAssertNotNil((id)no_type_at_create, @"should be able to create encoder with unset type, but got error %@", err2);
1933 if (no_type_at_create) {
1934 CFErrorRef err3 = NULL;
1935 SecTransformSetAttribute(no_type_at_create, kSecTransformInputAttributeName, NULL, &err3);
1936 STAssertNil((id)err3, @"Can't set INPUT: %@", err3);
1941 STAssertTrue(SecTransformSetAttribute(no_type_at_create, kSecEncodeTypeAttribute, kSecBase32Encoding, &err3), @"Can't set encode to valid type error: %@", err3);
1942 STAssertFalse(SecTransformSetAttribute(no_type_at_create, kSecEncodeTypeAttribute, invalid_encode_type, &err3), @"Set encode to invalid type, no error signaled", err3);
1943 fprintf(stderr, "Err3 = %p\n", err3);
1944 if (err3) CFRelease(err3);
1946 CFErrorRef err4 = NULL;
1947 CFTypeRef no_result = SecTransformExecute(no_type_at_create, &err4);
1948 STAssertNil((id)no_result, @"Got result when none expected %@");
1949 STAssertNotNil((id)err4, @"No error when one expected");
1950 fprintf(stderr, "Err4 = %p\n", err4);
1951 if (err4) CFRelease(err4);
1953 STFail(@"Unable to run some tests");
1956 CFRelease(no_type_at_create);
1957 CFRelease(invalid_encode_type);
1960 -(void)testNoUnderscores
1962 SecTransformRef zt = SecEncodeTransformCreate(kSecZLibEncoding, NULL);
1963 CFErrorRef err = NULL;
1964 SecTransformSetAttribute(zt, CFSTR("_FAIL"), kCFBooleanTrue, &err);
1965 STAssertNotNil((id)err, @"Expeced an error setting _FAIL");
1966 STAssertErrorHas((id)err, @"_FAIL", @"Expected error to contain _FAIL");
1967 STAssertErrorHas((id)err, @"Encoder", @"Expecting error to name offending transform", err);
1968 CFTypeRef v = SecTransformGetAttribute(zt, CFSTR("_FAIL"));
1969 STAssertNil((id)v, @"Expected nil result, got v=%p", v);
1974 -(void)testCanFetchDigestSizes
1976 NSDictionary *digests = [NSDictionary dictionaryWithObjectsAndKeys:
1977 [NSNumber numberWithInt:128/8], kSecDigestMD2,
1978 [NSNumber numberWithInt:128/8], kSecDigestMD4,
1979 [NSNumber numberWithInt:128/8], kSecDigestMD5,
1980 [NSNumber numberWithInt:160/8], kSecDigestSHA1,
1981 [NSNumber numberWithInt:512/8], kSecDigestSHA2,
1983 NSData *zero = [NSData dataWithBytes:"" length:1];
1985 for (NSString *digestType in digests) {
1986 CFErrorRef err = NULL;
1987 SecTransformRef digest = SecDigestTransformCreate(digestType, 0, &err);
1988 STAssertNotNil((id)digest, @"Expected to make digest (err=%@)", err);
1989 STAssertNil((id)err, @"Unexpected error: %@", err);
1990 NSNumber *actualLength = (NSNumber*)SecTransformGetAttribute(digest, kSecDigestLengthAttribute);
1991 STAssertTrue([actualLength intValue] != 0, @"Got zero length back");
1992 STAssertNotNil(actualLength, @"Expected to get a length");
1993 STAssertEqualObjects(actualLength, [digests objectForKey:digestType], @"Expected lengths to match for %@", digestType);
1995 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, zero, &err);
1996 STAssertNil((id)err, @"Unexpected error: %@", err);
1998 NSData *output = (NSData *)SecTransformExecute(digest, &err);
1999 STAssertNil((id)err, @"Unexpected error: %@", err);
2000 STAssertNotNil((id)output, @"No output");
2002 STAssertEquals([actualLength intValue], (int)[output length], @"Actual output not expected length");
2009 -(void)testBadTransformTypeNames
2011 CFErrorRef error = NULL;
2012 Boolean ok = SecTransformRegister(CFSTR("Not valid: has a col..co...double dot thing"), DelayTransformBlock, &error);
2013 STAssertFalse(ok, @"Register of name with : fails");
2014 STAssertErrorHas((id)error, @":", @"Error mentions invalid character (error=%@)", error);
2016 ok = SecTransformRegister(CFSTR("Not/valid has a slash"), DelayTransformBlock, &error);
2017 STAssertFalse(ok, @"Register of name with / fails");
2018 STAssertErrorHas((id)error, @"/", @"Error mentions invalid character (error=%@)", error);
2020 ok = SecTransformRegister(CFSTR("https://NOT/VALID"), DelayTransformBlock, &error);
2021 STAssertFalse(ok, @"Register of name with : and / fails");
2022 STAssertErrorHas((id)error, @"[:/]", @"Error mentions invalid character (error=%@)", error);
2024 ok = SecTransformRegister(CFSTR("_not valid at start"), DelayTransformBlock, &error);
2025 STAssertFalse(ok, @"Register of _name fails");
2026 STAssertErrorHas((id)error, @"_", @"Error mentions invalid character (error=%@)", error);
2028 ok = SecTransformRegister(CFSTR("it is ok to have a _ after start"), DelayTransformBlock, &error);
2029 STAssertTrue(ok, @"Register of _ IN should have worked (error=%@)", error);
2032 -(void)testExecuteBlock {
2033 unsigned char *raw_data = (unsigned char *)"Just some bytes, you know";
2034 NSData *empty = [NSData dataWithBytes:NULL length:0];
2035 NSData *data = [NSData dataWithBytes:raw_data length:strlen((const char *)raw_data)];
2036 NSUInteger ecnt = [empty retainCount];
2038 SecTransformRef zt = SecEncodeTransformCreate(kSecZLibEncoding, NULL);
2039 SecTransformSetAttribute(zt, kSecTransformInputAttributeName, data, NULL);
2040 dispatch_queue_t q = dispatch_queue_create("com.apple.security.testingQ", NULL);
2041 dispatch_queue_t q_sync = dispatch_queue_create("com.apple.security.testingQ_sync", NULL);
2042 dispatch_suspend((dispatch_object_t)q_sync);
2043 __block BOOL ran_block = NO;
2045 SecTransformExecuteAsync(zt, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
2046 if ([empty length]) {
2047 NSLog(@"Empty data not so empty");
2049 STAssertTrue(dispatch_get_current_queue() == q, @"block dispatched to proper queue");
2056 if (message == NULL) {
2057 dispatch_resume((dispatch_object_t)q_sync);
2061 STAssertTrue(ecnt < [empty retainCount], @"SecTransformExecute retained block");
2062 dispatch_sync(q_sync, ^{ });
2063 STAssertTrue(ran_block, @"Block executed");
2065 dispatch_release(q_sync);
2066 dispatch_release(q);
2070 // STAssertTrue(ecnt == [empty retainCount], @"SecTransformExecute released block");
2073 static SecTransformInstanceBlock ConnectionCheck(CFStringRef name,
2074 SecTransformRef newTransform,
2075 SecTransformImplementationRef ref)
2077 SecTransformInstanceBlock instanceBlock =
2079 CFErrorRef result = NULL;
2080 __block SecTransformMetaAttributeType dir = kSecTransformMetaAttributeValue;
2082 SecTransformAttributeRef out_ah =
2083 SecTranformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef);
2085 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DIRECTION"),
2086 ^(SecTransformAttributeRef ah, CFTypeRef value)
2088 if (CFEqual(value, CFSTR("<")))
2090 dir = kSecTransformMetaAttributeHasInboundConnection;
2092 else if (CFEqual(value, CFSTR(">")))
2094 dir = kSecTransformMetaAttributeHasOutboundConnections;
2098 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unsupported direction %@, expected < or >", value);
2103 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2104 ^(SecTransformAttributeRef ah, CFTypeRef value)
2106 if (dir != kSecTransformMetaAttributeValue)
2110 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue,
2111 SecTranformCustomGetAttribute(ref, value, dir));
2115 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, NULL);
2120 SecTransformPushbackAttribute(ref, ah, value);
2129 return Block_copy(instanceBlock);
2132 -(void)testConnectionChecks {
2134 CFStringRef name = CFSTR("com.apple.security.unit-test.connection-checks");
2135 CFErrorRef error = NULL;
2136 SecTransformRegister(name, &*ConnectionCheck, &error);
2139 NSString *attr, *dir;
2140 CFBooleanRef expect;
2142 {@"INPUT", @"<", kCFBooleanTrue},
2143 {@"OUTPUT", @">", kCFBooleanTrue},
2144 {@"INPUT", @">", kCFBooleanFalse},
2145 {@"OUTPUT", @"<", kCFBooleanFalse},
2146 {@"DIRECTION", @"<", kCFBooleanFalse},
2147 {@"DIRECTION", @">", kCFBooleanFalse},
2150 CFIndex i, n = sizeof(cases)/sizeof(test_case);
2151 for(i = 0; i < n; ++i)
2153 test_case *t = cases + i;
2155 SecTransformRef cct = SecTransformCreate(name, NULL);
2156 SecTransformRef tee0 = SecNullTransformCreate();
2157 SecTransformRef tee1 = SecNullTransformCreate();
2158 SecTransformRef group = SecTransformCreateGroupTransform();
2160 SecTransformSetAttribute(cct, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2161 SecTransformSetAttribute(tee0, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2162 SecTransformSetAttribute(tee1, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2164 SecTransformSetAttribute(tee0, CFSTR("NAME"), CFSTR("tee0"), NULL);
2165 SecTransformSetAttribute(tee1, CFSTR("NAME"), CFSTR("tee1"), NULL);
2167 SecTransformConnectTransforms(cct, CFSTR("OUTPUT"), tee1, CFSTR("INPUT"), group, NULL);
2168 SecTransformConnectTransforms(tee0, CFSTR("OUTPUT"), cct, CFSTR("INPUT"), group, NULL);
2170 SecTransformSetAttribute(cct, CFSTR("DIRECTION"), t->dir, NULL);
2171 SecTransformSetAttribute(tee0, CFSTR("INPUT"), t->attr, NULL);
2172 CFErrorRef err = NULL;
2173 CFTypeRef r = SecTransformExecute(group, &err);
2174 STAssertNil((id)err, @"Error=%@ for case#%d", err, i);
2175 STAssertNotNil((id)r, @"Nil result for case#%d", i);
2176 STAssertEqualObjects((id)(t->expect), (id)r, @"Expected result for case#%d %@%@", i, t->dir, t->attr);
2186 static SecTransformInstanceBlock PushBackTest(CFStringRef name,
2187 SecTransformRef newTransform,
2188 SecTransformImplementationRef ref)
2190 SecTransformInstanceBlock instanceBlock =
2192 CFErrorRef result = NULL;
2193 __block CFStringRef input_d = NULL;
2194 __block CFStringRef data_d = NULL;
2196 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DATA"),
2197 ^(SecTransformAttributeRef ah, CFTypeRef value)
2201 SecTransformPushbackAttribute(ref, ah, value);
2209 data_d = (CFStringRef)CFRetain(value);
2214 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2215 ^(SecTransformAttributeRef ah, CFTypeRef value)
2223 input_d = (CFStringRef)CFRetain(value);
2226 SecTransformPushbackAttribute(ref, ah, value);
2234 SecTransformPushbackAttribute(ref, ah, NULL);
2239 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
2246 return Block_copy(instanceBlock);
2249 -(void)testPushback {
2251 CFStringRef name = CFSTR("com.apple.security.unit-test.basic-pushback");
2252 CFStringRef one = CFSTR("1");
2253 CFStringRef two = CFSTR("2");
2254 CFStringRef expect = CFSTR("12");
2256 // This unit test makes pushback look very complex, but that is because we are abusing it for test purposes.
2257 // normally it is a simple "if I need X before I can go on, and X isn't here yet pushback". Here we attempt
2258 // to carefully sequence 2 attributes to be the inverse of the normal order AND test pushback of NULL as well
2259 // as normal values.
2261 CFErrorRef error = NULL;
2262 SecTransformRegister(name, &PushBackTest, &error);
2264 SecTransformRef pt = SecTransformCreate(name, NULL);
2266 SecTransformSetAttribute(pt, CFSTR("DATA"), two, NULL);
2267 SecTransformSetAttribute(pt, CFSTR("INPUT"), one, NULL);
2269 CFTypeRef result = SecTransformExecute(pt, NULL);
2271 STAssertEqualObjects((id)result, (id)expect, @"Testing pushback");
2275 // NOTE: we want to test doing a double pushback, but that sets the Abort attribute which currently causes an abort not an orderly shutdown
2279 static SecTransformInstanceBlock CustomExternalization(CFStringRef name,
2280 SecTransformRef newTransform,
2281 SecTransformImplementationRef ref)
2283 SecTransformInstanceBlock instanceBlock =
2285 CFErrorRef result = NULL;
2286 // Create a non-attribute 'instance' variable which will contain
2287 // the version number of this class
2289 __block float versionNumber = 1.0;
2291 // Register the custom externalize override
2292 SecTransformActionBlock ExternalizeExtraDataOverride =
2294 CFStringRef key = CFSTR("VersionNumber");
2295 CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &versionNumber);
2297 CFDictionaryRef result = CFDictionaryCreate(kCFAllocatorDefault,
2298 (const void **)&key, (const void **)&value,
2299 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2304 return (CFTypeRef)result;
2307 SecTransformSetTransformAction(ref, kSecTransformActionExternalizeExtraData, ExternalizeExtraDataOverride);
2309 // Register the custom internalize override
2310 SecTransformDataBlock InternalizeExtraDataOverride =
2313 CFTypeRef internalizeResult = NULL;
2316 //STAssertNotNil(testObj, @"Internalize did NOT get a dictionary!");
2318 if (CFDictionaryGetTypeID() == CFGetTypeID(d))
2320 CFStringRef key = CFSTR("VersionNumber");
2321 CFDictionaryRef dict = (CFDictionaryRef)d;
2322 CFNumberRef varsNum = (CFNumberRef)CFDictionaryGetValue(dict, key);
2323 // STAssertNotNil((NSNumber *)varsNum,
2324 // @"Unable to retrieve the dictionary when the internalized data override");
2325 if (NULL != varsNum)
2327 Boolean numResult = CFNumberGetValue(varsNum, kCFNumberFloatType, &versionNumber);
2328 // STAssertTrue(numResult, @"Could not get the version number from the CFNumberRef");
2331 float knownVersion = 1.0;
2332 // STAssertTrue(knownVersion == versionNumber, @"Versions do not Match!");
2336 return internalizeResult;
2338 SecTransformSetDataAction(ref, kSecTransformActionInternalizeExtraData,
2339 InternalizeExtraDataOverride);
2344 return Block_copy(instanceBlock);
2347 /* --------------------------------------------------------------------------
2348 method: testCustomExternalization
2349 description: Test the ability to write out custom external data
2350 -------------------------------------------------------------------------- */
2351 - (void)testCustomExternalization
2353 NSString* ctName = @"com.apple.security.unit-test-customExternalization";
2354 NSError* error = nil;
2356 CFStringRef aName = (CFStringRef)ctName;
2357 CFErrorRef* anError = (CFErrorRef *)&error;
2359 Boolean registerResult = SecTransformRegister(aName, &CustomExternalization, anError);
2360 STAssertTrue(registerResult, @"Unable to register the custom externalization transform");
2362 SecTransformRef externalTrans = SecTransformCreate((CFStringRef)ctName,
2363 (CFErrorRef *)&error);
2365 STAssertNotNil((id)externalTrans, @"Could not create the custom externalization transform");
2367 CFDictionaryRef externalData = SecTransformCopyExternalRepresentation(externalTrans);
2368 STAssertNotNil((NSDictionary *)externalData, @"Did not get a dictionary from SecTransformCopyExternalRepresentation");
2370 CFRelease(externalTrans);
2372 externalTrans = NULL;
2373 externalTrans = SecTransformCreateFromExternalRepresentation(externalData, (CFErrorRef *)&error);
2374 STAssertNotNil((id)externalTrans, @"Could not create the custom external representation");
2375 CFRelease(externalData);
2376 if (NULL != externalTrans)
2378 CFRelease(externalTrans);
2382 static SecTransformInstanceBlock TestString(CFStringRef name,
2383 SecTransformRef newTransform,
2384 SecTransformImplementationRef ref)
2386 SecTransformInstanceBlock instanceBlock =
2388 CFErrorRef result = NULL;
2389 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
2392 CFDataRef d = (CFDataRef)value;
2394 return (CFTypeRef)CFStringCreateWithBytes(NULL, CFDataGetBytePtr(d), CFDataGetLength(d), kCFStringEncodingMacRoman, FALSE);
2396 return (CFTypeRef)d;
2402 return Block_copy(instanceBlock);
2405 -(void)testStringResults {
2406 CFStringRef name = CFSTR("com.apple.security.unit-test.string-converter");
2407 CFErrorRef error = NULL;
2408 SecTransformRegister(name, &TestString, &error);
2410 SecTransformRef sr = SecTransformCreate(name, NULL);
2412 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...";
2413 CFDataRef data = CFDataCreate(NULL, msg, strlen((const char *)msg));
2414 NSString *ns_msg = [NSString stringWithCString:(const char *)msg encoding:NSMacOSRomanStringEncoding];
2416 SecTransformRef er = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
2417 SecTransformRef dr = SecDecodeTransformCreate(kSecBase32Encoding, NULL);
2419 SecTransformSetAttribute(er, kSecTransformInputAttributeName, data, NULL);
2421 SecGroupTransformRef group = SecTransformCreateGroupTransform();
2422 SecTransformConnectTransforms(er, kSecTransformOutputAttributeName, dr, kSecTransformInputAttributeName, group, NULL);
2423 SecTransformConnectTransforms(dr, kSecTransformOutputAttributeName, sr, kSecTransformInputAttributeName, group, NULL);
2426 CFStringRef result = (CFStringRef)SecTransformExecute(sr, NULL);
2427 STAssertEqualObjects(ns_msg, (NSString *)result, @"string results");
2440 CFNumberRef MakeNumber1(long n)
2442 return CFNumberCreate(NULL, kCFNumberLongType, &n);
2447 static SecTransformInstanceBlock TestRegisterCreate(CFStringRef name,
2448 SecTransformRef newTransform,
2449 SecTransformImplementationRef ref)
2453 SecTransformInstanceBlock instanceBlock =
2455 __block long count = 0;
2457 __block CFNumberRef countNum = MakeNumber1(count);;
2458 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum);
2459 CFRelease(countNum);
2460 fprintf(stderr, "countNum = %p\n", countNum);
2462 CFErrorRef result = NULL;
2463 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
2466 CFDataRef d = (CFDataRef)value;
2469 count += CFDataGetLength(d);
2471 CFNumberRef countNum2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &count);
2472 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum2);
2473 CFRelease(countNum2);
2474 fprintf(stderr, "countNum = %p\n", countNum);
2478 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, NULL);
2487 return Block_copy(instanceBlock);
2490 - (void)testRegisterCreate
2492 CFStringRef name = CFSTR("com.apple.security.unit-test.novel-unique-at-least-unusual-name");
2494 CFNumberRef countNum = NULL;
2495 CFErrorRef error = NULL;
2496 Boolean ok = SecTransformRegister(name, &TestRegisterCreate, &error);
2497 STAssertTrue(ok, @"Successful register");
2499 SecTransformRef tr = SecTransformCreate(name, NULL);
2500 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
2501 SecTransformSetAttribute(tr, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2503 char *data_bytes = (char *)"It was the best of transforms, it was the worst of transforms.";
2504 CFDataRef data = CFDataCreate(NULL, (const UInt8 *)data_bytes, strlen(data_bytes));
2506 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
2508 SecTransformRef nt = SecNullTransformCreate();
2509 SecTransformRef tg = SecTransformCreateGroupTransform();
2510 SecTransformConnectTransforms(tr, CFSTR("OUTPUT"), nt, CFSTR("DISCARD"), tg, &error);
2511 STAssertNil((id)error, @"Connected tr's output to nt's discard: %@", error);
2512 SecTransformConnectTransforms(tr, CFSTR("Count"), nt, CFSTR("INPUT"), tg, &error);
2513 STAssertNil((id)error, @"Connected tr's count to nt's input: %@", error);
2515 SecTransformSetAttribute(nt, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2518 countNum = (CFNumberRef)SecTransformGetAttribute(tr, CFSTR("Count"));
2519 CFNumberGetValue(countNum, kCFNumberLongType, &count);
2520 CFRelease(countNum);
2521 STAssertTrue(count == 0, @"length unchanged before execute");
2523 countNum = (CFNumberRef)SecTransformExecute(tg, NULL);
2524 STAssertNotNil((id)countNum, @"Got result from execute");
2525 STAssertEquals(CFGetTypeID(countNum), CFNumberGetTypeID(), @"expected a number from execute");
2526 CFNumberGetValue(countNum, kCFNumberLongType, &count);
2527 CFRelease(countNum);
2529 STAssertTrue(count == CFDataGetLength(data), @"Wrong data length");
2538 static SecTransformInstanceBlock CountTransformTest(CFStringRef name,
2539 SecTransformRef newTransform,
2540 SecTransformImplementationRef ref)
2542 SecTransformInstanceBlock instanceBlock =
2544 CFErrorRef result = NULL;
2545 SecTransformSetAttributeAction(ref,kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2546 ^(SecTransformAttributeRef ah, CFTypeRef value)
2549 if (CFGetTypeID(value) != CFNumberGetTypeID()) {
2550 SecTransformCustomSetAttribute(ref, CFSTR("ABORT"), kSecTransformMetaAttributeValue, CFSTR("Bad type"));
2553 CFNumberRef nr = (CFNumberRef)value;
2555 CFNumberGetValue(nr, kCFNumberIntType, &max);
2556 for(i = 0; i < max; ++i) {
2557 nr = CFNumberCreate(NULL, kCFNumberIntType, &i);
2558 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, nr);
2562 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
2571 return Block_copy(instanceBlock);
2574 SecTransformRef count_transform(int n) {
2575 CFStringRef name = CFSTR("com.apple.security.unit-test.count");
2576 static dispatch_once_t once;
2578 dispatch_once(&once,
2580 SecTransformRegister(name, &CountTransformTest, NULL);
2583 SecTransformRef ct = SecTransformCreate(name, NULL);
2584 CFNumberRef num = CFNumberCreate(NULL, kCFNumberIntType, &n);
2585 SecTransformSetAttribute(ct, CFSTR("INPUT"), num, NULL);
2592 static SecTransformInstanceBlock StallTest(CFStringRef name,
2593 SecTransformRef newTransform,
2594 SecTransformImplementationRef ref)
2596 SecTransformInstanceBlock instanceBlock =
2598 CFErrorRef result = NULL;
2599 __block bool go = false;
2601 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("GO"),
2602 ^(SecTransformAttributeRef ah, CFTypeRef value)
2608 SecTransformAttributeRef in_ah = SecTransformCustomGetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeRef);
2609 SecTransformAttributeRef out_ah = SecTransformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef);
2611 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL,
2612 ^(SecTransformAttributeRef ah, CFTypeRef value)
2615 SecTransformPushbackAttribute(ref, ah, value);
2618 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, value);
2627 return Block_copy(instanceBlock);
2631 CFStringRef name = CFSTR("com.apple.security.unit-test.stall");
2633 (void)SecTransformRegister(name, &StallTest, NULL);
2635 SecTransformRef stall = SecTransformCreate(name, NULL);
2636 SecTransformRef seven = count_transform(7);
2637 SecTransformRef group = SecTransformCreateGroupTransform();
2638 SecTransformRef delay = delay_transform(NSEC_PER_SEC / 10);
2640 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("FOO"), group, NULL);
2641 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("BAR"), group, NULL);
2642 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("BAZ"), group, NULL);
2643 SecTransformConnectTransforms(seven, CFSTR("OUTPUT"), stall, CFSTR("INPUT"), group, NULL);
2644 SecTransformConnectTransforms(delay, CFSTR("OUTPUT"), stall, CFSTR("GO"), group, NULL);
2646 SecTransformSetAttribute(delay, CFSTR("INPUT"), (CFNumberRef)[NSNumber numberWithInt:42], NULL);
2648 CFErrorRef err = NULL;
2649 CFTypeRef r = SecTransformExecute(group, &err);
2651 STAssertNotNil((id)r, @"Results from testStall");
2652 STAssertNil((id)err, @"Got %@ error from testStall", err);
2653 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];
2654 STAssertEqualObjects((id)r, array_seven, @"Correct stall test results");
2662 -(void)testInappropriateExecution
2664 // We want to have more then enough work for all the CPUs to help force a race, so twice
2665 // the number of logical CPUs should do it. NOTE: the completion blocks got to a low
2666 // priority concurrent queue to encourage them to finish out of order and put more
2667 // stress on the system we are testing.
2669 int logical_cpus = 1;
2670 size_t int_size = sizeof(logical_cpus);
2671 int return_code = sysctlbyname("hw.logicalcpu_max", &logical_cpus, &int_size, NULL, 0);
2672 int e = errno; // Save this value so it doesn't get trashed by any subsequent syscalls
2673 STAssertEquals(return_code, 0, @"sysctlbyname failed %s (%d), assuming 1 CPU", strerror(e), e);
2675 SecTransformRef count_a_bunch = count_transform(logical_cpus * 2);
2676 CFErrorRef err = NULL;
2677 dispatch_group_t wait_for_async_to_complete = dispatch_group_create();
2678 dispatch_group_t outstanding_executions = dispatch_group_create();
2679 SecTransformRef count_group = SecTransformCreateGroupTransform();
2681 SecTransformConnectTransforms(count_a_bunch, CFSTR("kludge1"), count_a_bunch, CFSTR("kludge2"), count_group, &err);
2682 STAssertNil((id)err, @"Error (%@) connecting count transform to itself", err);
2684 dispatch_group_enter(wait_for_async_to_complete);
2685 SecTransformExecuteAsync(count_a_bunch, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
2687 dispatch_group_enter(outstanding_executions);
2689 CFErrorRef err = NULL;
2690 CFTypeRef no_result = SecTransformExecute(count_a_bunch, &err);
2691 STAssertNil((id)no_result, @"Attempting to execute an already executing transform should fail, not provide results: %@", no_result);
2692 STAssertNotNil((id)err, @"Attempting to execute an already executing transform should produce some sort of error");
2695 dispatch_group_leave(outstanding_executions);
2699 // Give any pending executions time to get to the group_enter
2701 dispatch_group_wait(outstanding_executions, DISPATCH_TIME_FOREVER);
2702 dispatch_release(outstanding_executions);
2703 dispatch_group_leave(wait_for_async_to_complete);
2707 // Before that SecTransformExecuteAsync completes, we do some more work at >low priority to help
2708 // keep the completion blocks landing out of order. In particular we run a transform to
2709 // completion, and then confirm that we can't run it again.
2711 SecTransformRef no_work = SecNullTransformCreate();
2712 SecTransformRef no_work_group = SecTransformCreateGroupTransform();
2713 SecTransformConnectTransforms(no_work, CFSTR("kludge1"), no_work, CFSTR("kludge2"), no_work_group, &err);
2714 STAssertNil((id)err, @"Can't connect no_work to itself (to make no_work_group), err=%@", err);
2716 SecTransformSetAttribute(no_work, CFSTR("INPUT"), CFSTR("value"), NULL);
2717 CFTypeRef no_result = SecTransformExecute(no_work_group, &err);
2718 STAssertNil((id)err, @"First execute of Null Transform should be ok, got e=%@", err);
2719 STAssertNotNil((id)no_result, @"First execute of Null Transform should produce a value");
2721 no_result = SecTransformExecute(no_work_group, &err);
2723 STAssertNotNil((id)err, @"Second execute of Null Transform should fail!");
2724 STAssertNil((id)no_result, @"Second execute of Null Transform shouldn't produce a value, got r=%@", no_result);
2727 // Now we wait for that first batch of tests to finish, we don't want to call STFail after self goes away.
2729 dispatch_group_wait(wait_for_async_to_complete, DISPATCH_TIME_FOREVER);
2730 dispatch_release(wait_for_async_to_complete);
2732 if (no_result) CFRelease(no_result);
2733 if (no_work) CFRelease(no_work);
2734 if (no_work_group) CFRelease(no_work_group);
2735 if (count_group) CFRelease(count_group);
2736 if (count_a_bunch) CFRelease(count_a_bunch);
2739 static SecTransformInstanceBlock ConnectionReqTest(CFStringRef name,
2740 SecTransformRef newTransform,
2741 SecTransformImplementationRef ref)
2743 SecTransformInstanceBlock instanceBlock =
2745 CFErrorRef result = NULL;
2746 SecTransformAttributeRef xah =
2747 (SecTransformAttributeRef)SecTranformCustomGetAttribute(ref, CFSTR("XYZZY"), kSecTransformMetaAttributeRef);
2749 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanTrue);
2750 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanFalse);
2751 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2752 ^(SecTransformAttributeRef ah, CFTypeRef value)
2754 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeValue, value);
2761 return Block_copy(instanceBlock);
2765 -(void)testConnectionReq {
2767 CFStringRef req_xyzzy_name = CFSTR("com.apple.security.unit-test.req_xyzzy");
2769 (void)SecTransformRegister(req_xyzzy_name, &ConnectionReqTest, NULL);
2771 SecTransformRef tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL);
2773 CFTypeRef in_value = (CFTypeRef)@"Fnord";
2774 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL);
2776 CFErrorRef err = NULL;
2777 CFTypeRef r = SecTransformExecute(tr_req_xyzzy, &err);
2779 STAssertNil((id)r, @"Execute of tr_req_xyzzy with no xyzzy r=%@", r);
2780 STAssertErrorHas((id)err, @"req_xyzzy", @"Error failed to refer to the transform by name (%@)", err);
2781 STAssertErrorHas((id)err, @"XYZZY", @"Error failed to refer to missing attribute by name (%@)", err);
2782 STAssertErrorHas((id)err, @"requires.*outbound connection", @"Error failed to diagnose invalid condition (%@)", err);
2785 CFRelease(tr_req_xyzzy);
2786 if (r) CFRelease(r);
2792 To make this work we need Josh's fix for FindLastTransform!
2794 CFRelease(tr_req_xyzzy);
2795 tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL);
2796 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL);
2798 SecTransformRef group = SecTransformCreateGroupTransform();
2799 SecTransformRef tee = SecNullTransformCreate();
2800 SecTransformConnectTransforms(tr_req_xyzzy, CFSTR("XYZZY"), tee, kSecTransformInputAttributeName, group, &err);
2801 STAssertNil((id)err, @"err=%@ from connect", err);
2802 STAssertNotNil((id)group, @"No group after connect");
2803 r = SecTransformExecute(group, &err);
2804 STAssertNil((id)err, @"Execute err=%@");
2805 STAssertEqualObjects((id)in_value, (id)r, @"Execution Result");
2810 static SecTransformInstanceBlock DeferredTest(CFStringRef name,
2811 SecTransformRef newTransform,
2812 SecTransformImplementationRef ref)
2814 SecTransformInstanceBlock instanceBlock =
2816 CFErrorRef result = NULL;
2817 SecTransformCustomSetAttribute(ref, CFSTR("LATE"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
2818 SecTransformCustomSetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeDeferred, kCFBooleanFalse);
2820 __block CFTypeRef in_v = NULL, late_v = NULL;
2822 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2823 ^(SecTransformAttributeRef ah, CFTypeRef value)
2825 if (NULL != late_v) {
2826 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue,
2827 CreateGenericErrorRef(CFSTR("FAIL"), 1, "LATE (%@) should process after INPUT (%@)", late_v, value));
2833 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("LATE"),
2834 ^(SecTransformAttributeRef ah, CFTypeRef value)
2837 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue,
2838 CreateGenericErrorRef(CFSTR("FAIL"), 1, "INPUT (%@) should process before LATE (%@)", in_v, value));
2842 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, NULL);
2849 return Block_copy(instanceBlock);
2853 -(void)testDeferred {
2854 CFStringRef deferred_name = CFSTR("com.apple.security.unit-test.deferred");
2856 (void)SecTransformRegister(deferred_name, &DeferredTest, NULL);
2858 SecTransformRef dt = SecTransformCreate(deferred_name, NULL);
2860 // these set attribute calls are failing, but we're ignoring the failures
2861 SecTransformSetAttribute(dt, CFSTR("INPUT"), (CFTypeRef)CFSTR("BLAH"), NULL);
2862 SecTransformSetAttribute(dt, CFSTR("LATE"), (CFTypeRef)CFSTR("QUUX"), NULL);
2863 CFErrorRef err = NULL;
2864 SecTransformExecute(dt, &err);
2865 STAssertNil((id)err, @"Error from execute err=%@", err);
2867 if (err) CFRelease(err);
2871 static SecTransformInstanceBlock SaveRestoreTest(CFStringRef name,
2872 SecTransformRef newTransform,
2873 SecTransformImplementationRef ref)
2875 SecTransformInstanceBlock instanceBlock =
2877 CFErrorRef result = NULL;
2878 SecTransformCustomSetAttribute(ref, CFSTR("Needed"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
2879 SecTransformCustomSetAttribute(ref, CFSTR("NoSaves"), kSecTransformMetaAttributeExternalize, kCFBooleanFalse);
2884 return Block_copy(instanceBlock);
2887 -(void)testSaveRestore
2890 unsigned char raw_data[] = "Val-U-Sav, nw wth lss vwls!";
2891 CFDataRef data = CFDataCreate(NULL, (const UInt8*)&raw_data, sizeof(raw_data));
2892 CFErrorRef err = NULL;
2894 CFStringRef name = CFSTR("com.apple.security.unit-test.SaveRestoreTest");
2896 (void)SecTransformRegister(name, &SaveRestoreTest, NULL);
2898 SecTransformRef tr1 = SecTransformCreate(name, NULL);
2900 SecTransformSetAttribute(tr1, CFSTR("Optional"), CFSTR("42"), NULL);
2901 SecTransformSetAttribute(tr1, CFSTR("Needed"), CFSTR("and provided"), NULL);
2902 SecTransformSetAttribute(tr1, CFSTR("NoSaves"), CFSTR("42"), NULL);
2904 CFDictionaryRef xr = SecTransformCopyExternalRepresentation(tr1);
2905 STAssertNotNil((NSDictionary *)xr, @"external rep");
2906 SecTransformRef tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL);
2907 SecTransformSetAttribute(tr2, kSecTransformInputAttributeName, data, NULL);
2908 CFTypeRef none = SecTransformGetAttribute(tr2, CFSTR("NoSaves"));
2909 STAssertNil((id)none, @"Expected %@ to be nil", none);
2910 CFTypeRef forty_two = SecTransformGetAttribute(tr2, CFSTR("Optional"));
2911 STAssertEqualObjects((id)forty_two, @"42", @"restored incorrect value");
2913 CFDataRef d = (CFDataRef)SecTransformExecute((NSObject *)tr2, &err);
2915 STAssertNotNil((NSData * )d, @"execute result (err=%@)", err);
2925 tr1 = SecTransformCreate(name, NULL);
2926 SecTransformSetAttribute(tr1, CFSTR("Needed"), CFSTR("and provided"), NULL);
2927 SecTransformSetAttribute(tr1, CFSTR("NoSaves"), CFSTR("42"), NULL);
2928 xr = SecTransformCopyExternalRepresentation(tr1);
2929 tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL);
2933 //tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL);
2934 SecTransformRef tga = SecTransformCreateGroupTransform();
2935 SecTransformSetAttribute(tr1, kSecTransformInputAttributeName, data, NULL);
2938 SecTransformConnectTransforms(tr1, CFSTR("OUTPUT"), tr2, CFSTR("INPUT"), tga, NULL);
2939 CFStringRef has1 = CFSTR("I has one!");
2940 CFStringRef has2 = CFSTR("I has two of them!");
2941 SecTransformSetAttribute(tr1, CFSTR("Needed"), has1, NULL);
2942 SecTransformSetAttribute(tr2, CFSTR("Needed"), has2, NULL);
2943 xr = SecTransformCopyExternalRepresentation(tr1);
2944 STAssertNotNil((NSDictionary *)xr, @"external rep for 2");
2945 NSLog(@"xr=%@", xr);
2947 SecTransformRef tgb = SecTransformCreateFromExternalRepresentation(xr, &err);
2948 STAssertNil((id)tgb, @"made transform group with duplicate labels");
2949 STAssertErrorHas((id)err, (NSString*)name, @"Error failed to identify the transform (%@)", err);
2950 STAssertErrorHas((id)err, @"damage|duplicate", @"Error failed to diagnose the invalid condition (%@)", err);
2952 CFStringRef new_name2 = CFSTR("SaveRestoreTestThingie#2");
2953 CFStringRef fetched_name;
2956 for(attempts = 0; attempts < 20; ++attempts)
2958 SecTransformSetAttribute(tr2, CFSTR("NAME"), new_name2, &err);
2959 fetched_name = (CFStringRef)SecTransformGetAttribute(tr2, CFSTR("NAME"));
2961 STAssertNil((id)err, @"Error from setting tr2's name: %@", err);
2962 STAssertEqualObjects((id)fetched_name, (id)new_name2, @"Set tr2's name, attempt %d", attempts);
2963 if (CFEqual(fetched_name, new_name2))
2973 xr = SecTransformCopyExternalRepresentation(tr1);
2974 STAssertNotNil((NSDictionary *)xr, @"external rep for 2, take 2");
2975 NSLog(@"xr=%@", xr);
2977 tgb = SecTransformCreateFromExternalRepresentation(xr, &err);
2978 STAssertNotNil((id)tgb, @"made transform group (take 2)");
2979 STAssertNil((id)err, @"error from make 2 take 2 (err=%@)", err);
2981 SecTransformRef tr1b = SecTransformFindByName(tgb, (CFStringRef)SecTransformGetAttribute(tr1, CFSTR("NAME")));
2982 STAssertNotNil((id)tr1b, @"Found tr1b");
2983 SecTransformRef tr2b = SecTransformFindByName(tgb, (CFStringRef)SecTransformGetAttribute(tr2, CFSTR("NAME")));
2984 STAssertNotNil((id)tr2b, @"Found tr2b");
2986 CFStringRef has1b = (CFStringRef)SecTransformGetAttribute(tr1b, CFSTR("Needed"));
2987 STAssertNotNil((id)tr1b, @"tr1b's name");
2988 CFStringRef has2b = (CFStringRef)SecTransformGetAttribute(tr2b, CFSTR("Needed"));
2989 STAssertNotNil((id)tr2b, @"tr1b's name");
2991 STAssertEqualObjects((id)has1, (id)has1b, @"has1 == has1b");
2992 STAssertEqualObjects((id)has2, (id)has2b, @"has2 == has2b");
2996 -(void)testRequiredAttributes
2998 CFStringRef name = CFSTR("com.apple.security.unit-test.requiresStuffThings");
3000 // In addition to testing required attributes, this also does a partial "lifecycle" test, making sure we
3001 // pass through the stages, don't regress stages, and don't receive the wrong events in the wrong stages.
3002 typedef enum { S_INITED = 0, S_STARTED, S_RUN, S_EOS, S_GONE } state_t;
3004 __block state_t state = S_INITED;
3005 dispatch_group_t leave_on_finalize = dispatch_group_create();
3007 SecTransformCreateBlock required_attributes_create_block = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) {
3008 params->overrideAttribute(kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef attribute, CFTypeRef value) {
3009 // NOTE: this is for testing with a single data value, not a series.
3012 STAssertTrue(state == S_STARTED, @"Init'ed for data (state=%d)", state);
3015 STAssertTrue(state == S_RUN, @"In run state at EOS (state=%d)", state);
3018 params->send(kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
3022 params->send(CFSTR("Stuff"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
3023 params->send(CFSTR("Things"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
3025 params->overrideTransform(kSecTransformActionStartingExecution, ^{
3026 STAssertTrue(state == S_INITED, @"Inited (state=%d)");
3028 return (CFTypeRef)NULL;
3031 params->overrideTransform(kSecTransformActionFinalize, ^{
3033 dispatch_group_leave(leave_on_finalize);
3034 return (CFTypeRef)NULL;
3038 dispatch_group_enter(leave_on_finalize);
3039 SecTransformRef tr = custom_transform(name, required_attributes_create_block);
3040 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
3042 char *data_bytes = (char *)"It was the best of transforms, it was the worst of transforms.";
3043 CFDataRef data = CFDataCreate(NULL, (const UInt8*)data_bytes, strlen(data_bytes));
3044 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
3046 STAssertTrue(state == S_INITED, @"not run yet");
3047 CFDataRef rdata = (CFDataRef)SecTransformExecute((NSObject *)tr, &error);
3049 STAssertTrue(rdata == NULL, @"Expected no result, but got: %@", rdata);
3050 STAssertErrorHas((id)error, @"missing required attributes?", @"Error describes condition (%@)", error);
3051 STAssertErrorHas((id)error, @" Things[ ,)]", @"Missing attributes named (%@)", error);
3052 STAssertErrorHas((id)error, @" Stuff[ ,)]", @"Missing attributes named (%@)", error);
3053 STAssertErrorHas((id)error, @"requiresStuffThings", @"Name of erroring Transform in message (%@)", error);
3060 STAssertFalse(dispatch_group_wait(leave_on_finalize, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"group was ready");
3061 STAssertTrue(state == S_GONE, @"Transform should be gone, state=%d", state);
3063 dispatch_group_enter(leave_on_finalize);
3065 tr = custom_transform(name, required_attributes_create_block);
3066 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
3069 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
3070 SecTransformSetAttribute(tr, CFSTR("Things"), CFSTR("grubby things"), NULL);
3071 SecTransformSetAttribute(tr, CFSTR("Stuff"), CFSTR("Cool stuff"), NULL);
3072 rdata = (CFDataRef)SecTransformExecute(tr, &error);
3074 STAssertNotNil((NSData *)rdata, @"Got data back");
3075 STAssertEqualObjects((NSData *)rdata, (NSData *)data, @"Data unchanged");
3076 STAssertTrue(state == S_EOS, @"Transform hit EOS");
3077 STAssertTrue(error == NULL, @"Error not set");
3080 STAssertFalse(dispatch_group_wait(leave_on_finalize, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"group was ready");
3081 STAssertTrue(state == S_GONE, @"Transform gone (state=%d)", state);
3082 dispatch_group_notify(leave_on_finalize, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
3083 dispatch_release(leave_on_finalize);
3087 static SecTransformInstanceBlock AttributeNotificationTest(CFStringRef name,
3088 SecTransformRef newTransform,
3089 SecTransformImplementationRef ref)
3091 SecTransformInstanceBlock instanceBlock =
3093 CFErrorRef result = NULL;
3096 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL,
3097 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3099 SecTransformCustomSetAttribute(ref, CFSTR("Generic"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3103 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("Specific"),
3104 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3106 SecTransformCustomSetAttribute(ref, CFSTR("Specific"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3111 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("AlsoSpecific"),
3112 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3114 SecTransformCustomSetAttribute(ref, CFSTR("AlsoSpecific"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3122 return Block_copy(instanceBlock);
3125 -(void)testAttributeNotifications
3127 NSString *name = @"com.apple.security.unit-test.testAttributeNotifications";
3128 Boolean generic_called = NO;
3129 Boolean specific_called = NO;
3130 Boolean also_specific_called = NO;
3132 Boolean ok = SecTransformRegister((CFStringRef)name, &AttributeNotificationTest, NULL);
3134 STAssertTrue(ok, @"Successful register");
3136 SecTransformRef tr = SecTransformCreate((CFStringRef)name, NULL);
3138 CFStringRef aNameStr = ((CFStringRef)name);
3139 SecTransformSetAttribute(tr, CFSTR("Generic"), aNameStr, NULL);
3140 SecTransformSetAttribute(tr, CFSTR("Specific"), aNameStr, NULL);
3141 SecTransformSetAttribute(tr, CFSTR("AlsoSpecific"), aNameStr, NULL);
3143 generic_called = (kCFBooleanTrue == (CFBooleanRef)SecTransformGetAttribute(tr, CFSTR("Generic")));
3144 specific_called = (kCFBooleanTrue == (CFBooleanRef)SecTransformGetAttribute(tr, CFSTR("Specific")));
3145 also_specific_called = (kCFBooleanTrue == (CFBooleanRef)SecTransformGetAttribute(tr, CFSTR("AlsoSpecific")));
3148 STAssertTrue(generic_called, @"generic called");
3149 STAssertTrue(specific_called, @"specific called");
3150 STAssertTrue(also_specific_called, @"also specific called");
3155 -(void)testEncryptAndDecryptTransforms
3157 NSAutoreleasePool *pool = [NSAutoreleasePool new];
3159 // generate a symmetrical key for testing
3160 OSStatus err = errSecSuccess;
3162 NSString* algNames[] =
3173 CSSM_ALGORITHMS symmetricalAlgos[] =
3179 CSSM_ALGID_3DES_3KEY_EDE,
3195 CSSM_KEYUSE keyUse = CSSM_KEYUSE_ANY;
3196 CSSM_KEYATTR_FLAGS keyAttrFlags = CSSM_KEYATTR_RETURN_DEFAULT;
3197 SecAccessRef accessRef = NULL;
3198 CSSM_CC_HANDLE handle = ((CSSM_CC_HANDLE)0);
3200 NSString* dataStr = @"At the round earth's imagined corners blow\
3201 Your trumpets, angels, and arise, arise\
3202 From death, you numberless infinities\
3203 Of souls, and to your scattered bodies go,\
3204 All whom the flood did, and fire shall, overthrow,\
3205 All whom war, dearth, age, agues, tyrannies,\
3206 Despair, law, chance, hath slain, and you whose eyes\
3207 Shall behold God, and never taste death's woe.\
3208 But let them sleep, Lord, and me mourn a space,\
3209 For, if above all these my sins abound,\
3210 'Tis late to ask abundance of Thy grace,\
3211 When we are there. Here on this lowly ground\
3212 Teach me how to repent; for that's as good\
3213 As if Thou'dst sealed my pardon, with Thy blood.";
3215 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
3216 int numItems = (sizeof(symmetricalAlgos) / sizeof(CSSM_ALGORITHMS));
3219 for (iCnt = 0; iCnt < numItems; iCnt++)
3221 SecKeyRef testKey = NULL;
3222 CSSM_ALGORITHMS algoToUse = symmetricalAlgos[iCnt];
3223 uint32 keySizeInBits = keySizes[iCnt];
3225 err = SecKeyGenerate(NULL, algoToUse, keySizeInBits, handle, keyUse, keyAttrFlags, accessRef, &testKey);
3226 STAssertTrue(err == errSecSuccess, [NSString stringWithFormat:@"Unable to create a symmetrical key %@", algNames[iCnt]]);
3227 if (errSecSuccess != err)
3231 __block CFErrorRef error = NULL;
3233 SecTransformRef encryptSymRef = NULL;
3234 encryptSymRef = SecEncryptTransformCreate(testKey, &error);
3238 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key %@", algNames[iCnt]]);
3242 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error);
3246 CFRelease(encryptSymRef);
3247 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key %@", algNames[iCnt]]);
3251 // connect the output of the encryption to the input of the decryption transform
3253 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3254 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName,
3255 decryptSymRef, kSecTransformInputAttributeName,
3260 CFRelease(encryptSymRef);
3261 CFRelease(decryptSymRef);
3262 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key %@", algNames[iCnt]]);
3267 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3270 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3274 CFRelease(encryptSymRef);
3275 CFRelease(decryptSymRef);
3276 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to set the input for key %@", algNames[iCnt]]);
3280 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3282 CFRelease(encryptSymRef);
3283 CFRelease(decryptSymRef);
3287 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for algo %@", algNames[iCnt]]);
3292 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3294 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for %@", algNames[iCnt]]);
3298 NSData* resultData = nil;
3299 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3301 resultData = (NSData*)transformResult;
3302 [resultData autorelease];
3307 STAssertTrue([testData isEqualToData:resultData], @"The output of the decrypt transform does NOT match the original input!");
3311 SecKeyRef publicKey = NULL;
3312 SecKeyRef privateKey = NULL;
3314 keyAttrFlags = CSSM_KEYATTR_RETURN_REF;
3316 const uint32 publicKeyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF;
3317 const uint32 privateKeyAttributes = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE;
3319 CSSM_KEYUSE pubKeyUse = CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP;
3320 CSSM_KEYUSE privKeyUse = CSSM_KEYUSE_SIGN | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP;
3323 err = SecKeyCreatePair(NULL, CSSM_ALGID_RSA, 2048, ((CSSM_CC_HANDLE)0),
3324 pubKeyUse, publicKeyAttributes,
3325 privKeyUse, privateKeyAttributes,
3326 NULL, &publicKey, &privateKey);
3328 STAssertTrue(errSecSuccess == err, @"Unable to create a key pair");
3329 if (errSecSuccess != err)
3331 cssmPerror(NULL, err);
3335 CFErrorRef error = NULL;
3336 SecTransformRef encryptSymRef = SecEncryptTransformCreate(publicKey , &error);
3339 CFRelease(publicKey);
3340 CFRelease(privateKey);
3341 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key RSA"]);
3345 SecTransformRef decryptSymRef = SecDecryptTransformCreate(privateKey, &error);
3348 CFRelease(publicKey);
3349 CFRelease(privateKey);
3350 CFRelease(encryptSymRef);
3351 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key RSA"]);
3355 // connect the output of the encryption to the input of the decryption transform
3357 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3358 (void)SecTransformConnectTransforms( encryptSymRef, kSecTransformOutputAttributeName,
3359 decryptSymRef, kSecTransformInputAttributeName,
3363 CFRelease(publicKey);
3364 CFRelease(privateKey);
3365 CFRelease(encryptSymRef);
3366 CFRelease(decryptSymRef);
3367 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key RSA"]);
3371 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3374 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3377 CFRelease(publicKey);
3378 CFRelease(privateKey);
3379 CFRelease(encryptSymRef);
3380 CFRelease(decryptSymRef);
3381 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to set the input for key RSA"]);
3384 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3387 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for RSA"]);
3392 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3394 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for RSA"]);
3398 NSData* resultData = nil;
3399 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3401 resultData = (NSData*)transformResult;
3402 [resultData autorelease];
3405 CFRelease(publicKey);
3406 CFRelease(privateKey);
3407 CFRelease(encryptSymRef);
3408 CFRelease(decryptSymRef);
3410 STAssertTrue([testData isEqualToData:resultData], @"(RSA)The output of the decrypt transform does NOT match the original input!");
3415 // NOTE: this test is largely the same as testEncryptAndDecryptTransforms, but
3416 // we make a single key and use it from many threads at once. This uncovered
3417 // some locking issues, so makes a good regression test.
3418 -(void)testMultiEncryptWithSameKey {
3419 // generate a symmetrical key for testing
3420 CSSM_KEYUSE keyUse = CSSM_KEYUSE_ANY;
3421 CSSM_KEYATTR_FLAGS keyAttrFlags = CSSM_KEYATTR_RETURN_DEFAULT;
3422 SecAccessRef accessRef = NULL;
3423 CSSM_CC_HANDLE handle = ((CSSM_CC_HANDLE)0);
3425 NSString* dataStr = @"Reduce, reuse, recycle. No crashes please.";
3426 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
3428 SecKeyRef testKey = NULL;
3431 err = SecKeyGenerate(NULL, CSSM_ALGID_AES, 256, handle, keyUse, keyAttrFlags, accessRef, &testKey);
3432 STAssertTrue(err == errSecSuccess, @"Unable to create a symmetrical key err=%x", err);
3435 // The number of iterations is somewhat arbitrary. When we use to have failures they were
3436 // within 2*#logicalCPUs iterations, but nothing says we won't have a regression that happens
3437 // outside that window.
3438 dispatch_apply(128, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) {
3439 __block CFErrorRef error = NULL;
3441 SecTransformRef encryptSymRef = NULL;
3442 encryptSymRef = SecEncryptTransformCreate(testKey, &error);
3445 STFail(@"Unable to create the encrypt transform iteration#%d error=%@", i, error);
3448 if (NULL == encryptSymRef) {
3449 STFail(@"Unable to create the encrypt transform iteration#%d, error=NULL", i);
3453 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error);
3456 CFRelease(encryptSymRef);
3457 STFail(@"Unable to create the decrypt transform iteration#%d error=%@", i, error);
3460 if (NULL == decryptSymRef) {
3461 CFRelease(encryptSymRef);
3462 STFail(@"Unable to create the decrypt transform iteration#%d, error=NULL", i);
3466 // connect the output of the encryption to the input of the decryption transform
3468 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3469 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName,
3470 decryptSymRef, kSecTransformInputAttributeName,
3474 CFRelease(encryptSymRef);
3475 CFRelease(decryptSymRef);
3476 STFail(@"Unable to connect transforms on iteration %d error=%@", i, error);
3481 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3484 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3487 CFRelease(encryptSymRef);
3488 CFRelease(decryptSymRef);
3489 STFail(@"Unable to set the input on iteration %d error=%@", i, error);
3493 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3498 STFail(@"returned an error on iteration %d error=%@", i, error);
3503 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3505 STFail(@"transformResult was NULL or empty for iteration %d", i);
3509 NSData* resultData = nil;
3510 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3512 resultData = (NSData*)transformResult;
3513 [resultData autorelease];
3516 CFRelease(encryptSymRef);
3517 CFRelease(decryptSymRef);
3519 STAssertEqualObjects(testData, resultData, @"The output of the decrypt transform does NOT match the original input iteration %d", i);
3525 static SecTransformInstanceBlock RoundTripCheck(CFStringRef name,
3526 SecTransformRef newTransform,
3527 SecTransformImplementationRef ref)
3529 SecTransformInstanceBlock instanceBlock =
3531 CFErrorRef result = NULL;
3532 __block CFDataRef remainder = NULL;
3533 __block SecTransformStringOrAttributeRef ahead = NULL;
3534 __block int eof_count = 0;
3535 __block bool drain = false;
3537 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
3538 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeStream, kCFBooleanTrue);
3540 dispatch_block_t not_equal =
3543 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, kCFBooleanFalse);
3544 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL);
3548 SecTransformAttributeActionBlock action =
3549 ^(SecTransformAttributeRef ah, CFTypeRef value)
3553 return (CFTypeRef)NULL;
3558 SecTransformPushbackAttribute(ref, ah, value);
3562 CFDataRef d = (CFDataRef)value;
3565 CFIndex compare_length;
3566 CFIndex remainder_length = CFDataGetLength(remainder);
3567 CFIndex d_length = CFDataGetLength(d);
3568 CFDataRef new_remainder = NULL;
3569 SecTransformAttributeRef new_ahead = NULL;
3571 if (remainder_length == d_length)
3573 compare_length = d_length;
3575 else if (remainder_length < d_length)
3577 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(d) + remainder_length, d_length - remainder_length);
3578 compare_length = remainder_length;
3582 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(remainder) + d_length, remainder_length - d_length);
3583 compare_length = d_length;
3587 if (bcmp(CFDataGetBytePtr(d), CFDataGetBytePtr(remainder), compare_length)) {
3592 CFRelease(remainder);
3593 remainder = new_remainder;
3602 remainder = CFDataCreateCopy(NULL, d);
3606 if (CFDataGetLength(d))
3616 if (++eof_count == 2)
3620 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3621 kSecTransformMetaAttributeValue,
3622 CFDataGetLength(remainder) ? kCFBooleanFalse : kCFBooleanTrue);
3624 CFRelease(remainder);
3628 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3629 kSecTransformMetaAttributeValue, kCFBooleanTrue);
3632 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3633 kSecTransformMetaAttributeValue, NULL);
3637 return (CFTypeRef)NULL;
3640 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT2"), action);
3641 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, action);
3646 return Block_copy(instanceBlock);
3649 BOOL RoundTrip(CFStringRef fname, SecTransformRef in, SecTransformRef out, BOOL share)
3651 static dispatch_once_t once;
3652 CFStringRef name = CFSTR("com.apple.examples.cmp");
3653 // concepts: pushback, SecTransformSetAttributeAction vs. ProcessData, ah==, & send value to output
3655 dispatch_once(&once,
3657 SecTransformRegister(name, &RoundTripCheck, NULL);
3660 SecTransformRef cmp = SecTransformCreate(name, NULL);
3661 SecTransformRef group = SecTransformCreateGroupTransform();
3662 CFErrorRef err = NULL;
3663 SecTransformConnectTransforms(in, kSecTransformOutputAttributeName, out, kSecTransformInputAttributeName, group, NULL);
3664 SecTransformConnectTransforms(out, kSecTransformOutputAttributeName, cmp, kSecTransformInputAttributeName, group, NULL);
3665 NSInputStream *is = [NSInputStream inputStreamWithFileAtPath:(NSString *)fname];
3666 // XXX: failure to do this seem to crash SecTransformExecute when it releases the error, track down & fix or file radar
3669 NSInputStream *is2 = nil;
3673 SecTransformRef tee = SecNullTransformCreate();
3674 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, in, kSecTransformInputAttributeName, group, NULL);
3675 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, cmp, CFSTR("INPUT2"), group, NULL);
3676 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, (CFTypeRef)is, NULL);
3679 is2 = [NSInputStream inputStreamWithFileAtPath:(NSString *)fname];
3681 SecTransformSetAttribute(in, kSecTransformInputAttributeName, (CFTypeRef)is, &err);
3682 SecTransformSetAttribute(cmp, CFSTR("INPUT2"), (CFTypeRef)is2, &err);
3685 assert(err == NULL);
3686 CFTypeRef r = SecTransformExecute(group, &err);
3708 return r == kCFBooleanTrue;
3712 CFfprintf(stderr, "round trip error: %@", err);
3717 static SecTransformInstanceBlock LineLengthCheck(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref)
3719 SecTransformInstanceBlock instanceBlock = ^{
3720 CFErrorRef result = NULL;
3721 __block int bytesPastLastEOL = 0;
3722 __block int max = 0;
3724 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("MAX"), ^(SecTransformAttributeRef ah, CFTypeRef value) {
3725 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &max);
3729 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef ah, CFTypeRef value) {
3730 if (NULL != value) {
3731 CFDataRef d = (CFDataRef)value;
3732 CFIndex len = CFDataGetLength(d);
3733 const UInt8 *bytes = CFDataGetBytePtr(d);
3735 for(int i = 0; i < len; i++) {
3736 if (bytes[i] == '\n') {
3737 bytesPastLastEOL = 0;
3740 if (bytesPastLastEOL > max) {
3741 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "MAX line length of %d exceeded", max));
3747 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
3754 return Block_copy(instanceBlock);
3757 -(void)testLargeChunkEncode
3759 NSError *err = NULL;
3760 NSData *d = [NSData dataWithContentsOfFile:@"/usr/share/dict/web2a" options:NSDataReadingMapped error: &err];
3761 STAssertNil(err, @"dataWithContentsOfFile %@", err);
3762 CFStringRef types[] = {kSecZLibEncoding, kSecBase64Encoding, kSecBase32Encoding, NULL};
3764 dispatch_group_t dg = dispatch_group_create();
3766 CFStringRef lengthCheckName = CFSTR("com.apple.security.unit-test.lineLengthCheck");
3767 SecTransformRegister(lengthCheckName, LineLengthCheck, (CFErrorRef *)&err);
3768 STAssertNil(err, @"Expected to register %@", lengthCheckName);
3770 for(int i = 0; types[i]; i++) {
3772 CFStringRef etype = types[i];
3774 void (^trial)(NSString *testName, id lineLength, int maxLineLength) = ^(NSString *testName, id lineLength, int maxLineLength) {
3775 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3777 SecTransformRef et = SecEncodeTransformCreate(etype, (CFErrorRef *)&err);
3778 SecTransformRef dt = SecDecodeTransformCreate(etype, (CFErrorRef *)&err);
3780 SecTransformRef lineLengthChecker = (etype == kSecZLibEncoding) ? SecNullTransformCreate() : SecTransformCreate(lengthCheckName, NULL);
3781 STAssertNotNil((id)lineLengthChecker, @"Expected to create line length checker");
3782 SecTransformSetAttribute(lineLengthChecker, CFSTR("MAX"), [NSNumber numberWithInt:maxLineLength], NULL);
3784 SecTransformConnectTransforms(et, kSecTransformOutputAttributeName, lineLengthChecker, kSecTransformInputAttributeName, group, (CFErrorRef *)&err);
3785 SecTransformConnectTransforms(lineLengthChecker, kSecTransformOutputAttributeName, dt, kSecTransformInputAttributeName, group, (CFErrorRef *)&err);
3787 SecTransformSetAttribute(et, kSecTransformInputAttributeName, (CFDataRef)d, (CFErrorRef *)&err);
3788 SecTransformSetAttribute(et, kSecEncodeLineLengthAttribute, lineLength, (CFErrorRef *)&err);
3789 SecTransformSetAttribute(et, CFSTR("NAME"), (CFStringRef)testName, (CFErrorRef *)&err);
3791 dispatch_group_async(dg, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
3792 CFDataRef result = (CFDataRef)SecTransformExecute(group, (CFErrorRef *)&err);
3794 STAssertNil(err, @"execute for %@ got %@", testName, err);
3795 STAssertNotNil((id)result, @"No result from execute of %@", testName);
3798 STAssertEqualObjects(d, (id)result, @"test %@ failed", testName);
3803 for(int j = max_j; j > 70; --j) {
3804 if (etype == kSecZLibEncoding && j != max_j) {
3807 trial([NSString stringWithFormat:@"%@-%d", etype, j], [NSNumber numberWithInt:j], j);
3810 if (etype != kSecZLibEncoding) {
3811 trial([NSString stringWithFormat:@"%@-LL64", etype], (id)kSecLineLength64, 64);
3812 trial([NSString stringWithFormat:@"%@-LL76", etype], (id)kSecLineLength76, 76);
3816 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
3820 SecTransformRef et = SecEncodeTransformCreate(kSecZLibEncoding, NULL);
3821 SecTransformRef dt = SecDecodeTransformCreate(kSecZLibEncoding, NULL);
3823 // using a tee would require >10 buffered items (we need to buffer about 64K), so we pass share=NO
3824 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/web2a", et, dt, NO), @"Roundtrip /usr/share/dict/web2a");
3830 If we want this we need a 'new' custom transform that will get receive the ratio data and be able to
3833 CFNumberRef r1 = (CFNumberRef)SecTransformGetAttribute(et, kSecCompressionRatio);
3834 CFNumberRef r2 = (CFNumberRef)SecTransformGetAttribute(dt, kSecCompressionRatio);
3836 STAssertNotNil((NSNumber *)r1, @"encode ratio");
3837 STAssertNotNil((NSNumber *)r2, @"decode ratio");
3838 STAssertEqualObjects((NSNumber *)r1, (NSNumber *)r2, @"same ratios");
3842 static SecTransformInstanceBlock CycleCheckTest(CFStringRef name,
3843 SecTransformRef newTransform,
3844 SecTransformImplementationRef ref)
3846 SecTransformInstanceBlock instanceBlock =
3848 CFErrorRef result = NULL;
3850 __block CFNumberRef feedback = CFNumberCreate(NULL, kCFNumberIntType, &zero);
3852 SecTransformCustomSetAttribute(ref, CFSTR("FEEDBACK"), kSecTransformMetaAttributeCanCycle, kCFBooleanTrue);
3854 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
3855 ^(SecTransformAttributeRef ah, CFTypeRef value)
3857 if (value == NULL) {
3858 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
3861 if (feedback == NULL) {
3862 SecTransformPushbackAttribute(ref, ah, value);
3863 return (CFTypeRef)NULL;
3867 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &x);
3868 CFNumberGetValue(feedback, kCFNumberIntType, &y);
3870 CFNumberRef res = CFNumberCreate(NULL, kCFNumberIntType, &x);
3871 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, res);
3873 CFRelease(feedback);
3875 return (CFTypeRef)NULL;
3878 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("FEEDBACK"),
3879 ^(SecTransformAttributeRef ah, CFTypeRef value)
3883 SecTransformPushbackAttribute(ref, ah, value);
3885 feedback = (CFNumberRef)CFRetain(value);
3889 return (CFTypeRef)NULL;
3896 return Block_copy(instanceBlock);
3899 -(void)testCycleCheck {
3901 SecTransformRef cat = SecNullTransformCreate();
3902 SecTransformRef group = SecTransformCreateGroupTransform();
3903 CFErrorRef err = NULL;
3905 CFStringRef name = CFSTR("com.apple.examples.unit-test.loop-test");
3907 SecTransformRegister(name, &CycleCheckTest, NULL);
3909 SecTransformRef twenty = count_transform(20);
3911 // this is getting an internal error, but it's being ignored.
3912 SecTransformRef xxor = SecTransformCreate(name, &err);
3914 SecTransformConnectTransforms(xxor, CFSTR("OUTPUT"), cat, CFSTR("INPUT"), group, &err);
3915 STAssertNil((id)err, @"xor->cat");
3916 SecTransformConnectTransforms(xxor, CFSTR("OUTPUT"), xxor, CFSTR("FEEDBACK"), group, &err);
3917 STAssertNil((id)err, @"xor->xor");
3918 SecTransformConnectTransforms(twenty, CFSTR("OUTPUT"), xxor, CFSTR("INPUT"), group, &err);
3919 STAssertNil((id)err, @"twenty->xor");
3921 //SecTransformSetAttribute(xxor, CFSTR("DEBUG"), kCFBooleanTrue, &err);
3923 CFTypeRef r = SecTransformExecute(group, &err);
3924 STAssertNil((id)err, @"execute err=%@", err);
3925 STAssertNotNil((id)r, @"no results from execute");
3928 CFNumberRef z = (CFNumberRef)[NSNumber numberWithInt:0];
3929 int n = CFArrayGetCountOfValue((CFArrayRef)r, CFRangeMake(0, CFArrayGetCount((CFArrayRef)r)), z);
3930 // There should be six zeros in the xor->feedback chain from 0 to 19.
3931 STAssertEquals(n, 6, @"There should be six zeros in %@", r);
3941 -(void)testValidate {
3942 SecTransformRef group = SecTransformCreateGroupTransform();
3943 CFErrorRef err = NULL;
3945 CFStringRef data_or_null_name = CFSTR("com.apple.examples.unit-test.data-or-null");
3946 SecTransformCreateBlock data_or_null = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) {
3947 params->overrideAttribute(kSecTransformActionAttributeValidation, CFSTR("INPUT"), SecTransformCreateValidatorForCFtype(CFDataGetTypeID(), YES));
3951 SecTransformRef makes_numbers = count_transform(20);
3952 SecTransformRef wants_data = custom_transform(data_or_null_name, data_or_null);
3954 SecTransformConnectTransforms(makes_numbers, CFSTR("OUTPUT"), wants_data, CFSTR("INPUT"), group, NULL);
3955 STAssertNil((id)err, @"unexpected connect error: %@", err);
3956 CFTypeRef r = SecTransformExecute(group, &err);
3957 STAssertNil((id)r, @"Got non-null result (%@) when expecting null!", r);
3958 STAssertNotNil((id)err, @"Expected an error!", err);
3959 STAssertErrorHas((id)err, @"/INPUT", @"Error indicated attribute that was set incorrectly");
3960 STAssertErrorHas((id)err, @" type CFNumber", @"Error indicated provided type");
3961 STAssertErrorHas((id)err, @" a CFData", @"Error indicated required type");
3967 CFRelease(wants_data);
3969 wants_data = custom_transform(data_or_null_name, data_or_null);
3971 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.";
3972 CFDataRef the_data = CFDataCreate(NULL, (UInt8*)raw_data, strlen(raw_data));
3973 SecTransformSetAttribute(wants_data, kSecTransformInputAttributeName, the_data, &err);
3974 CFRelease(the_data);
3976 STAssertNil((id)err, @"unexpected set error: %@", err);
3977 r = SecTransformExecute(wants_data, &err);
3978 STAssertNotNil((id)r, @"Expected a result, got error: %@", err);
3980 STAssertEqualObjects((id)the_data, (id)r, @"Invalid result");
3983 CFStringRef numbers_only_name = CFSTR("com.apple.examples.unit-test.numbers-only");
3984 SecTransformCreateBlock numbers_only = ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params) {
3985 params->overrideAttribute(kSecTransformActionAttributeValidation, CFSTR("INPUT"), SecTransformCreateValidatorForCFtype(CFNumberGetTypeID(), NO));
3989 CFRelease(makes_numbers);
3990 CFRelease(wants_data);
3992 group = SecTransformCreateGroupTransform();
3993 makes_numbers = count_transform(20);
3994 SecTransformRef wants_numbers = custom_transform(numbers_only_name, numbers_only);
3996 SecTransformConnectTransforms(makes_numbers, CFSTR("OUTPUT"), wants_numbers, CFSTR("INPUT"), group, NULL);
3997 STAssertNil((id)err, @"unexpected connect error: %@", err);
3998 r = SecTransformExecute(group, &err);
3999 CFfprintf(stderr, "r=%@; err=%@\n", r, err);
4000 STAssertNil((id)r, @"Got non-null result (%@) when expecting null!", r);
4001 STAssertNotNil((id)err, @"Expected an error!", err);
4002 STAssertErrorHas((id)err, @"/INPUT", @"Error indicated attribute that was set incorrectly");
4003 STAssertErrorHas((id)err, @"received NULL value", @"Error indicated provided value is NULL");
4004 STAssertErrorHas((id)err, @" a CFNumber", @"Error indicated required type");
4008 CFRelease(makes_numbers);
4009 CFRelease(wants_numbers);
4012 -(void)testCodeBase32 {
4013 struct base32_test_vector {
4014 const char *plain_text;
4015 const char *base32_rfc4648;
4016 const char *base32_fde;
4019 // RFC 4648 test vectors
4020 static base32_test_vector base32_test_vectors[] = {
4022 {"f", "MY======", "MY======"},
4023 {"fo", "MZXQ====", "MZXQ===="},
4024 {"foo", "MZXW6===", "MZXW6==="},
4025 {"foob", "MZXW6YQ=", "MZXW6YQ="},
4026 {"fooba", "MZXW6YTB", "MZXW6YTB"},
4027 {"foobar", "MZXW6YTBOI======", "MZXW6YTBO8======"}};
4029 void (^test)(NSString *test_name, SecTransformRef transform, const char *input, const char *expected_output, NSString *error_format) =
4030 ^(NSString *test_name, SecTransformRef transform, const char *input, const char *expected_output, NSString *error_format)
4033 STFail(@"No transform for %@", test_name);
4037 CFErrorRef err = NULL;
4038 NSData *input_data = [NSData dataWithBytes:input length:strlen(input)];
4039 NSData *expected_output_data = [NSData dataWithBytes:expected_output length:strlen(expected_output)];
4040 SecTransformSetAttribute(transform, kSecTransformInputAttributeName, input_data, &err);
4041 STAssertNil((NSError *)err, @"unexpected error %@ from SecTransformSetAttribute for %@", err, test_name);
4042 NSData *output_data = (NSData *)SecTransformExecute(transform, &err);
4043 [output_data autorelease];
4044 STAssertNil((NSError *)err, @"Error from %@ execute (in=%s, err=%s)", test_name, input, err);
4045 STAssertNotNil(output_data, @"Unexpected nil output from %@ execute (in=%s)", test_name, input);
4047 NSString *output_string = [NSString alloc];
4048 output_string = [output_string initWithBytes:[output_data bytes] length:[output_data length] encoding:NSMacOSRomanStringEncoding];
4049 [output_string autorelease];
4050 NSString *msg = [NSString stringWithFormat:error_format, input, expected_output, output_string];
4051 STAssertEqualObjects(expected_output_data, output_data, @"%@ %@", test_name, msg);
4053 CFRelease(transform);
4056 for(int idx = 0; idx < sizeof(base32_test_vectors)/sizeof(*base32_test_vectors); idx++)
4058 SecTransformRef base32encoder = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
4059 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$@\"");
4061 SecTransformRef base32decoder = SecDecodeTransformCreate(kSecBase32Encoding, NULL);
4062 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$@\"");
4064 SecTransformRef base32FDEencoder = SecEncodeTransformCreate(CFSTR("base32FDE"), NULL);
4065 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$@\"");
4067 SecTransformRef base32FDEdecoder = SecDecodeTransformCreate(CFSTR("base32FDE"), NULL);
4068 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$@\"");
4071 SecTransformRef bet = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
4072 STAssertNotNil((id)bet, @"got bulk base 32 encoder");
4073 SecTransformRef bdt = SecDecodeTransformCreate(kSecBase32Encoding, NULL);
4074 STAssertNotNil((id)bdt, @"got bulk base 32 decoder");
4075 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", bet, bdt, YES), @"Roundtrip base32 /usr/share/dict/words");
4080 // FDE uses a modified base32 alphabet, we want to test it here.
4081 SecTransformRef FDE_encode_transform = SecEncodeTransformCreate(@"base32FDE", NULL);
4082 STAssertNotNil((id)FDE_encode_transform, @"got FDE encoder");
4083 SecTransformRef FDE_decode_transform = SecDecodeTransformCreate(@"base32FDE", NULL);
4084 STAssertNotNil((id)FDE_decode_transform, @"got bulk base 32 decoder");
4085 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", FDE_encode_transform, FDE_decode_transform, YES), @"Roundtrip base32FDE /usr/share/dict/words");
4087 CFRelease(FDE_encode_transform);
4088 CFRelease(FDE_decode_transform);
4091 -(void)testCodeBase64 {
4092 CFErrorRef error = NULL;
4095 SecTransformRef tr = SecDecodeTransformCreate(@"Not a real encoding", &error);
4096 // XXX: known failure in Transform::SetAttribute 7707822 -- I would fix on this branch, but I think that code has diverged
4097 STAssertTrue(tr == NULL, @"Checks for invalid encodings");
4098 NSLog(@"Error: %@", error);
4101 SecTransformRef dt = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
4102 STAssertNotNil((id)dt, @"Got decoder");
4104 const char raw_data0[] = "Tm90IHV1ZW5jb2RlZAo=";
4105 const char raw_data1[] = "Not uuencoded\n";
4106 CFDataRef data0 = CFDataCreate(NULL, (const UInt8*)raw_data0, strlen(raw_data0));
4107 CFDataRef data1 = CFDataCreate(NULL, (const UInt8*)raw_data1, strlen(raw_data1));
4108 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, data0, NULL);
4110 CFDataRef decoded_data = (CFDataRef)SecTransformExecute(dt, &error);
4111 STAssertNotNil((NSData *)decoded_data, @"Got a decode result");
4112 STAssertEqualObjects((NSData *)decoded_data, (NSData *)data1, @"Proper decode results");
4114 SecTransformRef et = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4115 STAssertNotNil((id)et, @"Got encoder");
4117 SecTransformSetAttribute(et, kSecTransformInputAttributeName, data1, NULL);
4119 CFDataRef encoded_data = (CFDataRef)SecTransformExecute(et, NULL);
4120 STAssertNotNil((NSData *)encoded_data, @"Got an encode result");
4122 STAssertEqualObjects((NSData *)encoded_data, (NSData *)data0, @"Proper encode results");
4124 // XXX also for general testing we want a "RandomChunkSizer" that copies INPUT to OUTPUT, but makes random size chunks (incl 0) as it goes.
4126 SecTransformRef dt2 = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
4127 SecTransformRef et2 = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4129 SecTransformSetAttribute(et2, kSecEncodeLineLengthAttribute, CFNumberCreate(NULL, kCFNumberIntType, &ll), NULL);
4131 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", et2, dt2, YES), @"Roundtrip base64 /usr/share/dict/words");
4137 static SecTransformInstanceBlock ErrorResultsTest(CFStringRef name,
4138 SecTransformRef newTransform,
4139 SecTransformImplementationRef ref)
4141 SecTransformInstanceBlock instanceBlock =
4143 CFErrorRef result = NULL;
4144 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
4149 return (CFTypeRef)CFErrorCreate(NULL, CFSTR("expected error"), 42, NULL);
4153 return SecTransformNoData();
4160 return Block_copy(instanceBlock);
4164 -(void)testErrorResults {
4165 CFStringRef name = CFSTR("com.apple.security.unit-test.error-results");
4166 SecTransformRegister(name, &ErrorResultsTest, NULL);
4168 SecTransformRef tr = SecTransformCreate(name, NULL);
4169 CFDataRef data = CFDataCreate(NULL, NULL, 0);
4170 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
4172 CFErrorRef err = NULL;
4173 CFTypeRef no_result = SecTransformExecute(tr, &err);
4175 STAssertErrorHas((id)err, @"expected error", @"Signaled error has original string");
4176 STAssertErrorHas((id)err, @"42", @"Signaled error has original error code");
4177 STAssertNil((id)no_result, @"No result from erroring transform");
4183 -(void)testErrorExecutesInRightQueue {
4184 // testExecuteBlock checks to see if blocks are generally executed on the proper queue, this specifically checks
4185 // for an error while starting (which was originally improperly coded).
4187 SecTransformRef unassigned_input = SecNullTransformCreate();
4188 dispatch_queue_t q = dispatch_queue_create("com.apple.unit-test.ErrorExecutesInRightQueue", NULL);
4189 dispatch_group_t got_final = dispatch_group_create();
4190 dispatch_group_enter(got_final);
4191 __block bool saw_data = false;
4192 __block bool saw_error = false;
4194 SecTransformExecuteAsync(unassigned_input, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
4195 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());
4196 saw_data = saw_data || (message != NULL);
4197 saw_error = saw_error || (error != NULL);
4199 dispatch_group_leave(got_final);
4203 STAssertFalse(dispatch_group_wait(got_final, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"Execute completed");
4204 STAssertFalse(saw_data, @"Should have seen no data (but did)");
4205 STAssertTrue(saw_error, @"Should have seen error (but didn't)");
4207 CFRelease(unassigned_input);
4208 dispatch_group_notify(got_final, q, ^{
4209 dispatch_release(got_final);
4210 dispatch_release(q);
4215 -(void)testSignVerify {
4216 unsigned char *raw_message = (unsigned char *)"Controlling complexity is the essence of computer programming. - Brian Kernigan";
4217 dispatch_group_t dg = dispatch_group_create();
4218 CFErrorRef err = NULL;
4219 CFDataRef message = CFDataCreate(NULL, raw_message, strlen((const char *)raw_message));
4220 __block SecKeyRef rsa_pub_key = NULL;
4221 __block SecKeyRef rsa_priv_key = NULL;
4222 __block SecKeyRef ecdsa_pub_key = NULL;
4223 __block SecKeyRef ecdsa_priv_key = NULL;
4224 __block SecKeyRef dsa_pub_key = NULL;
4225 __block SecKeyRef dsa_priv_key = NULL;
4228 asprintf(&tmp_dir, "%s/sign-verify-test-keychain-", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
4230 unsigned char *raw_bad_message = (unsigned char *)"Standards are great, there are so many to choose from - Andrew S. Tanenbaum (maybe)";
4231 CFDataRef bad_message = CFDataCreate(NULL, raw_bad_message, strlen((const char *)raw_bad_message));
4233 // when safe replace with a concurrent queue
4234 dispatch_queue_t key_q = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4236 dispatch_group_async(dg, key_q,
4238 NSAutoreleasePool *pool = [NSAutoreleasePool new];
4240 // (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)
4241 NSDictionary *key_opts = [NSDictionary dictionaryWithObjectsAndKeys:
4242 (NSString *)kSecAttrKeyTypeRSA, (NSString *)kSecAttrKeyType,
4243 [NSNumber numberWithInt:1024], (NSString *)kSecAttrKeySizeInBits,
4244 @"RSA transform unit test key", (NSString *)kSecAttrLabel,
4246 OSStatus gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &rsa_pub_key, &rsa_priv_key);
4247 STAssertTrue(gp_status == 0, @"RSA (gp_status=0x%x)", gp_status);
4251 dispatch_group_async(dg, key_q,
4255 // 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
4256 NSDictionary *key_opts = [NSDictionary dictionaryWithObjectsAndKeys:
4257 (NSString *)kSecAttrKeyTypeECDSA, (NSString *)kSecAttrKeyType,
4258 [NSNumber numberWithInt:512], (NSString *)kSecAttrKeySizeInBits,
4259 @"ECDSA transform unit test key", (NSString *)kSecAttrLabel,
4261 gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &ecdsa_pub_key, &ecdsa_priv_key);
4264 SecKeychainRef tmp_keychain = NULL;
4265 gp_status = SecKeyCreatePair(tmp_keychain, CSSM_ALGID_ECDSA, 256, NULL,
4267 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT,
4269 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT,
4270 NULL, &ecdsa_pub_key, &ecdsa_priv_key);
4275 STAssertTrue(gp_status == 0, @"ECDSA (gp_status=0x%x)", gp_status);
4279 dispatch_group_async(dg, key_q,
4283 // 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
4284 NSDictionary *key_opts = [NSDictionary dictionaryWithObjectsAndKeys:(NSString *)kSecAttrKeyTypeDSA,
4285 (NSString *)kSecAttrKeyType, [NSNumber numberWithInt:512], (NSString *)kSecAttrKeySizeInBits, nil];
4286 gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &ecdsa_pub_key, &ecdsa_priv_key);
4289 const char *passwd = "this is not secret";
4290 SecKeychainRef tmp_keychain = NULL;
4292 asprintf(&kcfname, "%s-DSA-XXXXXXXXXX", tmp_dir);
4293 // NOTE: "mktemp" isn't as safe as you might think...but this is test code and doesn't have to be, but
4294 // if you copy it elsewhere you may well need to rewrite it. (use mkstemp)
4296 gp_status = SecKeychainCreate(kcfname, strlen(passwd), passwd, NO, NULL, &tmp_keychain);
4297 STAssertTrue(gp_status == 0, @"SecKeychainCreate (gp_status=0x%x)", gp_status);
4298 gp_status = SecKeyCreatePair(tmp_keychain, CSSM_ALGID_DSA, 512, NULL,
4299 CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_WRAP,
4300 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_RETURN_REF,
4301 CSSM_KEYUSE_SIGN|CSSM_KEYUSE_DECRYPT|CSSM_KEYUSE_UNWRAP,
4302 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_RETURN_REF,
4303 NULL, &dsa_pub_key, &dsa_priv_key);
4307 STAssertTrue(gp_status == 0, @"DSA (gp_status=0x%x)", gp_status);
4312 SecKeyRef pub_key, priv_key;
4313 CFDataRef msg_sign, msg_verify;
4314 CFTypeRef dalgo_sign, dalgo_verify;
4315 int dlen_sign, dlen_verify;
4319 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
4321 struct sv_test sv_tests[] =
4323 {@"Basic RSA", rsa_pub_key, rsa_priv_key, message, message, NULL, NULL, 0, 0, YES},
4324 {@"Basic RSA (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, NULL, NULL, 0, 0, NO},
4325 {@"RSA, mismatched digest algos", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA1, 0, 0, NO},
4327 {@"RSA SHA1 MD5", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, YES},
4328 {@"RSA SHA1 MD5 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, NO},
4330 {@"RSA MD5", rsa_pub_key, rsa_priv_key, message, message, kSecDigestMD5, kSecDigestMD5, 0, 0, YES},
4331 {@"RSA MD5 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestMD5, kSecDigestMD5, 0, 0, NO},
4333 {@"RSA MD2", rsa_pub_key, rsa_priv_key, message, message, kSecDigestMD2, kSecDigestMD2, 0, 0, YES},
4334 {@"RSA MD2 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestMD2, kSecDigestMD2, 0, 0, NO},
4336 {@"RSA SHA2 512", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, YES},
4337 {@"RSA SHA2 512 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, NO},
4338 {@"RSA SHA2 512 vs. 384", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 512, 384, NO},
4340 {@"RSA SHA2 384", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, YES},
4341 {@"RSA SHA2 384 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, NO},
4343 {@"RSA SHA2 256", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, YES},
4344 {@"RSA SHA2 256 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, NO},
4346 {@"RSA SHA2 224", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, YES},
4347 {@"RSA SHA2 224 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, NO},
4349 {@"RSA SHA2 0", rsa_pub_key, rsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, YES},
4350 {@"RSA SHA2 0 (tampered data)", rsa_pub_key, rsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, NO},
4352 {@"Basic ECDSA", ecdsa_pub_key, ecdsa_priv_key, message, message, NULL, NULL, 0, 0, YES},
4353 {@"Basic ECDSA (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, NULL, NULL, 0, 0, NO},
4354 {@"ECDSA (mismatched digest algos)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA1, 0, 0, NO},
4356 {@"ECDSA SHA1", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, YES},
4357 {@"ECDSA SHA1 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, NO},
4359 {@"ECDSA SHA2 224", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, YES},
4360 {@"ECDSA SHA2 224 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 224, 224, NO},
4362 {@"ECDSA SHA2 256", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, YES},
4363 {@"ECDSA SHA2 256 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 256, 256, NO},
4365 {@"ECDSA SHA2 384", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, YES},
4366 {@"ECDSA SHA2 384 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 384, 384, NO},
4368 {@"ECDSA SHA2 512", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, YES},
4369 {@"ECDSA SHA2 512 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 512, 512, NO},
4371 {@"ECDSA SHA2 0", ecdsa_pub_key, ecdsa_priv_key, message, message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, YES},
4372 {@"ECDSA SHA2 0 (tampered data)", ecdsa_pub_key, ecdsa_priv_key, message, bad_message, kSecDigestSHA2, kSecDigestSHA2, 0, 0, NO},
4374 {@"Basic DSA", dsa_pub_key, dsa_priv_key, message, message, NULL, NULL, 0, 0, YES},
4375 {@"Basic DSA (tampered data)", dsa_pub_key, dsa_priv_key, message, bad_message, NULL, NULL, 0, 0, NO},
4376 // only SHA1 is supported, so no mismatched digest algo test is available
4378 {@"DSA SHA1", dsa_pub_key, dsa_priv_key, message, message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, YES},
4379 {@"DSA SHA1 (tampered data)", dsa_pub_key, dsa_priv_key, message, bad_message, kSecDigestSHA1, kSecDigestSHA1, 0, 0, NO},
4385 for(i = 0; i < sizeof(sv_tests)/sizeof(sv_test); i++)
4387 CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest};
4388 //CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest, kSecInputIsRaw};
4389 const int ilim = sizeof(input_cases)/sizeof(input_cases[0]);
4391 for(; ii < ilim; ++ii)
4393 for(ij = 0; ij < ilim; ++ij)
4396 struct sv_test *tst = sv_tests + i;
4397 NSString *tname = [NSString stringWithFormat:@"%@ %@ %@", tst->name, input_cases[ii], input_cases[ij]];
4399 CFStringRef sign_input_is = input_cases[ii];
4400 CFStringRef verify_input_is = input_cases[ij];
4402 if (sign_input_is != kSecInputIsPlainText && tst->dalgo_sign == NULL) {
4405 if (verify_input_is != kSecInputIsPlainText && tst->dalgo_verify == NULL) {
4409 if ((sign_input_is == kSecInputIsRaw || verify_input_is == kSecInputIsRaw) && [tst->name rangeOfString:@"RSA"].location == NSNotFound) {
4410 // we can only synthesize these tests for RSA
4411 NSLog(@"No %@ test", tname);
4415 STAssertNotNil((id)tst->pub_key, @"Have pub_key for %@", tname);
4416 STAssertNotNil((id)tst->priv_key, @"Have priv_key for %@", tname);
4418 if (tst->pub_key == nil || tst->priv_key == nil) {
4422 SecTransformRef sign = SecSignTransformCreate(tst->priv_key, &err);
4423 STAssertNil((NSError *)err, @"creating sign for %@", tname);
4424 STAssertNotNil((id)sign, @"Creating sign for %@", tname);
4430 SecTransformRef verify = SecVerifyTransformCreate(tst->pub_key, NULL, &err);
4431 STAssertNotNil((id)verify, @"Creating verify for %@", tname);
4432 STAssertNil((NSError *)err, @"Creating verify for %@", tname);
4434 if (verify == NULL) {
4438 SecTransformRef sign_digest = NULL;
4439 SecTransformRef verify_digest = NULL;
4440 SecTransformRef sign2 = NULL;
4442 if (tst->dalgo_sign)
4444 SecTransformSetAttribute(sign, kSecDigestTypeAttribute, tst->dalgo_sign, &err);
4445 STAssertNil((NSError *)err, @"Setting sign's digest type for %@", tname);
4446 SecTransformSetAttribute(sign, kSecDigestLengthAttribute, [NSNumber numberWithInt:tst->dlen_sign], &err);
4447 STAssertNil((NSError *)err, @"Setting sign's digest length for %@", tname);
4449 if (sign_input_is == kSecInputIsDigest)
4451 sign_digest = SecDigestTransformCreate(tst->dalgo_sign, tst->dlen_sign, &err);
4452 STAssertNotNil((id)sign_digest, @"Create sign's %@-%d digest transform (for %@)", tst->dalgo_sign, tst->dlen_sign, tname);
4453 STAssertNil((NSError *)err, @"Making sign's digester (for %@) - err=%@", tname, err);
4455 SecTransformSetAttribute(sign, kSecInputIsAttributeName, sign_input_is, &err);
4456 STAssertNil((NSError *)err, @"Setting sign's InputIs (for %@) - err=%@", tname, err);
4460 if (tst->dalgo_verify) {
4461 SecTransformSetAttribute(verify, kSecDigestTypeAttribute, tst->dalgo_verify, &err);
4462 STAssertNil((NSError *)err, @"Setting verify's digest type for %@", tname);
4463 SecTransformSetAttribute(verify, kSecDigestLengthAttribute, [NSNumber numberWithInt:tst->dlen_verify], &err);
4464 STAssertNil((NSError *)err, @"Setting verify's digest length for %@", tname);
4466 if (verify_input_is == kSecInputIsDigest) {
4467 verify_digest = SecDigestTransformCreate(tst->dalgo_verify, tst->dlen_verify, &err);
4468 STAssertNotNil((id)verify_digest, @"Create verify's %@-%d digest transform (for %@)", tst->dalgo_verify, tst->dlen_verify, tname);
4469 STAssertNil((NSError *)err, @"Making verify's digester (for %@) - err=%@", tname, err);
4471 SecTransformSetAttribute(verify, kSecInputIsAttributeName, verify_input_is, &err);
4472 STAssertNil((NSError *)err, @"Setting verify's InputIs (for %@) - err=%@", tname, err);
4476 SecGroupTransformRef group = SecTransformCreateGroupTransform();
4477 SecTransformSetAttribute(sign_digest ? sign_digest : sign, kSecTransformInputAttributeName, tst->msg_sign, (CFErrorRef *)&err);
4479 STAssertNil((NSError *)err, @"Setting sign's digest's input for %@", tname);
4480 SecTransformConnectTransforms(sign_digest, kSecTransformOutputAttributeName,
4481 sign, kSecTransformInputAttributeName, group, NULL);
4483 STAssertNil((NSError *)err, @"Setting sign's input for %@", tname);
4487 SecTransformSetAttribute(verify_digest ? verify_digest : verify, kSecTransformInputAttributeName, tst->msg_verify, (CFErrorRef *)&err);
4488 if (verify_digest) {
4489 STAssertNil((NSError *)err, @"Setting verify's digest's input for %@", tname);
4490 SecTransformConnectTransforms(verify_digest, kSecTransformOutputAttributeName,
4491 verify, kSecTransformInputAttributeName, group, NULL);
4493 STAssertNil((NSError *)err, @"Setting verify's input for %@", tname);
4496 SecTransformConnectTransforms(sign2 ? sign2 : sign, kSecTransformOutputAttributeName, verify, kSecSignatureAttributeName, group, NULL);
4498 dispatch_group_enter(dg);
4499 dispatch_queue_t temp_q = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4500 SecTransformExecuteAsync(sign, temp_q,
4501 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
4507 STAssertTrue(message == kCFBooleanTrue, @"Failed to verify proper signature %@; message = %@", tname, message);
4510 STAssertTrue(message == kCFBooleanFalse, @"Failed to detect tampering %@; message = %@", tname, message);
4514 STAssertNil((NSError *)err, @"Executed ok for %@ (err=%@)", tname, error);
4518 dispatch_group_leave(dg);
4530 SecKeyRef pub, priv;
4533 {rsa_pub_key, rsa_priv_key, @"RSA raw test"},
4534 {dsa_pub_key, dsa_priv_key, @"DSA raw test"},
4535 {ecdsa_pub_key, ecdsa_priv_key, @"ECDSA raw test"},
4538 for(i = 0; i < sizeof(raw_tests)/sizeof(raw_tests[0]); ++i) {
4539 raw_test *t = raw_tests + i;
4540 SecTransformRef tee = SecNullTransformCreate();
4541 const char *raw_bytes = "some bytes";
4542 CFDataRef bytes = CFDataCreate(NULL, (UInt8*)raw_bytes, strlen(raw_bytes));
4543 CFErrorRef err = NULL;
4545 SecTransformRef sign = SecSignTransformCreate(t->priv, &err);
4546 STAssertNil((id)err, @"%@ test sign create err=%@", t->name, err);
4548 SecTransformRef verify = SecVerifyTransformCreate(t->pub, NULL, &err);
4549 STAssertNil((id)err, @"%@ test verify create err=%@", t->name, err);
4551 SecGroupTransformRef group = SecTransformCreateGroupTransform();
4552 SecTransformConnectTransforms(sign, kSecTransformOutputAttributeName, verify, kSecSignatureAttributeName, group, &err);
4553 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, sign, kSecTransformInputAttributeName, group, &err);
4554 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, verify, kSecTransformInputAttributeName, group, &err);
4555 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, bytes, &err);
4556 STAssertNil((id)err, @"%@ setup error=%@", t->name, err);
4558 dispatch_group_async(dg, dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
4559 CFErrorRef xerr = NULL;
4560 CFTypeRef result = SecTransformExecute(group, &xerr);
4564 STAssertTrue(result == kCFBooleanTrue, @"%@ sign result=%@", t->name, result);
4566 STFail(@"%@ no result", t->name);
4568 STAssertNil((id)err, @"%@ execute error=%@", t->name, xerr);
4573 // Test some things we want to fail for:
4575 SecTransformRef tee = SecNullTransformCreate();
4576 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, message, NULL);
4577 SecTransformRef vrfy = SecVerifyTransformCreate(ecdsa_pub_key, NULL, NULL);
4579 SecGroupTransformRef group = SecTransformCreateGroupTransform();
4580 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, vrfy, kSecSignatureAttributeName, group, NULL);
4581 SecTransformSetAttribute(vrfy, kSecDigestTypeAttribute, CFSTR("No such type"), NULL);
4582 SecTransformSetAttribute(vrfy, kSecTransformInputAttributeName, message, NULL);
4584 CFTypeRef no_result = SecTransformExecute(group, (CFErrorRef*)&err);
4587 STAssertNil((id)no_result, @"No result from nonexistent digest");
4588 STAssertErrorHas((id)err, @"[Ii]nvalid digest algorithm", @"Error message describes nature of error (%@)", err);
4589 STAssertErrorHas((id)err, @"ECDSA signature", @"Error is not overly general (%@)", err);
4590 STAssertErrorHas((id)err, @"ECDSA signature", @"Error is not overly general (%@)", err);
4591 STAssertErrorHas((id)err, @"SHA1.*SHA2", @"Error describes valid algorithms (%@)", err);
4594 // It would be awesome if we supported all the digests, and this test went away.
4595 vrfy = SecVerifyTransformCreate(dsa_pub_key, message, NULL);
4596 tee = SecNullTransformCreate();
4598 group = SecTransformCreateGroupTransform();
4599 SecTransformConnectTransforms(vrfy, kSecSignatureAttributeName, tee, kSecTransformOutputAttributeName, group, NULL);
4600 SecTransformConnectTransforms(tee, kSecTransformOutputAttributeName, vrfy, kSecTransformInputAttributeName, group, NULL);
4601 SecTransformSetAttribute(vrfy, kSecDigestTypeAttribute, kSecDigestSHA2, NULL);
4602 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, message, NULL);
4604 no_result = SecTransformExecute(group, (CFErrorRef*)&err);
4607 STAssertNil((id)no_result, @"No result from invalid digest");
4608 STAssertErrorHas((id)err, @"[Ii]nvalid digest algorithm", @"Error message gives problem statement (%@)", err);
4609 STAssertErrorHas((id)err, @"[^A-Z]DSA signature", @"Error is not overly general (%@)", err);
4610 STAssertErrorHas((id)err, @"SHA1", @"Correct algorithm is named (%@)", err);
4612 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
4615 static BOOL keyWithBytes(CFDataRef keyData, SecKeyRef* key, CFTypeRef keyClass) {
4616 CFErrorRef errorRef=NULL;
4617 CFMutableDictionaryRef parameters;
4618 parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 10, NULL, NULL);
4621 kSecAttrKeyClass values:
4622 kSecAttrKeyClassPublic
4623 kSecAttrKeyClassPrivate
4624 kSecAttrKeyClassSymmetric
4626 CFDictionaryAddValue(parameters, kSecAttrKeyClass, keyClass);
4627 CFDictionaryAddValue(parameters, kSecAttrIsPermanent, kCFBooleanFalse); /* also means we have raw bits */
4628 CFDictionaryAddValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA); /* also means we have raw bits */
4629 *key = SecKeyCreateFromData(parameters, keyData, &errorRef);
4630 CFRelease(parameters);
4631 return (key != NULL);
4634 -(void)testVerifyWithKeyFromBytes {
4635 static const uint8_t original_pubKeyData[] =
4637 0x30, 0x48, 0x02, 0x41, 0x00, 0xd1, 0x4d, 0x1c, 0xe6, 0xbd, 0xd6, 0x8c, 0x4b, 0x77, 0x1e, 0x9f,
4638 0xbc, 0xe1, 0xf6, 0x96, 0xf2, 0x55, 0xa2, 0xdc, 0x28, 0x36, 0x39, 0xf4, 0xec, 0x5b, 0x85, 0x9b,
4639 0x3c, 0x7f, 0x98, 0xe0, 0xed, 0x49, 0xf5, 0x44, 0xb1, 0x87, 0xa8, 0xf6, 0x7f, 0x55, 0xc0, 0x39,
4640 0xf0, 0xe7, 0xcc, 0x9c, 0x84, 0xde, 0x7d, 0x9a, 0x87, 0x38, 0xf2, 0x4b, 0x11, 0x6f, 0x63, 0x90,
4641 0xfc, 0x72, 0x2c, 0x86, 0xa3, 0x02, 0x03, 0x01, 0x00, 0x01
4644 // openssl genrsa -out /tmp/rsa512.pem
4645 // openssl rsa -inform PEM -in /tmp/rsa512.pem -outform DER -out /tmp/rsa512.der
4646 // hexdump -C /tmp/rsa512.der | cut -c10-58 | tr -s ' ' ' ' | sed -e 's/ /, 0x/g' -e 's/$/,/' | cut -c3-|pbcopy
4647 static const uint8_t pubKeyData[] = {
4648 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
4649 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xbf, 0xd5, 0xce, 0x43, 0x59, 0xd5, 0xf8,
4650 0x41, 0xb2, 0xe1, 0x16, 0x02, 0x2a, 0x16, 0xcb, 0xef, 0x49, 0xea, 0x98, 0x71, 0xf8, 0xfb, 0x94,
4651 0x23, 0x12, 0xf7, 0xbc, 0x80, 0xd0, 0x8b, 0xfd, 0x29, 0xb8, 0xfc, 0x2c, 0x3d, 0x13, 0x6f, 0x37,
4652 0xef, 0xa7, 0x1e, 0xf9, 0x4c, 0x3d, 0x38, 0x3a, 0x2f, 0x6b, 0xa8, 0x16, 0x00, 0x27, 0x5a, 0xbe,
4653 0x3d, 0x61, 0xdd, 0x18, 0x45, 0x22, 0xdb, 0x1a, 0xff, 0x02, 0x03, 0x01, 0x00, 0x01,
4655 static const uint8_t signatureData[] =
4657 0xbc, 0x76, 0x2a, 0x50, 0x4e, 0x17, 0x0b, 0xa9, 0x31, 0x3b, 0xc5, 0xb0, 0x4d, 0x2a, 0x01, 0x9a,
4658 0xbb, 0x5e, 0x7b, 0x6e, 0x90, 0x2f, 0xaf, 0x3f, 0x40, 0xdb, 0xb0, 0xfc, 0x49, 0xcf, 0xbb, 0xb6,
4659 0x08, 0xf0, 0xbb, 0x04, 0x5f, 0x89, 0x0b, 0x10, 0x47, 0x06, 0x93, 0xb3, 0xb7, 0x0b, 0x4e, 0x17,
4660 0xe9, 0xb1, 0x55, 0x94, 0x63, 0x30, 0x0b, 0xa3, 0xb1, 0x28, 0xba, 0xe8, 0xef, 0xb4, 0xbd, 0xc5
4663 const char *raw_data = "Data to verify";
4664 CFDataRef data = CFDataCreate(NULL, (UInt8*) raw_data, strlen(raw_data));
4667 CFDataRef cfkeybytes;
4669 cfkeybytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pubKeyData, sizeof(pubKeyData),kCFAllocatorNull);
4671 if(keyWithBytes(cfkeybytes, &key, kSecAttrKeyClassPublic)){
4672 CFDataRef signature = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, signatureData, sizeof(signatureData),kCFAllocatorNull);
4673 SecTransformRef vt = SecVerifyTransformCreate(key,signature,&error);
4674 SecTransformSetAttribute(vt, kSecTransformDebugAttributeName, @"YES", NULL);
4675 SecTransformSetAttribute(vt, kSecTransformInputAttributeName, data, &error);
4676 CFBooleanRef signature_ok = (CFBooleanRef) SecTransformExecute(vt, &error);
4680 CFRelease(signature);
4682 CFRelease(cfkeybytes);
4684 NSLog(@"STE result %@, err=%@", signature_ok, error);
4685 STAssertNil((id)error, @"Error from SecTransformExecute: %@", error);
4687 STFail(@"Can't get SecKeyCreateFromData to work");
4691 -(void)testAESAndCastKeysFromBytes {
4692 CFErrorRef err = NULL;
4698 const char *aes_kbytes = "0123456789012345";
4699 const char *cast_kbytes = "01234567";
4701 struct tcase cases[] = {
4702 {"AES", kSecAttrKeyTypeAES, [NSData dataWithBytes:aes_kbytes length:strlen(aes_kbytes)]},
4703 {"CAST", kSecAttrKeyTypeCAST, [NSData dataWithBytes:cast_kbytes length:strlen(cast_kbytes)]},
4707 for(i = 0; i < sizeof(cases)/sizeof(cases[0]); ++i) {
4708 NSDictionary *parm = [NSDictionary dictionaryWithObjectsAndKeys:
4709 (id)kSecAttrKeyClassSymmetric, kSecAttrKeyClass,
4710 (id)cases[i].key_type, kSecAttrKeyType,
4711 (id)kCFBooleanFalse, kSecAttrIsPermanent,
4714 SecKeyRef k = SecKeyCreateFromData((CFDictionaryRef)parm, (CFDataRef)cases[i].key_data, (CFErrorRef *)&err);
4715 STAssertNotNil((id)k, @"%s SecKeyCreateFromData didn't", cases[i].name);
4716 STAssertNil((id)err, @"%s SecKeyCreateFromData err=%@", err);
4718 SecTransformRef et = SecEncryptTransformCreate(k, &err);
4719 STAssertNotNil((id)et, @"No %s EncryptTransform created", cases[i].name);
4720 STAssertNil((id)err, @"Error from %s SecEncryptTransformCreate err=%@", cases[i].name, err);
4722 SecTransformRef dt = SecDecryptTransformCreate(k, &err);
4723 STAssertNotNil((id)dt, @"No %s DecryptTransform created", cases[i].name);
4724 STAssertNil((id)err, @"Error from %s SecDecryptTransformCreate err=%@", cases[i].name, err);
4727 BOOL rt_ok = RoundTrip(CFSTR("/usr/share/dict/propernames"), et, dt, YES);
4730 STAssertTrue(rt_ok, @"%s's round trip", cases[i].name);
4735 -(void)testDispatchAsumptions {
4736 // Failures here don't directly indicate we have a bug. It would indicate that
4737 // either dispatch has one, or that we rely on something dispatch never promised
4740 dispatch_semaphore_t pre_sem = dispatch_semaphore_create(0);
4741 dispatch_semaphore_t post_sem = dispatch_semaphore_create(0);
4742 __block bool pre_wait_works = false;
4744 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
4745 STAssertTrue(0 == dispatch_semaphore_wait(pre_sem, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"semaphore signal prior to wait pre-wakes");
4746 pre_wait_works = true;
4747 dispatch_semaphore_signal(post_sem);
4749 dispatch_semaphore_signal(pre_sem);
4750 STAssertTrue(0 == dispatch_semaphore_wait(post_sem, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)), @"signal after wait wakes");
4751 STAssertTrue(pre_wait_works, @"pre-wait worked");
4756 // Build a group containing 3 subgroups, G1 which has 2 encoders, G2 and G3 which have one
4757 // decoder each. Exports and attributes are hooked up so execution results in a CFData
4758 // with the same contents as input_data. "self" is used by the STAssert macros.
4759 // The various transforms are assigned names: G1, G2, G3, E64, EZLIB, DZLIB, D64.
4760 SecTransformRef build_nested_groups(id self, CFDataRef input_data) {
4761 SecGroupTransformRef outer = SecTransformCreateGroupTransform();
4762 SecGroupTransformRef g1 = SecTransformCreateGroupTransform();
4763 SecGroupTransformRef g2 = SecTransformCreateGroupTransform();
4764 SecGroupTransformRef g3 = SecTransformCreateGroupTransform();
4766 CFErrorRef err = NULL;
4768 SecTransformSetAttribute(outer, kSecTransformTransformName, CFSTR("OUTER"), &err);
4769 STAssertNil((id)err, @"Can't set outer's name: %@", err);
4770 SecTransformSetAttribute(g1, kSecTransformTransformName, CFSTR("G1"), &err);
4771 STAssertNil((id)err, @"Can't set g1's name: %@", err);
4772 SecTransformSetAttribute(g2, kSecTransformTransformName, CFSTR("G2"), &err);
4773 STAssertNil((id)err, @"Can't set g2's name: %@", err);
4774 SecTransformSetAttribute(g3, kSecTransformTransformName, CFSTR("G3"), &err);
4775 STAssertNil((id)err, @"Can't set g3's name: %@", err);
4777 SecTransformRef e64 = SecEncodeTransformCreate(kSecBase64Encoding, &err);
4778 STAssertNil((id)err, @"Expected err to be nil, got: %@", err);
4779 STAssertNotNil((id)e64, @"Could not make Encode64 transform");
4780 SecTransformSetAttribute(e64, kSecTransformTransformName, CFSTR("E64"), NULL);
4781 SecTransformRef ezlib = SecEncodeTransformCreate(kSecZLibEncoding, &err);
4782 STAssertNil((id)err, @"Expected err to be nil, got: %@", err);
4783 STAssertNotNil((id)ezlib, @"Could not make Encode ZLib transform");
4784 SecTransformSetAttribute(ezlib, kSecTransformTransformName, CFSTR("EZLIB"), NULL);
4786 SecTransformConnectTransforms(e64, kSecTransformOutputAttributeName, ezlib, kSecTransformInputAttributeName, g1, &err);
4787 STAssertNil((id)err, @"Can't connect e64 to ezlib: %@", err);
4788 SecTransformConnectTransforms(g1, kSecTransformInputAttributeName, e64, kSecTransformInputAttributeName, g1, &err);
4789 STAssertNil((id)err, @"Can't connect g1's input to e64's input: %@", err);
4790 SecTransformConnectTransforms(ezlib, kSecTransformOutputAttributeName, g1, kSecTransformOutputAttributeName, g1, &err);
4791 STAssertNil((id)err, @"Can't connect ezlib's output to g1's output: %@", err);
4793 SecTransformRef dzlib = SecDecodeTransformCreate(kSecZLibEncoding, &err);
4794 STAssertNil((id)err, @"Expected err to be nil, got: %@", err);
4795 STAssertNotNil((id)dzlib, @"Could not make Decode ZLib transform");
4796 SecTransformSetAttribute(dzlib, kSecTransformTransformName, CFSTR("dzlib"), NULL);
4797 SecTransformRef d64 = SecDecodeTransformCreate(kSecBase64Encoding, &err);
4798 STAssertNil((id)err, @"Expected err to be nil, got: %@", err);
4799 STAssertNotNil((id)d64, @"Could not make Decode64 transform");
4800 SecTransformSetAttribute(dzlib, kSecTransformTransformName, CFSTR("D64"), NULL);
4802 // putting just one transform in g2 and g3
4803 SecTransformConnectTransforms(g2, kSecTransformInputAttributeName, dzlib, kSecTransformInputAttributeName, g2, &err);
4804 STAssertNil((id)err, @"Can't connect g2's input to dzlib's input: %@", err);
4805 SecTransformConnectTransforms(dzlib, kSecTransformOutputAttributeName, g2, kSecTransformOutputAttributeName, g2, &err);
4806 STAssertNil((id)err, @"Can't connect dzlib's output to g2's output: %@", err);
4808 SecTransformConnectTransforms(g3, kSecTransformInputAttributeName, d64, kSecTransformInputAttributeName, g3, &err);
4809 STAssertNil((id)err, @"Can't connect g2's input to d64's input: %@", err);
4810 SecTransformConnectTransforms(d64, kSecTransformOutputAttributeName, g3, kSecTransformOutputAttributeName, g3, &err);
4811 STAssertNil((id)err, @"Can't connect d64's output to g2's output: %@", err);
4813 SecTransformConnectTransforms(g1, kSecTransformOutputAttributeName, g2, kSecTransformInputAttributeName, outer, &err);
4814 STAssertNil((id)err, @"Can't connect g1 to g2 (dzlib): %@", err);
4815 SecTransformConnectTransforms(g2, kSecTransformOutputAttributeName, g3, kSecTransformInputAttributeName, outer, &err);
4816 STAssertNil((id)err, @"Can't connect g2 (dzlib) to g3 (d64): %@", err);
4818 SecTransformSetAttribute(g1, kSecTransformInputAttributeName, input_data, &err);
4819 STAssertNil((id)err, @"Can't set g1's input: %@", err);
4832 -(void)testGroupsInGroups {
4833 UInt8 original_bytes[] = "'Twas brillig and the...was that smiley toads? Something with chives? Aw heck!";
4834 CFDataRef original = CFDataCreate(NULL, original_bytes, sizeof(original_bytes));
4836 // Test executing the top group, a sub group, and a non-group member.
4837 for (NSString *name in [NSArray arrayWithObjects:@"OUTER", @"G1", @"D64", nil]) {
4838 CFErrorRef err = NULL;
4839 SecGroupTransformRef outer = build_nested_groups(self, original);
4840 SecTransformRef start_at = SecTransformFindByName(outer, (CFStringRef)name);
4841 STAssertNotNil((id)start_at, @"Expected to find %@", name);
4843 CFDataRef output = (CFDataRef)SecTransformExecute(start_at, &err);
4844 STAssertNil((id)err, @"Can't execute directly created nested transform starting at %@: %@", start_at, err);
4845 STAssertEqualObjects((id)output, (id)original, @"Output and original should match (started at %@)", start_at);
4853 SecGroupTransformRef bad_outer = build_nested_groups(self, original);
4854 SecTransformRef d64 = SecTransformFindByName(bad_outer, CFSTR("D64"));
4855 STAssertNotNil((id)d64, @"Expected to find d64");
4856 CFErrorRef err = NULL;
4857 // d64 is in a group in bad_outer, we set things up to fail
4858 // and later expect execute to fail because of it.
4859 SecTransformSetAttribute(d64, kSecDecodeTypeAttribute, CFSTR("NOT valid"), &err);
4861 // It can fail right away
4862 ErrorHas((NSError*)err, @"Unsupported decode type");
4864 // Or later (see below)
4865 STAssertNil((id)err, @"Expected to set decode type: %@", err);
4868 SecTransformRef e64 = SecTransformFindByName(bad_outer, CFSTR("E64"));
4869 STAssertNotNil((id)e64, @"Expected to find e64");
4870 CFStringRef any = CFSTR("ANY");
4871 // e64 and d64 aren't in the same groups, but they are in outer.
4872 // There should be no way to (directly) connect them, so try all
4873 // 4 groups and make sure none work.
4874 for (NSString *group_name in [NSArray arrayWithObjects:@"OUTER", @"G1", @"G2", @"G3", nil]) {
4875 SecTransformRef connect_in = SecTransformFindByName(bad_outer, (CFStringRef)group_name);
4876 STAssertNotNil((id)connect_in, @"Expected to find %@", group_name);
4878 SecTransformConnectTransforms(d64, any, e64, any, bad_outer, &err);
4879 STAssertNotNil((id)err, @"Expected error on cross group connect (in %@)", group_name);
4881 STAssertEquals(CFErrorGetCode(err), (CFIndex)kSecTransformErrorInvalidConnection, @"error code (in %@)", group_name);
4882 STAssertEqualObjects((id)CFErrorGetDomain(err), (id)kSecTransformErrorDomain, @"error domain (in %@)", group_name);
4887 // While we are here, make sure we can't set a non-exported group attribute
4888 SecTransformSetAttribute((SecTransformRef)connect_in, CFSTR("nobody-exports-me"), CFSTR("VALUE"), &err);
4889 STAssertNotNil((id)err, @"Expected an error setting a non-exported attribute on %@", connect_in);
4890 // Make sure this is the error we expect, not something unrelated to our transgression
4891 ErrorHas((NSError*)err, @"non-exported attribute");
4892 // Error should have the name of the offending attribute
4893 ErrorHas((NSError*)err, @"nobody-exports-me");
4900 CFTypeRef no_result = SecTransformExecute(bad_outer, &err);
4901 STAssertNotNil((id)err, @"Expected error");
4902 ErrorHas((NSError*)err, @"Unsupported decode type");
4903 STAssertNil((id)no_result, @"Expected no result, got: %@", no_result);
4904 CFRelease(bad_outer);
4906 // Make sure we can't connect to or from non-exported group attributes
4907 bad_outer = build_nested_groups(self, original);
4908 STAssertNotNil((id)bad_outer, @"Expected to build nested transform");
4909 SecTransformRef g1 = SecTransformFindByName(bad_outer, CFSTR("G1"));
4910 STAssertNotNil((id)g1, @"Expected to find g1");
4911 SecTransformRef appendix = SecNullTransformCreate();
4912 SecTransformConnectTransforms(appendix, kSecTransformOutputAttributeName, g1, CFSTR("NONE"), bad_outer, &err);
4913 STAssertNotNil((id)err, @"Expected to fail connecting appendix to g1, but didn't");
4914 ErrorHas((NSError*)err, @"non-exported attribute");
4919 SecTransformConnectTransforms(g1, CFSTR("DOES_NOT_EXIST"), appendix, kSecTransformInputAttributeName, bad_outer, &err);
4920 STAssertNotNil((id)err, @"Expected to fail connecting g1 to appendix, but didn't");
4921 ErrorHas((NSError*)err, @"non-exported attribute");
4927 CFRelease(bad_outer);
4928 CFRelease(appendix);
4932 // 10080968 covers this case. It isn't a regression (it was impossible to create nested groups
4933 // until recently), but it needs to be addressed before we ship.
4934 -(void)disabledUntilPR_10080968_testExternalizeGroupsInGroups {
4935 CFErrorRef err = NULL;
4936 UInt8 original_bytes[] = "Sic Semper Tyrannosaurus!";
4937 CFDataRef original = CFDataCreate(NULL, original_bytes, sizeof(original_bytes));
4939 SecGroupTransformRef outer = build_nested_groups(self, original);
4940 NSLog(@"outer=%@", SecTransformDotForDebugging(outer));
4941 SecTransformRef d64 = SecTransformFindByName(outer, CFSTR("D64"));
4942 STAssertNotNil((id)d64, @"Expected to find d64");
4944 CFDictionaryRef freezeDriedNestedGroups = SecTransformCopyExternalRepresentation(d64);
4945 STAssertNotNil((id)freezeDriedNestedGroups, @"Expected to externalize group");
4947 SecTransformRef outer2 = SecTransformCreateFromExternalRepresentation(freezeDriedNestedGroups, &err);
4948 STAssertNil((id)err, @"Can't create nested group err: %@", err);
4949 STAssertNotNil((id)outer2, @"Expected transform fron xrep: %@", freezeDriedNestedGroups);
4950 NSLog(@"outer2=%@", SecTransformDotForDebugging(outer2));
4952 CFTypeRef output2 = SecTransformExecute(outer2, &err);
4953 STAssertNil((id)err, @"Can't execute outer2: %@", err);
4954 STAssertEqualObjects((id)output2, (id)original, @"Output2 and original should match");
4957 NSString *CopyLeakLine()
4959 static char os_build[16];
4960 static dispatch_once_t get_os_build_once;
4961 static BOOL broken_leaks_command = NO;
4963 dispatch_once(&get_os_build_once, ^{
4964 int mib[] = { CTL_KERN, KERN_OSVERSION };
4965 size_t bufsz = sizeof(os_build);
4966 sysctl(mib, 2, os_build, &bufsz, NULL, 0);
4968 if (4 == sizeof(char*) && 0 == strcmp(os_build, "12A75")) {
4969 // 12A75's leaks command was badly broken for 32 bit.
4970 // Running it suspends otest, and it is too hard to
4972 broken_leaks_command = YES;
4976 if (broken_leaks_command) {
4977 return [NSString stringWithFormat:@"Leaks command is broken in %s", os_build];
4980 NSRegularExpression *matchLeaksLine = [NSRegularExpression regularExpressionWithPattern:@"^Process \\d+: \\d+ leaks for \\d+ total leaked bytes.$" options:NSRegularExpressionAnchorsMatchLines error:NULL];
4982 char *leak_command = NULL;
4983 NSString *fname = [NSString stringWithFormat:@"/tmp/L%d-%d", getpid(), (int)arc4random()];
4984 asprintf(&leak_command, "(/usr/bin/leaks %d >%s || (echo OOPS; kill -CONT %d))", getpid(), [fname UTF8String], getpid());
4985 system(leak_command);
4987 NSString *output = [NSString stringWithContentsOfFile:fname encoding:NSUTF8StringEncoding error:NULL];
4988 NSTextCheckingResult *result = [matchLeaksLine firstMatchInString:output options:0 range:NSMakeRange(0, [output length])];
4989 if (result.range.location == NSNotFound) {
4992 NSRange matchRange = result.range;
4993 return [output substringWithRange:matchRange];
4996 -(void)testAAASimpleLeakTest {
4997 NSString *starting_leaks = CopyLeakLine();
4998 STAssertNotNil(starting_leaks, @"Found initial leaks");
4999 for(int i = 0; i < 10; i++) {
5000 CFRelease(SecTransformCreateGroupTransform());
5003 NSString *current_leaks = NULL;
5005 // Some of the destruction is async, so if they don't pan out the same, a little sleep and retry
5006 // can legitimately fix it.
5007 for(int i = 0; i < 10; i++) {
5008 current_leaks = CopyLeakLine();
5009 if ([current_leaks isEqualToString:starting_leaks]) {
5016 STAssertNotNil(current_leaks, @"Found current leaks");
5017 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks");
5020 -(void)testAAASimpleishLeakTest {
5021 NSLog(@"pid=%d", getpid());
5022 NSString *starting_leaks = CopyLeakLine();
5023 STAssertNotNil(starting_leaks, @"Found initial leaks");
5024 CFErrorRef err = NULL;
5026 // Derived from Matt Wright's 10242560 test.c
5027 int fd = open("/dev/random", O_RDONLY);
5028 SecTransformRef b64encode = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
5029 const int buffer_size = 1024;
5030 void *buffer = malloc(buffer_size);
5031 // For this test, ignore short reads
5032 read(fd, buffer, buffer_size);
5033 CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, (UInt8*)buffer, buffer_size, kCFAllocatorMalloc);
5034 SecTransformSetAttribute(b64encode, kSecTransformInputAttributeName, data, &err);
5035 STAssertNil((id)err, @"Expected no SecTransformSetAttribute error, got: %@", err);
5037 CFTypeRef output = SecTransformExecute(b64encode, &err);
5038 STAssertNotNil((id)output, @"Expected result");
5039 STAssertNil((id)err, @"Expected no execute error, got: %@", err);
5041 CFRelease(b64encode);
5043 NSString *current_leaks = NULL;
5045 // Some of the destruction is async, so if they don't pan out the same, a little sleep and retry
5046 // can legitimately fix it.
5047 for(int i = 0; i < 10; i++) {
5048 current_leaks = CopyLeakLine();
5049 if ([current_leaks isEqualToString:starting_leaks]) {
5056 STAssertNotNil(current_leaks, @"Found current leaks");
5057 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks");