]> git.saurik.com Git - apple/security.git/blob - libsecurity_transform/custom.mm
Security-55471.tar.gz
[apple/security.git] / libsecurity_transform / custom.mm
1 //
2 // custom.m
3 // libsecurity_transform
4 //
5 // Created by JOsborne on 2/18/10.
6 // Copyright 2010 Apple. All rights reserved.
7 //
8
9
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>
20 #import "misc.h"
21 #import "Utilities.h"
22 #import "SecNullTransform.h"
23 #include "regex.h"
24 #include <dispatch/dispatch.h>
25 #import "SecMaskGenerationFunctionTransform.h"
26 #import "SecTransformInternal.h"
27 #import "custom.h"
28 #include "SecTransformReadTransform.h"
29 #import "SecTransformValidator.h"
30 #include <sys/types.h>
31 #include <sys/sysctl.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <CommonCrypto/CommonCryptor.h>
37 #include <sys/stat.h>
38 #import "NSData+HexString.h"
39
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);
47 };
48
49 typedef void (^SecTransformCreateBlock)(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params);
50
51 SecTransformCreateBlock global_create_block;
52
53 static SecTransformInstanceBlock block_for_custom_transform(CFStringRef name, SecTransformRef tr, SecTransformImplementationRef ir)
54 {
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)));
58
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);
62 };
63
64 params->overrideTransform = ^(CFStringRef action, SecTransformActionBlock newAction) {
65 return SecTransformSetTransformAction(ir, action, newAction);
66 };
67
68 params->get = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type) {
69 return SecTranformCustomGetAttribute(ir, attribute, type);
70 };
71
72 params->send = ^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value) {
73 return SecTransformCustomSetAttribute(ir, attribute, type, value);
74 };
75
76 params->pushback = ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) {
77 return SecTransformPushbackAttribute(ir, attribute, value);
78 };
79
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);
85
86 global_create_block(name, tr, params);
87
88 return (CFErrorRef)NULL;
89 };
90
91 return Block_copy(b);
92 }
93
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)
98 {
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;
103
104 dispatch_sync(cnt_q, ^{
105 CFErrorRef err = NULL;
106
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);
111 if (err) {
112 CFfprintf(stderr, "Error %@ creating %@\n", err, base_name);
113 CFRelease(err);
114 }
115 } else {
116 CFfprintf(stderr, "Error %@ registering %@\n", err, base_name);
117 CFRelease(err);
118 }
119 global_create_block = NULL;
120 CFRelease(name);
121 });
122
123 return ret;
124 }
125
126
127 #define STAssertErrorHas(err, rx, msg...) STAssertTrue(ErrorHas(err, rx), ##msg);
128
129 BOOL ErrorHas(NSError *error, NSString *rx) {
130 if (!error) {
131 return NO;
132 }
133 if (![error isKindOfClass:[NSError class]]) {
134 return NO;
135 }
136
137 NSString *es = [error description];
138 if (!es) {
139 return NO;
140 }
141 return [es rangeOfString:rx options:NSRegularExpressionSearch].location != NSNotFound;
142 }
143
144
145 static SecTransformInstanceBlock DelayTransformBlock(CFStringRef name,
146 SecTransformRef newTransform,
147 SecTransformImplementationRef ref)
148 {
149 SecTransformInstanceBlock instanceBlock =
150 ^{
151 CFErrorRef result = NULL;
152
153
154 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
155 ^(CFTypeRef value)
156 {
157
158 if (NULL != value && CFNumberGetTypeID() == CFGetTypeID(value))
159 {
160 long long n;
161 CFNumberGetValue((CFNumberRef)value, kCFNumberLongLongType, &n);
162 usleep(n / NSEC_PER_USEC);
163 }
164
165 return value;
166 });
167 return result;
168 };
169
170 return Block_copy(instanceBlock);
171 }
172
173 SecTransformRef delay_transform(long long nsec) {
174 CFStringRef name = CFSTR("com.apple.security.unit-test.delay");
175
176
177
178 static dispatch_once_t once;
179 __block Boolean ok = TRUE;
180
181 dispatch_block_t aBlock = ^
182 {
183 ok = SecTransformRegister(name, &DelayTransformBlock, NULL);
184 };
185
186 dispatch_once(&once, aBlock);
187
188 if (!ok)
189 {
190 return NULL;
191 }
192
193 SecTransformRef ct = SecTransformCreate(name, NULL);
194 CFNumberRef nr = CFNumberCreate(NULL, kCFNumberLongLongType, &nsec);
195 SecTransformSetAttribute(ct, CFSTR("DELAY"), nr, NULL);
196 CFRelease(nr);
197
198 return ct;
199 }
200
201 @implementation custom
202
203 class BufferStream
204 {
205 protected:
206 const char* mBuffer;
207 size_t mLength;
208 size_t mStringLength;
209 size_t mPos;
210
211 char *mCurrentString;
212
213 public:
214 BufferStream(const char* buffer, size_t length) : mBuffer(buffer), mLength(length), mStringLength(0), mPos(0), mCurrentString(NULL) {}
215 ~BufferStream();
216
217 const char* GetNextString();
218 void SplitString(const char*& stringA, const char*& stringB);
219 };
220
221
222
223 BufferStream::~BufferStream()
224 {
225 if (NULL != mCurrentString)
226 {
227 free(mCurrentString);
228 }
229 }
230
231
232
233 const char* BufferStream::GetNextString()
234 {
235 size_t p = mPos;
236 if (p >= mLength)
237 {
238 return NULL; // eof
239 }
240
241 // run to either the end of the buffer or a return
242 while (p < mLength && mBuffer[p] != '\n')
243 {
244 p += 1;
245 }
246
247 if (p != mLength)
248 {
249 // handle the end of the buffer specially, since it doesn't point
250 // to valid space
251 p -= 1;
252 }
253
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;
260 mPos = p + 2;
261
262 return mCurrentString;
263 }
264
265
266
267 void BufferStream::SplitString(const char*& a, const char*& b)
268 {
269 // scan the buffer, looking for a ':'
270 size_t p = 0;
271 while (mCurrentString[p] != 0 && mCurrentString[p] != ':')
272 {
273 p += 1;
274 }
275
276 // the first string is always our buffer pointer
277 a = mCurrentString;
278
279 if (mCurrentString[p] == ':')
280 {
281 mCurrentString[p] = 0;
282
283 // look for the beginning of the next string
284 p += 1;
285 while (p < mLength && isspace(mCurrentString[p]))
286 {
287 p += 1;
288 }
289
290 b = mCurrentString + p;
291 }
292 else
293 {
294 b = NULL;
295 }
296 }
297
298
299
300 -(void)disabledtestzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
301 {
302 // open leaks and make a connection to it.
303 char* name;
304
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);
310 system(buffer);
311
312 struct stat st;
313 stat(name, &st);
314
315 char* rBuffer = (char*) malloc(st.st_size);
316 FILE* f = fopen(name, "r");
317 fread(rBuffer, 1, st.st_size, f);
318 fclose(f);
319
320 // set up our output parser
321 BufferStream bStream(rBuffer, st.st_size);
322 const char* s = bStream.GetNextString();
323
324 bool didError = true;
325
326 if (NULL != s)
327 {
328 // we have our string, split it and see what it means
329 const char* key;
330 const char* value;
331
332 bStream.SplitString(key, value);
333 if (strcmp(key, "leaks Report Version") != 0 || strcmp(value, "2.0") != 0)
334 {
335 didError = true;
336 }
337 else
338 {
339 didError = false;
340 }
341 }
342
343 if (!didError)
344 {
345 const char* key;
346 const char* value;
347
348 // figure out what our target line will look like
349 char* target;
350 asprintf(&target, "Process %d", thePid);
351
352 const char* nextString = bStream.GetNextString();
353 while (nextString)
354 {
355 bStream.SplitString(key, value);
356 if (strcmp(key, target) == 0) // we found our target!!!
357 {
358 // do it again
359 bStream.GetNextString();
360 bStream.SplitString(key, value);
361
362 if (value[0] != '0') // we have a non-zero result... :(
363 {
364 didError = true;
365 }
366 }
367
368 nextString = bStream.GetNextString();
369 }
370
371 free(target);
372 }
373
374 STAssertFalse(didError, @"You have leaks!");
375
376 if (didError)
377 {
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);
382 fclose(f);
383 }
384 else
385 {
386 unlink(name);
387 }
388
389 free(name);
390 }
391
392
393
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";
409
410 const NSString* gAbortTransformName = (NSString*) kSecTransformAbortAttributeName;
411
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.";
424
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};
429
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};
434 -(void)testPaddings
435 {
436 CFStringRef paddings[] = {kSecPaddingNoneKey, kSecPaddingPKCS7Key, kSecPaddingPKCS5Key, kSecPaddingPKCS1Key};
437
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
445
446 CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
447 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
448 &kCFTypeDictionaryValueCallBacks);
449
450 CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
451
452 cfdatacryptokey = CFDataCreate(kCFAllocatorDefault, rawcryptokey,
453 sizeof(rawcryptokey));
454 cryptokey = SecKeyCreateFromData(parameters,
455 cfdatacryptokey, &error);
456 STAssertNil((id)error, @"Unexpected SecKeyCreateFromData error: %@", error);
457
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;
463 }
464 sourceData = (CFDataRef)[NSData dataWithBytes:sourceCString length:len];
465
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);
470
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);
476
477 SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName, sourceData, &error);
478 STAssertNil((id)error, @"Couldn't set encrypt transform input: %@", error);
479
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");
483
484 SecTransformSetAttribute(decrypt, kSecTransformInputAttributeName, encryptedData, &error);
485 STAssertNil((id)error, @"Couldn't set decrypt transform input: %@", error);
486
487 decryptedData = (CFDataRef)SecTransformExecute(decrypt, &error);
488 STAssertNil((id)error, @"Couldn't execute decrypt: %@", error);
489 STAssertNotNil((id)decryptedData, @"Didn't get decrypt data");
490
491 STAssertEqualObjects((id)decryptedData, (id)sourceData, @"Decrypt output didn't match encrypt input for padding %@", paddings[i]);
492 }
493 }
494
495 static SecTransformInstanceBlock nopInstance(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref)
496 {
497 SecTransformInstanceBlock instanceBlock = ^{
498 return (CFErrorRef)NULL;
499 };
500
501 return Block_copy(instanceBlock);
502 }
503
504
505 -(void)test_manyregister
506 {
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);
513 });
514 }
515
516 -(void)test_emptyOAEP
517 {
518 SecKeychainRef tmp_keychain = NULL;
519 char *kcfname;
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)
524 mktemp(kcfname);
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);
527
528 const char *pem_key_bytes[] = {
529 // From the spec
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",
531 NULL,
532 };
533 struct key_pair {
534 SecKeyRef pubKey, privKey;
535 };
536 key_pair keys[1];
537
538 int i;
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));
545
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("");
552
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);
563 }
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);
566
567
568 CFErrorRef err = NULL;
569
570 SecTransformRef encryptor = SecEncryptTransformCreate(keys[0].pubKey, &err);
571
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);
576
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);
583
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);
597 sleep(5);
598
599 return;
600 }
601
602 -(void)testzzzzZZZZ
603 {
604 // Give xcode a little time to parse all the output before the unit tests exit
605 sleep(2);
606 }
607
608 -(void)test_multiOAEP
609 {
610 SecKeychainRef tmp_keychain = NULL;
611 char *kcfname;
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)
616 mktemp(kcfname);
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);
619
620 const char *pem_key_bytes[] = {
621 // From the spec
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",
634 NULL,
635 };
636 struct key_pair {
637 SecKeyRef pubKey, privKey;
638 };
639 key_pair keys[11];
640
641 int i;
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));
648
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("");
655
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);
666 }
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);
669
670 struct KAT {
671 NSData *message, *seed, *encryptedMessage;
672 NSString *label;
673 key_pair keys;
674 };
675 KAT tests[] = {
676 // This first one is from the spec
677 {
678 .message = [NSData dataWithHexString:@"d436e99569fd32a7c8a05bbc90d32c49"],
679 .seed = [NSData dataWithHexString:@"aafd12f659cae63489b479e5076ddec2f06cb58f"],
680 .encryptedMessage = [NSData dataWithHexString:@"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955"],
681 .keys = keys[0],
682 .label = @"From spec",
683 },
684 // The next 60 are from oaep-vect.txt
685 {
686 .message = [NSData dataWithHexString:@"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"],
687 .seed = [NSData dataWithHexString:@"18b776ea21069d69776a33e96bad48e1dda0a5ef"],
688 .encryptedMessage = [NSData dataWithHexString:@"354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"],
689 .keys = keys[1],
690 .label = @"1-1",
691 },
692 {
693 .message = [NSData dataWithHexString:@"750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"],
694 .seed = [NSData dataWithHexString:@"0cc742ce4a9b7f32f951bcb251efd925fe4fe35f"],
695 .encryptedMessage = [NSData dataWithHexString:@"640db1acc58e0568fe5407e5f9b701dff8c3c91e716c536fc7fcec6cb5b71c1165988d4a279e1577d730fc7a29932e3f00c81515236d8d8e31017a7a09df4352d904cdeb79aa583adcc31ea698a4c05283daba9089be5491f67c1a4ee48dc74bbbe6643aef846679b4cb395a352d5ed115912df696ffe0702932946d71492b44"],
696 .keys = keys[1],
697 .label = @"1-2",
698 },
699 {
700 .message = [NSData dataWithHexString:@"d94ae0832e6445ce42331cb06d531a82b1db4baad30f746dc916df24d4e3c2451fff59a6423eb0e1d02d4fe646cf699dfd818c6e97b051"],
701 .seed = [NSData dataWithHexString:@"2514df4695755a67b288eaf4905c36eec66fd2fd"],
702 .encryptedMessage = [NSData dataWithHexString:@"423736ed035f6026af276c35c0b3741b365e5f76ca091b4e8c29e2f0befee603595aa8322d602d2e625e95eb81b2f1c9724e822eca76db8618cf09c5343503a4360835b5903bc637e3879fb05e0ef32685d5aec5067cd7cc96fe4b2670b6eac3066b1fcf5686b68589aafb7d629b02d8f8625ca3833624d4800fb081b1cf94eb"],
703 .keys = keys[1],
704 .label = @"1-3",
705 },
706 {
707 .message = [NSData dataWithHexString:@"52e650d98e7f2a048b4f86852153b97e01dd316f346a19f67a85"],
708 .seed = [NSData dataWithHexString:@"c4435a3e1a18a68b6820436290a37cefb85db3fb"],
709 .encryptedMessage = [NSData dataWithHexString:@"45ead4ca551e662c9800f1aca8283b0525e6abae30be4b4aba762fa40fd3d38e22abefc69794f6ebbbc05ddbb11216247d2f412fd0fba87c6e3acd888813646fd0e48e785204f9c3f73d6d8239562722dddd8771fec48b83a31ee6f592c4cfd4bc88174f3b13a112aae3b9f7b80e0fc6f7255ba880dc7d8021e22ad6a85f0755"],
710 .keys = keys[1],
711 .label = @"1-4",
712 },
713 {
714 .message = [NSData dataWithHexString:@"8da89fd9e5f974a29feffb462b49180f6cf9e802"],
715 .seed = [NSData dataWithHexString:@"b318c42df3be0f83fea823f5a7b47ed5e425a3b5"],
716 .encryptedMessage = [NSData dataWithHexString:@"36f6e34d94a8d34daacba33a2139d00ad85a9345a86051e73071620056b920e219005855a213a0f23897cdcd731b45257c777fe908202befdd0b58386b1244ea0cf539a05d5d10329da44e13030fd760dcd644cfef2094d1910d3f433e1c7c6dd18bc1f2df7f643d662fb9dd37ead9059190f4fa66ca39e869c4eb449cbdc439"],
717 .keys = keys[1],
718 .label = @"1-5",
719 },
720 {
721 .message = [NSData dataWithHexString:@"26521050844271"],
722 .seed = [NSData dataWithHexString:@"e4ec0982c2336f3a677f6a356174eb0ce887abc2"],
723 .encryptedMessage = [NSData dataWithHexString:@"42cee2617b1ecea4db3f4829386fbd61dafbf038e180d837c96366df24c097b4ab0fac6bdf590d821c9f10642e681ad05b8d78b378c0f46ce2fad63f74e0ad3df06b075d7eb5f5636f8d403b9059ca761b5c62bb52aa45002ea70baace08ded243b9d8cbd62a68ade265832b56564e43a6fa42ed199a099769742df1539e8255"],
724 .keys = keys[1],
725 .label = @"1-6",
726 },
727
728 {
729 .message = [NSData dataWithHexString:@"8ff00caa605c702830634d9a6c3d42c652b58cf1d92fec570beee7"],
730 .seed = [NSData dataWithHexString:@"8c407b5ec2899e5099c53e8ce793bf94e71b1782"],
731 .encryptedMessage = [NSData dataWithHexString:@"0181af8922b9fcb4d79d92ebe19815992fc0c1439d8bcd491398a0f4ad3a329a5bd9385560db532683c8b7da04e4b12aed6aacdf471c34c9cda891addcc2df3456653aa6382e9ae59b54455257eb099d562bbe10453f2b6d13c59c02e10f1f8abb5da0d0570932dacf2d0901db729d0fefcc054e70968ea540c81b04bcaefe720e"],
732 .keys = keys[2],
733 .label = @"2-1",
734 },
735 {
736 .message = [NSData dataWithHexString:@"2d"],
737 .seed = [NSData dataWithHexString:@"b600cf3c2e506d7f16778c910d3a8b003eee61d5"],
738 .encryptedMessage = [NSData dataWithHexString:@"018759ff1df63b2792410562314416a8aeaf2ac634b46f940ab82d64dbf165eee33011da749d4bab6e2fcd18129c9e49277d8453112b429a222a8471b070993998e758861c4d3f6d749d91c4290d332c7a4ab3f7ea35ff3a07d497c955ff0ffc95006b62c6d296810d9bfab024196c7934012c2df978ef299aba239940cba10245"],
739 .keys = keys[2],
740 .label = @"2-2",
741 },
742 {
743 .message = [NSData dataWithHexString:@"74fc88c51bc90f77af9d5e9a4a70133d4b4e0b34da3c37c7ef8e"],
744 .seed = [NSData dataWithHexString:@"a73768aeeaa91f9d8c1ed6f9d2b63467f07ccae3"],
745 .encryptedMessage = [NSData dataWithHexString:@"018802bab04c60325e81c4962311f2be7c2adce93041a00719c88f957575f2c79f1b7bc8ced115c706b311c08a2d986ca3b6a9336b147c29c6f229409ddec651bd1fdd5a0b7f610c9937fdb4a3a762364b8b3206b4ea485fd098d08f63d4aa8bb2697d027b750c32d7f74eaf5180d2e9b66b17cb2fa55523bc280da10d14be2053"],
746 .keys = keys[2],
747 .label = @"2-3",
748 },
749 {
750 .message = [NSData dataWithHexString:@"a7eb2a5036931d27d4e891326d99692ffadda9bf7efd3e34e622c4adc085f721dfe885072c78a203b151739be540fa8c153a10f00a"],
751 .seed = [NSData dataWithHexString:@"9a7b3b0e708bd96f8190ecab4fb9b2b3805a8156"],
752 .encryptedMessage = [NSData dataWithHexString:@"00a4578cbc176318a638fba7d01df15746af44d4f6cd96d7e7c495cbf425b09c649d32bf886da48fbaf989a2117187cafb1fb580317690e3ccd446920b7af82b31db5804d87d01514acbfa9156e782f867f6bed9449e0e9a2c09bcecc6aa087636965e34b3ec766f2fe2e43018a2fddeb140616a0e9d82e5331024ee0652fc7641"],
753 .keys = keys[2],
754 .label = @"2-4",
755 },
756 {
757 .message = [NSData dataWithHexString:@"2ef2b066f854c33f3bdcbb5994a435e73d6c6c"],
758 .seed = [NSData dataWithHexString:@"eb3cebbc4adc16bb48e88c8aec0e34af7f427fd3"],
759 .encryptedMessage = [NSData dataWithHexString:@"00ebc5f5fda77cfdad3c83641a9025e77d72d8a6fb33a810f5950f8d74c73e8d931e8634d86ab1246256ae07b6005b71b7f2fb98351218331ce69b8ffbdc9da08bbc9c704f876deb9df9fc2ec065cad87f9090b07acc17aa7f997b27aca48806e897f771d95141fe4526d8a5301b678627efab707fd40fbebd6e792a25613e7aec"],
760 .keys = keys[2],
761 .label = @"2-5",
762 },
763 {
764 .message = [NSData dataWithHexString:@"8a7fb344c8b6cb2cf2ef1f643f9a3218f6e19bba89c0"],
765 .seed = [NSData dataWithHexString:@"4c45cf4d57c98e3d6d2095adc51c489eb50dff84"],
766 .encryptedMessage = [NSData dataWithHexString:@"010839ec20c27b9052e55befb9b77e6fc26e9075d7a54378c646abdf51e445bd5715de81789f56f1803d9170764a9e93cb78798694023ee7393ce04bc5d8f8c5a52c171d43837e3aca62f609eb0aa5ffb0960ef04198dd754f57f7fbe6abf765cf118b4ca443b23b5aab266f952326ac4581100644325f8b721acd5d04ff14ef3a"],
767 .keys = keys[2],
768 .label = @"2-6",
769 },
770
771 {
772 .message = [NSData dataWithHexString:@"087820b569e8fa8d"],
773 .seed = [NSData dataWithHexString:@"8ced6b196290805790e909074015e6a20b0c4894"],
774 .encryptedMessage = [NSData dataWithHexString:@"026a0485d96aebd96b4382085099b962e6a2bdec3d90c8db625e14372de85e2d5b7baab65c8faf91bb5504fb495afce5c988b3f6a52e20e1d6cbd3566c5cd1f2b8318bb542cc0ea25c4aab9932afa20760eaddec784396a07ea0ef24d4e6f4d37e5052a7a31e146aa480a111bbe926401307e00f410033842b6d82fe5ce4dfae80"],
775 .keys = keys[3],
776 .label = @"3-1",
777 },
778 {
779 .message = [NSData dataWithHexString:@"4653acaf171960b01f52a7be63a3ab21dc368ec43b50d82ec3781e04"],
780 .seed = [NSData dataWithHexString:@"b4291d6567550848cc156967c809baab6ca507f0"],
781 .encryptedMessage = [NSData dataWithHexString:@"024db89c7802989be0783847863084941bf209d761987e38f97cb5f6f1bc88da72a50b73ebaf11c879c4f95df37b850b8f65d7622e25b1b889e80fe80baca2069d6e0e1d829953fc459069de98ea9798b451e557e99abf8fe3d9ccf9096ebbf3e5255d3b4e1c6d2ecadf067a359eea86405acd47d5e165517ccafd47d6dbee4bf5"],
782 .keys = keys[3],
783 .label = @"3-2",
784 },
785 {
786 .message = [NSData dataWithHexString:@"d94cd0e08fa404ed89"],
787 .seed = [NSData dataWithHexString:@"ce8928f6059558254008badd9794fadcd2fd1f65"],
788 .encryptedMessage = [NSData dataWithHexString:@"0239bce681032441528877d6d1c8bb28aa3bc97f1df584563618995797683844ca86664732f4bed7a0aab083aaabfb7238f582e30958c2024e44e57043b97950fd543da977c90cdde5337d618442f99e60d7783ab59ce6dd9d69c47ad1e962bec22d05895cff8d3f64ed5261d92b2678510393484990ba3f7f06818ae6ffce8a3a"],
789 .keys = keys[3],
790 .label = @"3-3",
791 },
792 {
793 .message = [NSData dataWithHexString:@"6cc641b6b61e6f963974dad23a9013284ef1"],
794 .seed = [NSData dataWithHexString:@"6e2979f52d6814a57d83b090054888f119a5b9a3"],
795 .encryptedMessage = [NSData dataWithHexString:@"02994c62afd76f498ba1fd2cf642857fca81f4373cb08f1cbaee6f025c3b512b42c3e8779113476648039dbe0493f9246292fac28950600e7c0f32edf9c81b9dec45c3bde0cc8d8847590169907b7dc5991ceb29bb0714d613d96df0f12ec5d8d3507c8ee7ae78dd83f216fa61de100363aca48a7e914ae9f42ddfbe943b09d9a0"],
796 .keys = keys[3],
797 .label = @"3-4",
798 },
799 {
800 .message = [NSData dataWithHexString:@"df5151832b61f4f25891fb4172f328d2eddf8371ffcfdbe997939295f30eca6918017cfda1153bf7a6af87593223"],
801 .seed = [NSData dataWithHexString:@"2d760bfe38c59de34cdc8b8c78a38e66284a2d27"],
802 .encryptedMessage = [NSData dataWithHexString:@"0162042ff6969592a6167031811a239834ce638abf54fec8b99478122afe2ee67f8c5b18b0339805bfdbc5a4e6720b37c59cfba942464c597ff532a119821545fd2e59b114e61daf71820529f5029cf524954327c34ec5e6f5ba7efcc4de943ab8ad4ed787b1454329f70db798a3a8f4d92f8274e2b2948ade627ce8ee33e43c60"],
803 .keys = keys[3],
804 .label = @"3-5",
805 },
806 {
807 .message = [NSData dataWithHexString:@"3c3bad893c544a6d520ab022319188c8d504b7a788b850903b85972eaa18552e1134a7ad6098826254ff7ab672b3d8eb3158fac6d4cbaef1"],
808 .seed = [NSData dataWithHexString:@"f174779c5fd3cfe007badcb7a36c9b55bfcfbf0e"],
809 .encryptedMessage = [NSData dataWithHexString:@"00112051e75d064943bc4478075e43482fd59cee0679de6893eec3a943daa490b9691c93dfc0464b6623b9f3dbd3e70083264f034b374f74164e1a00763725e574744ba0b9db83434f31df96f6e2a26f6d8eba348bd4686c2238ac07c37aac3785d1c7eea2f819fd91491798ed8e9cef5e43b781b0e0276e37c43ff9492d005730"],
810 .label = @"3-6",
811 .keys = keys[3],
812 },
813
814 {
815 .message = [NSData dataWithHexString:@"4a86609534ee434a6cbca3f7e962e76d455e3264c19f605f6e5ff6137c65c56d7fb344cd52bc93374f3d166c9f0c6f9c506bad19330972d2"],
816 .seed = [NSData dataWithHexString:@"1cac19ce993def55f98203f6852896c95ccca1f3"],
817 .encryptedMessage = [NSData dataWithHexString:@"04cce19614845e094152a3fe18e54e3330c44e5efbc64ae16886cb1869014cc5781b1f8f9e045384d0112a135ca0d12e9c88a8e4063416deaae3844f60d6e96fe155145f4525b9a34431ca3766180f70e15a5e5d8e8b1a516ff870609f13f896935ced188279a58ed13d07114277d75c6568607e0ab092fd803a223e4a8ee0b1a8"],
818 .keys = keys[4],
819 .label = @"4-1",
820 },
821 {
822 .message = [NSData dataWithHexString:@"b0adc4f3fe11da59ce992773d9059943c03046497ee9d9f9a06df1166db46d98f58d27ec074c02eee6cbe2449c8b9fc5080c5c3f4433092512ec46aa793743c8"],
823 .seed = [NSData dataWithHexString:@"f545d5897585e3db71aa0cb8da76c51d032ae963"],
824 .encryptedMessage = [NSData dataWithHexString:@"0097b698c6165645b303486fbf5a2a4479c0ee85889b541a6f0b858d6b6597b13b854eb4f839af03399a80d79bda6578c841f90d645715b280d37143992dd186c80b949b775cae97370e4ec97443136c6da484e970ffdb1323a20847821d3b18381de13bb49aaea66530c4a4b8271f3eae172cd366e07e6636f1019d2a28aed15e"],
825 .keys = keys[4],
826 .label = @"4-2",
827 },
828 {
829 .message = [NSData dataWithHexString:@"bf6d42e701707b1d0206b0c8b45a1c72641ff12889219a82bdea965b5e79a96b0d0163ed9d578ec9ada20f2fbcf1ea3c4089d83419ba81b0c60f3606da99"],
830 .seed = [NSData dataWithHexString:@"ad997feef730d6ea7be60d0dc52e72eacbfdd275"],
831 .encryptedMessage = [NSData dataWithHexString:@"0301f935e9c47abcb48acbbe09895d9f5971af14839da4ff95417ee453d1fd77319072bb7297e1b55d7561cd9d1bb24c1a9a37c619864308242804879d86ebd001dce5183975e1506989b70e5a83434154d5cbfd6a24787e60eb0c658d2ac193302d1192c6e622d4a12ad4b53923bca246df31c6395e37702c6a78ae081fb9d065"],
832 .keys = keys[4],
833 .label = @"4-3",
834 },
835 {
836 .message = [NSData dataWithHexString:@"fb2ef112f5e766eb94019297934794f7be2f6fc1c58e"],
837 .seed = [NSData dataWithHexString:@"136454df5730f73c807a7e40d8c1a312ac5b9dd3"],
838 .encryptedMessage = [NSData dataWithHexString:@"02d110ad30afb727beb691dd0cf17d0af1a1e7fa0cc040ec1a4ba26a42c59d0a796a2e22c8f357ccc98b6519aceb682e945e62cb734614a529407cd452bee3e44fece8423cc19e55548b8b994b849c7ecde4933e76037e1d0ce44275b08710c68e430130b929730ed77e09b015642c5593f04e4ffb9410798102a8e96ffdfe11e4"],
839 .keys = keys[4],
840 .label = @"4-4",
841 },
842 {
843 .message = [NSData dataWithHexString:@"28ccd447bb9e85166dabb9e5b7d1adadc4b9d39f204e96d5e440ce9ad928bc1c2284"],
844 .seed = [NSData dataWithHexString:@"bca8057f824b2ea257f2861407eef63d33208681"],
845 .encryptedMessage = [NSData dataWithHexString:@"00dbb8a7439d90efd919a377c54fae8fe11ec58c3b858362e23ad1b8a44310799066b99347aa525691d2adc58d9b06e34f288c170390c5f0e11c0aa3645959f18ee79e8f2be8d7ac5c23d061f18dd74b8c5f2a58fcb5eb0c54f99f01a83247568292536583340948d7a8c97c4acd1e98d1e29dc320e97a260532a8aa7a758a1ec2"],
846 .keys = keys[4],
847 .label = @"4-5",
848 },
849 {
850 .message = [NSData dataWithHexString:@"f22242751ec6b1"],
851 .seed = [NSData dataWithHexString:@"2e7e1e17f647b5ddd033e15472f90f6812f3ac4e"],
852 .encryptedMessage = [NSData dataWithHexString:@"00a5ffa4768c8bbecaee2db77e8f2eec99595933545520835e5ba7db9493d3e17cddefe6a5f567624471908db4e2d83a0fbee60608fc84049503b2234a07dc83b27b22847ad8920ff42f674ef79b76280b00233d2b51b8cb2703a9d42bfbc8250c96ec32c051e57f1b4ba528db89c37e4c54e27e6e64ac69635ae887d9541619a9"],
853 .keys = keys[4],
854 .label = @"4-6",
855 },
856
857 {
858 .message = [NSData dataWithHexString:@"af71a901e3a61d3132f0fc1fdb474f9ea6579257ffc24d164170145b3dbde8"],
859 .seed = [NSData dataWithHexString:@"44c92e283f77b9499c603d963660c87d2f939461"],
860 .encryptedMessage = [NSData dataWithHexString:@"036046a4a47d9ed3ba9a89139c105038eb7492b05a5d68bfd53accff4597f7a68651b47b4a4627d927e485eed7b4566420e8b409879e5d606eae251d22a5df799f7920bfc117b992572a53b1263146bcea03385cc5e853c9a101c8c3e1bda31a519807496c6cb5e5efb408823a352b8fa0661fb664efadd593deb99fff5ed000e5"],
861 .keys = keys[5],
862 .label = @"5-1",
863 },
864 {
865 .message = [NSData dataWithHexString:@"a3b844a08239a8ac41605af17a6cfda4d350136585903a417a79268760519a4b4ac3303ec73f0f87cfb32399"],
866 .seed = [NSData dataWithHexString:@"cb28f5860659fceee49c3eeafce625a70803bd32"],
867 .encryptedMessage = [NSData dataWithHexString:@"03d6eb654edce615bc59f455265ed4e5a18223cbb9be4e4069b473804d5de96f54dcaaa603d049c5d94aa1470dfcd2254066b7c7b61ff1f6f6770e3215c51399fd4e34ec5082bc48f089840ad04354ae66dc0f1bd18e461a33cc1258b443a2837a6df26759aa2302334986f87380c9cc9d53be9f99605d2c9a97da7b0915a4a7ad"],
868 .keys = keys[5],
869 .label = @"5-2",
870 },
871 {
872 .message = [NSData dataWithHexString:@"308b0ecbd2c76cb77fc6f70c5edd233fd2f20929d629f026953bb62a8f4a3a314bde195de85b5f816da2aab074d26cb6acddf323ae3b9c678ac3cf12fbdde7"],
873 .seed = [NSData dataWithHexString:@"2285f40d770482f9a9efa2c72cb3ac55716dc0ca"],
874 .encryptedMessage = [NSData dataWithHexString:@"0770952181649f9f9f07ff626ff3a22c35c462443d905d456a9fd0bff43cac2ca7a9f554e9478b9acc3ac838b02040ffd3e1847de2e4253929f9dd9ee4044325a9b05cabb808b2ee840d34e15d105a3f1f7b27695a1a07a2d73fe08ecaaa3c9c9d4d5a89ff890d54727d7ae40c0ec1a8dd86165d8ee2c6368141016a48b55b6967"],
875 .keys = keys[5],
876 .label = @"5-3",
877 },
878 {
879 .message = [NSData dataWithHexString:@"15c5b9ee1185"],
880 .seed = [NSData dataWithHexString:@"49fa45d3a78dd10dfd577399d1eb00af7eed5513"],
881 .encryptedMessage = [NSData dataWithHexString:@"0812b76768ebcb642d040258e5f4441a018521bd96687e6c5e899fcd6c17588ff59a82cc8ae03a4b45b31299af1788c329f7dcd285f8cf4ced82606b97612671a45bedca133442144d1617d114f802857f0f9d739751c57a3f9ee400912c61e2e6992be031a43dd48fa6ba14eef7c422b5edc4e7afa04fdd38f402d1c8bb719abf"],
882 .keys = keys[5],
883 .label = @"5-4",
884 },
885 {
886 .message = [NSData dataWithHexString:@"21026e6800c7fa728fcaaba0d196ae28d7a2ac4ffd8abce794f0985f60c8a6737277365d3fea11db8923a2029a"],
887 .seed = [NSData dataWithHexString:@"f0287413234cc5034724a094c4586b87aff133fc"],
888 .encryptedMessage = [NSData dataWithHexString:@"07b60e14ec954bfd29e60d0047e789f51d57186c63589903306793ced3f68241c743529aba6a6374f92e19e0163efa33697e196f7661dfaaa47aac6bde5e51deb507c72c589a2ca1693d96b1460381249b2cdb9eac44769f2489c5d3d2f99f0ee3c7ee5bf64a5ac79c42bd433f149be8cb59548361640595513c97af7bc2509723"],
889 .keys = keys[5],
890 .label = @"5-5",
891 },
892 {
893 .message = [NSData dataWithHexString:@"541e37b68b6c8872b84c02"],
894 .seed = [NSData dataWithHexString:@"d9fba45c96f21e6e26d29eb2cdcb6585be9cb341"],
895 .encryptedMessage = [NSData dataWithHexString:@"08c36d4dda33423b2ed6830d85f6411ba1dcf470a1fae0ebefee7c089f256cef74cb96ea69c38f60f39abee44129bcb4c92de7f797623b20074e3d9c2899701ed9071e1efa0bdd84d4c3e5130302d8f0240baba4b84a71cc032f2235a5ff0fae277c3e8f9112bef44c9ae20d175fc9a4058bfc930ba31b02e2e4f444483710f24a"],
896 .keys = keys[5],
897 .label = @"5-6",
898 },
899 {
900 .label = @"6-1",
901 .keys = keys[6],
902 .message = [NSData dataWithHexString:@"4046ca8baa3347ca27f49e0d81f9cc1d71be9ba517d4"],
903 .seed = [NSData dataWithHexString:@"dd0f6cfe415e88e5a469a51fbba6dfd40adb4384"],
904 .encryptedMessage = [NSData dataWithHexString:@"0630eebcd2856c24f798806e41f9e67345eda9ceda386acc9facaea1eeed06ace583709718d9d169fadf414d5c76f92996833ef305b75b1e4b95f662a20faedc3bae0c4827a8bf8a88edbd57ec203a27a841f02e43a615bab1a8cac0701de34debdef62a088089b55ec36ea7522fd3ec8d06b6a073e6df833153bc0aefd93bd1a3"],
905 },
906 {
907 .label = @"6-2",
908 .keys = keys[6],
909 .message = [NSData dataWithHexString:@"5cc72c60231df03b3d40f9b57931bc31109f972527f28b19e7480c7288cb3c92b22512214e4be6c914792ddabdf57faa8aa7"],
910 .seed = [NSData dataWithHexString:@"8d14bd946a1351148f5cae2ed9a0c653e85ebd85"],
911 .encryptedMessage = [NSData dataWithHexString:@"0ebc37376173a4fd2f89cc55c2ca62b26b11d51c3c7ce49e8845f74e7607317c436bc8d23b9667dfeb9d087234b47bc6837175ae5c0559f6b81d7d22416d3e50f4ac533d8f0812f2db9e791fe9c775ac8b6ad0f535ad9ceb23a4a02014c58ab3f8d3161499a260f39348e714ae2a1d3443208fd8b722ccfdfb393e98011f99e63f"],
912 },
913 {
914 .label = @"6-3",
915 .keys = keys[6],
916 .message = [NSData dataWithHexString:@"b20e651303092f4bccb43070c0f86d23049362ed96642fc5632c27db4a52e3d831f2ab068b23b149879c002f6bf3feee97591112562c"],
917 .seed = [NSData dataWithHexString:@"6c075bc45520f165c0bf5ea4c5df191bc9ef0e44"],
918 .encryptedMessage = [NSData dataWithHexString:@"0a98bf1093619394436cf68d8f38e2f158fde8ea54f3435f239b8d06b8321844202476aeed96009492480ce3a8d705498c4c8c68f01501dc81db608f60087350c8c3b0bd2e9ef6a81458b7c801b89f2e4fe99d4900ba6a4b5e5a96d865dc676c7755928794130d6280a8160a190f2df3ea7cf9aa0271d88e9e6905ecf1c5152d65"],
919 },
920 {
921 .label = @"6-4",
922 .keys = keys[6],
923 .message = [NSData dataWithHexString:@"684e3038c5c041f7"],
924 .seed = [NSData dataWithHexString:@"3bbc3bd6637dfe12846901029bf5b0c07103439c"],
925 .encryptedMessage = [NSData dataWithHexString:@"008e7a67cacfb5c4e24bec7dee149117f19598ce8c45808fef88c608ff9cd6e695263b9a3c0ad4b8ba4c95238e96a8422b8535629c8d5382374479ad13fa39974b242f9a759eeaf9c83ad5a8ca18940a0162ba755876df263f4bd50c6525c56090267c1f0e09ce0899a0cf359e88120abd9bf893445b3cae77d3607359ae9a52f8"],
926 },
927 {
928 .label = @"6-5",
929 .keys = keys[6],
930 .message = [NSData dataWithHexString:@"32488cb262d041d6e4dd35f987bf3ca696db1f06ac29a44693"],
931 .seed = [NSData dataWithHexString:@"b46b41893e8bef326f6759383a83071dae7fcabc"],
932 .encryptedMessage = [NSData dataWithHexString:@"00003474416c7b68bdf961c385737944d7f1f40cb395343c693cc0b4fe63b31fedf1eaeeac9ccc0678b31dc32e0977489514c4f09085f6298a9653f01aea4045ff582ee887be26ae575b73eef7f3774921e375a3d19adda0ca31aa1849887c1f42cac9677f7a2f4e923f6e5a868b38c084ef187594dc9f7f048fea2e02955384ab"],
933 },
934 {
935 .label = @"6-6",
936 .keys = keys[6],
937 .message = [NSData dataWithHexString:@"50ba14be8462720279c306ba"],
938 .seed = [NSData dataWithHexString:@"0a2403312a41e3d52f060fbc13a67de5cf7609a7"],
939 .encryptedMessage = [NSData dataWithHexString:@"0a026dda5fc8785f7bd9bf75327b63e85e2c0fdee5dadb65ebdcac9ae1de95c92c672ab433aa7a8e69ce6a6d8897fac4ac4a54de841ae5e5bbce7687879d79634cea7a30684065c714d52409b928256bbf53eabcd5231eb7259504537399bd29164b726d33a46da701360a4168a091ccab72d44a62fed246c0ffea5b1348ab5470"],
940 },
941 {
942 .label = @"7-1",
943 .keys = keys[7],
944 .message = [NSData dataWithHexString:@"47aae909"],
945 .seed = [NSData dataWithHexString:@"43dd09a07ff4cac71caa4632ee5e1c1daee4cd8f"],
946 .encryptedMessage = [NSData dataWithHexString:@"1688e4ce7794bba6cb7014169ecd559cede2a30b56a52b68d9fe18cf1973ef97b2a03153951c755f6294aa49adbdb55845ab6875fb3986c93ecf927962840d282f9e54ce8b690f7c0cb8bbd73440d9571d1b16cd9260f9eab4783cc482e5223dc60973871783ec27b0ae0fd47732cbc286a173fc92b00fb4ba6824647cd93c85c1"],
947 },
948 {
949 .label = @"7-2",
950 .keys = keys[7],
951 .message = [NSData dataWithHexString:@"1d9b2e2223d9bc13bfb9f162ce735db48ba7c68f6822a0a1a7b6ae165834e7"],
952 .seed = [NSData dataWithHexString:@"3a9c3cec7b84f9bd3adecbc673ec99d54b22bc9b"],
953 .encryptedMessage = [NSData dataWithHexString:@"1052ed397b2e01e1d0ee1c50bf24363f95e504f4a03434a08fd822574ed6b9736edbb5f390db10321479a8a139350e2bd4977c3778ef331f3e78ae118b268451f20a2f01d471f5d53c566937171b2dbc2d4bde459a5799f0372d6574239b2323d245d0bb81c286b63c89a361017337e4902f88a467f4c7f244bfd5ab46437ff3b6"],
954 },
955 {
956 .label = @"7-3",
957 .keys = keys[7],
958 .message = [NSData dataWithHexString:@"d976fc"],
959 .seed = [NSData dataWithHexString:@"76a75e5b6157a556cf8884bb2e45c293dd545cf5"],
960 .encryptedMessage = [NSData dataWithHexString:@"2155cd843ff24a4ee8badb7694260028a490813ba8b369a4cbf106ec148e5298707f5965be7d101c1049ea8584c24cd63455ad9c104d686282d3fb803a4c11c1c2e9b91c7178801d1b6640f003f5728df007b8a4ccc92bce05e41a27278d7c85018c52414313a5077789001d4f01910b72aad05d220aa14a58733a7489bc54556b"],
961 },
962 {
963 .label = @"7-4",
964 .keys = keys[7],
965 .message = [NSData dataWithHexString:@"d4738623df223aa43843df8467534c41d013e0c803c624e263666b239bde40a5f29aeb8de79e3daa61dd0370f49bd4b013834b98212aef6b1c5ee373b3cb"],
966 .seed = [NSData dataWithHexString:@"7866314a6ad6f2b250a35941db28f5864b585859"],
967 .encryptedMessage = [NSData dataWithHexString:@"0ab14c373aeb7d4328d0aaad8c094d88b9eb098b95f21054a29082522be7c27a312878b637917e3d819e6c3c568db5d843802b06d51d9e98a2be0bf40c031423b00edfbff8320efb9171bd2044653a4cb9c5122f6c65e83cda2ec3c126027a9c1a56ba874d0fea23f380b82cf240b8cf540004758c4c77d934157a74f3fc12bfac"],
968 },
969 {
970 .label = @"7-5",
971 .keys = keys[7],
972 .message = [NSData dataWithHexString:@"bb47231ca5ea1d3ad46c99345d9a8a61"],
973 .seed = [NSData dataWithHexString:@"b2166ed472d58db10cab2c6b000cccf10a7dc509"],
974 .encryptedMessage = [NSData dataWithHexString:@"028387a318277434798b4d97f460068df5298faba5041ba11761a1cb7316b24184114ec500257e2589ed3b607a1ebbe97a6cc2e02bf1b681f42312a33b7a77d8e7855c4a6de03e3c04643f786b91a264a0d6805e2cea91e68177eb7a64d9255e4f27e713b7ccec00dc200ebd21c2ea2bb890feae4942df941dc3f97890ed347478"],
975 },
976 {
977 .label = @"7-6",
978 .keys = keys[7],
979 .message = [NSData dataWithHexString:@"2184827095d35c3f86f600e8e59754013296"],
980 .seed = [NSData dataWithHexString:@"52673bde2ca166c2aa46131ac1dc808d67d7d3b1"],
981 .encryptedMessage = [NSData dataWithHexString:@"14c678a94ad60525ef39e959b2f3ba5c097a94ff912b67dbace80535c187abd47d075420b1872152bba08f7fc31f313bbf9273c912fc4c0149a9b0cfb79807e346eb332069611bec0ff9bcd168f1f7c33e77313cea454b94e2549eecf002e2acf7f6f2d2845d4fe0aab2e5a92ddf68c480ae11247935d1f62574842216ae674115"],
982 },
983 {
984 .label = @"8-1",
985 .keys = keys[8],
986 .message = [NSData dataWithHexString:@"050b755e5e6880f7b9e9d692a74c37aae449b31bfea6deff83747a897f6c2c825bb1adbf850a3c96994b5de5b33cbc7d4a17913a7967"],
987 .seed = [NSData dataWithHexString:@"7706ffca1ecfb1ebee2a55e5c6e24cd2797a4125"],
988 .encryptedMessage = [NSData dataWithHexString:@"09b3683d8a2eb0fb295b62ed1fb9290b714457b7825319f4647872af889b30409472020ad12912bf19b11d4819f49614824ffd84d09c0a17e7d17309d12919790410aa2995699f6a86dbe3242b5acc23af45691080d6b1ae810fb3e3057087f0970092ce00be9562ff4053b6262ce0caa93e13723d2e3a5ba075d45f0d61b54b61"],
989 },
990 {
991 .label = @"8-2",
992 .keys = keys[8],
993 .message = [NSData dataWithHexString:@"4eb68dcd93ca9b19df111bd43608f557026fe4aa1d5cfac227a3eb5ab9548c18a06dded23f81825986b2fcd71109ecef7eff88873f075c2aa0c469f69c92bc"],
994 .seed = [NSData dataWithHexString:@"a3717da143b4dcffbc742665a8fa950585548343"],
995 .encryptedMessage = [NSData dataWithHexString:@"2ecf15c97c5a15b1476ae986b371b57a24284f4a162a8d0c8182e7905e792256f1812ba5f83f1f7a130e42dcc02232844edc14a31a68ee97ae564a383a3411656424c5f62ddb646093c367be1fcda426cf00a06d8acb7e57776fbbd855ac3df506fc16b1d7c3f2110f3d8068e91e186363831c8409680d8da9ecd8cf1fa20ee39d"],
996 },
997 {
998 .label = @"8-3",
999 .keys = keys[8],
1000 .message = [NSData dataWithHexString:@"8604ac56328c1ab5ad917861"],
1001 .seed = [NSData dataWithHexString:@"ee06209073cca026bb264e5185bf8c68b7739f86"],
1002 .encryptedMessage = [NSData dataWithHexString:@"4bc89130a5b2dabb7c2fcf90eb5d0eaf9e681b7146a38f3173a3d9cfec52ea9e0a41932e648a9d69344c50da763f51a03c95762131e8052254dcd2248cba40fd31667786ce05a2b7b531ac9dac9ed584a59b677c1a8aed8c5d15d68c05569e2be780bf7db638fd2bfd2a85ab276860f3777338fca989ffd743d13ee08e0ca9893f"],
1003 },
1004 {
1005 .label = @"8-4",
1006 .keys = keys[8],
1007 .message = [NSData dataWithHexString:@"fdda5fbf6ec361a9d9a4ac68af216a0686f438b1e0e5c36b955f74e107f39c0dddcc"],
1008 .seed = [NSData dataWithHexString:@"990ad573dc48a973235b6d82543618f2e955105d"],
1009 .encryptedMessage = [NSData dataWithHexString:@"2e456847d8fc36ff0147d6993594b9397227d577752c79d0f904fcb039d4d812fea605a7b574dd82ca786f93752348438ee9f5b5454985d5f0e1699e3e7ad175a32e15f03deb042ab9fe1dd9db1bb86f8c089ccb45e7ef0c5ee7ca9b7290ca6b15bed47039788a8a93ff83e0e8d6244c71006362deef69b6f416fb3c684383fbd0"],
1010 },
1011 {
1012 .label = @"8-5",
1013 .keys = keys[8],
1014 .message = [NSData dataWithHexString:@"4a5f4914bee25de3c69341de07"],
1015 .seed = [NSData dataWithHexString:@"ecc63b28f0756f22f52ac8e6ec1251a6ec304718"],
1016 .encryptedMessage = [NSData dataWithHexString:@"1fb9356fd5c4b1796db2ebf7d0d393cc810adf6145defc2fce714f79d93800d5e2ac211ea8bbecca4b654b94c3b18b30dd576ce34dc95436ef57a09415645923359a5d7b4171ef22c24670f1b229d3603e91f76671b7df97e7317c97734476d5f3d17d21cf82b5ba9f83df2e588d36984fd1b584468bd23b2e875f32f68953f7b2"],
1017 },
1018 {
1019 .label = @"8-6",
1020 .keys = keys[8],
1021 .message = [NSData dataWithHexString:@"8e07d66f7b880a72563abcd3f35092bc33409fb7f88f2472be"],
1022 .seed = [NSData dataWithHexString:@"3925c71b362d40a0a6de42145579ba1e7dd459fc"],
1023 .encryptedMessage = [NSData dataWithHexString:@"3afd9c6600147b21798d818c655a0f4c9212db26d0b0dfdc2a7594ccb3d22f5bf1d7c3e112cd73fc7d509c7a8bafdd3c274d1399009f9609ec4be6477e453f075aa33db382870c1c3409aef392d7386ae3a696b99a94b4da0589447e955d16c98b17602a59bd736279fcd8fb280c4462d590bfa9bf13fed570eafde97330a2c210"],
1024 },
1025 {
1026 .label = @"9-1",
1027 .keys = keys[9],
1028 .message = [NSData dataWithHexString:@"f735fd55ba92592c3b52b8f9c4f69aaa1cbef8fe88add095595412467f9cf4ec0b896c59eda16210e7549c8abb10cdbc21a12ec9b6b5b8fd2f10399eb6"],
1029 .seed = [NSData dataWithHexString:@"8ec965f134a3ec9931e92a1ca0dc8169d5ea705c"],
1030 .encryptedMessage = [NSData dataWithHexString:@"267bcd118acab1fc8ba81c85d73003cb8610fa55c1d97da8d48a7c7f06896a4db751aa284255b9d36ad65f37653d829f1b37f97b8001942545b2fc2c55a7376ca7a1be4b1760c8e05a33e5aa2526b8d98e317088e7834c755b2a59b12631a182c05d5d43ab1779264f8456f515ce57dfdf512d5493dab7b7338dc4b7d78db9c091ac3baf537a69fc7f549d979f0eff9a94fda4169bd4d1d19a69c99e33c3b55490d501b39b1edae118ff6793a153261584d3a5f39f6e682e3d17c8cd1261fa72"],
1031 },
1032 {
1033 .label = @"9-2",
1034 .keys = keys[9],
1035 .message = [NSData dataWithHexString:@"81b906605015a63aabe42ddf11e1978912f5404c7474b26dce3ed482bf961ecc818bf420c54659"],
1036 .seed = [NSData dataWithHexString:@"ecb1b8b25fa50cdab08e56042867f4af5826d16c"],
1037 .encryptedMessage = [NSData dataWithHexString:@"93ac9f0671ec29acbb444effc1a5741351d60fdb0e393fbf754acf0de49761a14841df7772e9bc82773966a1584c4d72baea00118f83f35cca6e537cbd4d811f5583b29783d8a6d94cd31be70d6f526c10ff09c6fa7ce069795a3fcd0511fd5fcb564bcc80ea9c78f38b80012539d8a4ddf6fe81e9cddb7f50dbbbbcc7e5d86097ccf4ec49189fb8bf318be6d5a0715d516b49af191258cd32dc833ce6eb4673c03a19bbace88cc54895f636cc0c1ec89096d11ce235a265ca1764232a689ae8"],
1038 },
1039 {
1040 .label = @"9-3",
1041 .keys = keys[9],
1042 .message = [NSData dataWithHexString:@"fd326429df9b890e09b54b18b8f34f1e24"],
1043 .seed = [NSData dataWithHexString:@"e89bb032c6ce622cbdb53bc9466014ea77f777c0"],
1044 .encryptedMessage = [NSData dataWithHexString:@"81ebdd95054b0c822ef9ad7693f5a87adfb4b4c4ce70df2df84ed49c04da58ba5fc20a19e1a6e8b7a3900b22796dc4e869ee6b42792d15a8eceb56c09c69914e813cea8f6931e4b8ed6f421af298d595c97f4789c7caa612c7ef360984c21b93edc5401068b5af4c78a8771b984d53b8ea8adf2f6a7d4a0ba76c75e1dd9f658f20ded4a46071d46d7791b56803d8fea7f0b0f8e41ae3f09383a6f9585fe7753eaaffd2bf94563108beecc207bbb535f5fcc705f0dde9f708c62f49a9c90371d3"],
1045 },
1046 {
1047 .label = @"9-4",
1048 .keys = keys[9],
1049 .message = [NSData dataWithHexString:@"f1459b5f0c92f01a0f723a2e5662484d8f8c0a20fc29dad6acd43bb5f3effdf4e1b63e07fdfe6628d0d74ca19bf2d69e4a0abf86d293925a796772f8088e"],
1050 .seed = [NSData dataWithHexString:@"606f3b99c0b9ccd771eaa29ea0e4c884f3189ccc"],
1051 .encryptedMessage = [NSData dataWithHexString:@"bcc35f94cde66cb1136625d625b94432a35b22f3d2fa11a613ff0fca5bd57f87b902ccdc1cd0aebcb0715ee869d1d1fe395f6793003f5eca465059c88660d446ff5f0818552022557e38c08a67ead991262254f10682975ec56397768537f4977af6d5f6aaceb7fb25dec5937230231fd8978af49119a29f29e424ab8272b47562792d5c94f774b8829d0b0d9f1a8c9eddf37574d5fa248eefa9c5271fc5ec2579c81bdd61b410fa61fe36e424221c113addb275664c801d34ca8c6351e4a858"],
1052 },
1053 {
1054 .label = @"9-5",
1055 .keys = keys[9],
1056 .message = [NSData dataWithHexString:@"53e6e8c729d6f9c319dd317e74b0db8e4ccca25f3c8305746e137ac63a63ef3739e7b595abb96e8d55e54f7bd41ab433378ffb911d"],
1057 .seed = [NSData dataWithHexString:@"fcbc421402e9ecabc6082afa40ba5f26522c840e"],
1058 .encryptedMessage = [NSData dataWithHexString:@"232afbc927fa08c2f6a27b87d4a5cb09c07dc26fae73d73a90558839f4fd66d281b87ec734bce237ba166698ed829106a7de6942cd6cdce78fed8d2e4d81428e66490d036264cef92af941d3e35055fe3981e14d29cbb9a4f67473063baec79a1179f5a17c9c1832f2838fd7d5e59bb9659d56dce8a019edef1bb3accc697cc6cc7a778f60a064c7f6f5d529c6210262e003de583e81e3167b89971fb8c0e15d44fffef89b53d8d64dd797d159b56d2b08ea5307ea12c241bd58d4ee278a1f2e"],
1059 },
1060 {
1061 .label = @"9-6",
1062 .keys = keys[9],
1063 .message = [NSData dataWithHexString:@"b6b28ea2198d0c1008bc64"],
1064 .seed = [NSData dataWithHexString:@"23aade0e1e08bb9b9a78d2302a52f9c21b2e1ba2"],
1065 .encryptedMessage = [NSData dataWithHexString:@"438cc7dc08a68da249e42505f8573ba60e2c2773d5b290f4cf9dff718e842081c383e67024a0f29594ea987b9d25e4b738f285970d195abb3a8c8054e3d79d6b9c9a8327ba596f1259e27126674766907d8d582ff3a8476154929adb1e6d1235b2ccb4ec8f663ba9cc670a92bebd853c8dbf69c6436d016f61add836e94732450434207f9fd4c43dec2a12a958efa01efe2669899b5e604c255c55fb7166de5589e369597bb09168c06dd5db177e06a1740eb2d5c82faeca6d92fcee9931ba9f"],
1066 },
1067 {
1068 .label = @"10-1",
1069 .keys = keys[10],
1070 .message = [NSData dataWithHexString:@"8bba6bf82a6c0f86d5f1756e97956870b08953b06b4eb205bc1694ee"],
1071 .seed = [NSData dataWithHexString:@"47e1ab7119fee56c95ee5eaad86f40d0aa63bd33"],
1072 .encryptedMessage = [NSData dataWithHexString:@"53ea5dc08cd260fb3b858567287fa91552c30b2febfba213f0ae87702d068d19bab07fe574523dfb42139d68c3c5afeee0bfe4cb7969cbf382b804d6e61396144e2d0e60741f8993c3014b58b9b1957a8babcd23af854f4c356fb1662aa72bfcc7e586559dc4280d160c126785a723ebeebeff71f11594440aaef87d10793a8774a239d4a04c87fe1467b9daf85208ec6c7255794a96cc29142f9a8bd418e3c1fd67344b0cd0829df3b2bec60253196293c6b34d3f75d32f213dd45c6273d505adf4cced1057cb758fc26aeefa441255ed4e64c199ee075e7f16646182fdb464739b68ab5daff0e63e9552016824f054bf4d3c8c90a97bb6b6553284eb429fcc"],
1073 },
1074 {
1075 .label = @"10-2",
1076 .keys = keys[10],
1077 .message = [NSData dataWithHexString:@"e6ad181f053b58a904f2457510373e57"],
1078 .seed = [NSData dataWithHexString:@"6d17f5b4c1ffac351d195bf7b09d09f09a4079cf"],
1079 .encryptedMessage = [NSData dataWithHexString:@"a2b1a430a9d657e2fa1c2bb5ed43ffb25c05a308fe9093c01031795f5874400110828ae58fb9b581ce9dddd3e549ae04a0985459bde6c626594e7b05dc4278b2a1465c1368408823c85e96dc66c3a30983c639664fc4569a37fe21e5a195b5776eed2df8d8d361af686e750229bbd663f161868a50615e0c337bec0ca35fec0bb19c36eb2e0bbcc0582fa1d93aacdb061063f59f2ce1ee43605e5d89eca183d2acdfe9f81011022ad3b43a3dd417dac94b4e11ea81b192966e966b182082e71964607b4f8002f36299844a11f2ae0faeac2eae70f8f4f98088acdcd0ac556e9fccc511521908fad26f04c64201450305778758b0538bf8b5bb144a828e629795"],
1080 },
1081 {
1082 .label = @"10-3",
1083 .keys = keys[10],
1084 .message = [NSData dataWithHexString:@"510a2cf60e866fa2340553c94ea39fbc256311e83e94454b4124"],
1085 .seed = [NSData dataWithHexString:@"385387514deccc7c740dd8cdf9daee49a1cbfd54"],
1086 .encryptedMessage = [NSData dataWithHexString:@"9886c3e6764a8b9a84e84148ebd8c3b1aa8050381a78f668714c16d9cfd2a6edc56979c535d9dee3b44b85c18be8928992371711472216d95dda98d2ee8347c9b14dffdff84aa48d25ac06f7d7e65398ac967b1ce90925f67dce049b7f812db0742997a74d44fe81dbe0e7a3feaf2e5c40af888d550ddbbe3bc20657a29543f8fc2913b9bd1a61b2ab2256ec409bbd7dc0d17717ea25c43f42ed27df8738bf4afc6766ff7aff0859555ee283920f4c8a63c4a7340cbafddc339ecdb4b0515002f96c932b5b79167af699c0ad3fccfdf0f44e85a70262bf2e18fe34b850589975e867ff969d48eabf212271546cdc05a69ecb526e52870c836f307bd798780ede"],
1087 },
1088 {
1089 .label = @"10-4",
1090 .keys = keys[10],
1091 .message = [NSData dataWithHexString:@"bcdd190da3b7d300df9a06e22caae2a75f10c91ff667b7c16bde8b53064a2649a94045c9"],
1092 .seed = [NSData dataWithHexString:@"5caca6a0f764161a9684f85d92b6e0ef37ca8b65"],
1093 .encryptedMessage = [NSData dataWithHexString:@"6318e9fb5c0d05e5307e1683436e903293ac4642358aaa223d7163013aba87e2dfda8e60c6860e29a1e92686163ea0b9175f329ca3b131a1edd3a77759a8b97bad6a4f8f4396f28cf6f39ca58112e48160d6e203daa5856f3aca5ffed577af499408e3dfd233e3e604dbe34a9c4c9082de65527cac6331d29dc80e0508a0fa7122e7f329f6cca5cfa34d4d1da417805457e008bec549e478ff9e12a763c477d15bbb78f5b69bd57830fc2c4ed686d79bc72a95d85f88134c6b0afe56a8ccfbc855828bb339bd17909cf1d70de3335ae07039093e606d655365de6550b872cd6de1d440ee031b61945f629ad8a353b0d40939e96a3c450d2a8d5eee9f678093c8"],
1094 },
1095 {
1096 .label = @"10-5",
1097 .keys = keys[10],
1098 .message = [NSData dataWithHexString:@"a7dd6c7dc24b46f9dd5f1e91ada4c3b3df947e877232a9"],
1099 .seed = [NSData dataWithHexString:@"95bca9e3859894b3dd869fa7ecd5bbc6401bf3e4"],
1100 .encryptedMessage = [NSData dataWithHexString:@"75290872ccfd4a4505660d651f56da6daa09ca1301d890632f6a992f3d565cee464afded40ed3b5be9356714ea5aa7655f4a1366c2f17c728f6f2c5a5d1f8e28429bc4e6f8f2cff8da8dc0e0a9808e45fd09ea2fa40cb2b6ce6ffff5c0e159d11b68d90a85f7b84e103b09e682666480c657505c0929259468a314786d74eab131573cf234bf57db7d9e66cc6748192e002dc0deea930585f0831fdcd9bc33d51f79ed2ffc16bcf4d59812fcebcaa3f9069b0e445686d644c25ccf63b456ee5fa6ffe96f19cdf751fed9eaf35957754dbf4bfea5216aa1844dc507cb2d080e722eba150308c2b5ff1193620f1766ecf4481bafb943bd292877f2136ca494aba0"],
1101 },
1102 {
1103 .label = @"10-6",
1104 .keys = keys[10],
1105 .message = [NSData dataWithHexString:@"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac"],
1106 .seed = [NSData dataWithHexString:@"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32"],
1107 .encryptedMessage = [NSData dataWithHexString:@"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46"],
1108 },
1109
1110 };
1111
1112 int max_cycles = 100;
1113 if (!getenv("SUBMISSION_TEST")) {
1114 max_cycles = 10;
1115 CFfprintf(stderr, "Running the far faster but far less reliable fast test.\nSet the SUBMISSION_TEST environment variable for full testing\n");
1116 }
1117
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;
1123
1124 SecTransformRef encryptor = SecEncryptTransformCreate(tests[i].keys.pubKey, &err);
1125
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);
1130
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);
1137
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);
1150 }
1151 }
1152
1153 return;
1154 }
1155
1156 -(void)testNoSignKeyMakesError
1157 {
1158 NSData *data = [NSData dataWithBytes:"" length:1];
1159
1160 struct test_case {
1161 NSString *name;
1162 CFErrorRef createError;
1163 SecTransformRef transform;
1164 } test_cases[] = {
1165 {
1166 .name = @"Sign",
1167 .createError = NULL,
1168 .transform = SecSignTransformCreate(NULL, &(test_cases[0].createError))
1169 },
1170 {
1171 .name = @"Verify",
1172 .createError = NULL,
1173 .transform = SecVerifyTransformCreate(NULL, (CFDataRef)data, &(test_cases[1].createError))
1174 }
1175 };
1176
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) {
1182 continue;
1183 }
1184
1185 __block CFErrorRef err = NULL;
1186 SecTransformSetAttribute(test->transform, kSecTransformInputAttributeName, data, &err);
1187 STAssertNil((id)err, @"Error setting input for %@: %@", test->name, err);
1188
1189 dispatch_group_t execute_done = dispatch_group_create();
1190 dispatch_group_enter(execute_done);
1191
1192 SecTransformExecuteAsync(test->transform, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
1193 if (error) {
1194 err = error;
1195 }
1196 if (isFinal) {
1197 dispatch_group_leave(execute_done);
1198 }
1199 });
1200
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);
1205 });
1206 }
1207 }
1208
1209 -(void)testHMAC
1210 {
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;
1216 CFDataRef result;
1217 CFDataRef rightAnswer;
1218 CFComparisonResult ok;
1219
1220 // create the object
1221 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA1, 20, &error);
1222 STAssertNil((id) error, @"Unexpected error returned.");
1223
1224 // set the key
1225 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error);
1226 STAssertNil((id) error, @"Unexpected error returned.");
1227
1228 // digest the data
1229 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error);
1230 STAssertNil((id) error, @"Unexpected error returned.");
1231
1232 result = (CFDataRef) SecTransformExecute(hmacRef, &error);
1233 if (error)
1234 {
1235 CFShow(error);
1236 STAssertNil((id) error, @"Unexpected error returned.");
1237 CFRelease(error);
1238 }
1239
1240 STAssertNotNil((id) result, @"No data returned for SHA1");
1241
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);
1246 CFRelease(hmacRef);
1247 CFRelease(result);
1248
1249 if (error)
1250 {
1251 CFRelease(error);
1252 }
1253
1254 STAssertTrue(ok, @"Digest returned incorrect HMACSHA1 result.");
1255
1256 //+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
1257
1258 // create the object
1259 hmacRef = SecDigestTransformCreate(kSecDigestHMACSHA2, 256, &error);
1260 STAssertNil((id) error, @"Unexpected error returned.");
1261
1262 // set the key
1263 SecTransformSetAttribute(hmacRef, kSecDigestHMACKeyAttribute, hmacKey, &error);
1264 STAssertNil((id) error, @"Unexpected error returned.");
1265
1266 // digest the data
1267 SecTransformSetAttribute(hmacRef, kSecTransformInputAttributeName, hmacData, &error);
1268 STAssertNil((id) error, @"Unexpected error returned.");
1269
1270 result = (CFDataRef) SecTransformExecute(hmacRef, &error);
1271 if (error != nil)
1272 {
1273 CFShow(error);
1274 STAssertNil((id) error, @"Unexpected error returned.");
1275 CFRelease(error);
1276 }
1277
1278 STAssertNotNil((id) result, @"No data returned for SHA256");
1279
1280 rightAnswer = CFDataCreate(NULL, gSHA256HMAC, sizeof(gSHA256HMAC));
1281 ok = CFEqual(result, rightAnswer);
1282
1283 CFRelease(rightAnswer);
1284 CFRelease(hmacRef);
1285
1286 CFRelease(hmacData);
1287 CFRelease(hmacKey);
1288 CFRelease(result);
1289
1290 STAssertTrue(ok, @"Digest returned incorrect HMACSHA256 result.");
1291 }
1292
1293
1294
1295 -(void)echoParams:(NSString*)p1 p2:(NSString*)p2
1296 {
1297 }
1298
1299 -(void)testReadStreamTransform
1300 {
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");
1309
1310 CFReadStreamRef readStreamRef = CFReadStreamCreateWithFile(NULL, url);
1311 SecTransformRef transform = SecTransformCreateReadTransformWithReadStream(readStreamRef);
1312 STAssertNotNil((id) transform, @"Returned transform should not be nil.");
1313
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;
1317
1318 SecTransformExecuteAsync(transform, queue,
1319 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
1320 {
1321 if (message)
1322 {
1323 bytes_presented += CFDataGetLength((CFDataRef)message);
1324 }
1325 if (isFinal)
1326 {
1327 STAssertNil((id)error, @"Unexpected error!");
1328 dispatch_semaphore_signal(waitSemaphore);
1329 }
1330 });
1331
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);
1336
1337 dispatch_release(queue);
1338 dispatch_release(waitSemaphore);
1339 CFRelease(transform);
1340 CFRelease(readStreamRef);
1341 CFRelease(url);
1342 CFRelease(resolved_url);
1343 }
1344
1345 -(void)testMGF
1346 {
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;
1352
1353 SecTransformRef mgfTransform = SecCreateMaskGenerationFunctionTransform(NULL, 107, &err);
1354 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err);
1355 err = NULL;
1356 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, seed, &err);
1357 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err);
1358 err = NULL;
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");
1362
1363 CFRelease(mgfTransform);
1364 // XXX: leak test??
1365
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};
1367
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));
1371 err = NULL;
1372
1373 mgfTransform = SecCreateMaskGenerationFunctionTransform(kSecDigestSHA1, 20, &err);
1374 STAssertNotNil((id)mgfTransform, @"Expected to create a MGF transform e=%@", err);
1375 err = NULL;
1376 SecTransformSetAttribute(mgfTransform, kSecTransformInputAttributeName, maskedDB, &err);
1377 STAssertNil((id)err, @"Expected no error setting MGF's input, got %@", err);
1378 err = NULL;
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");
1382 }
1383
1384 -(void)testAbortParams
1385 {
1386 // make a simple transform
1387 SecTransformRef a = SecNullTransformCreate();
1388
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)
1394 {
1395 CFRelease(errorRef);
1396 }
1397
1398 CFRelease(a);
1399
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();
1406
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);
1411
1412 SecTransformSetAttribute(pass_through, kSecTransformInputAttributeName, dev_null_stream, NULL);
1413 SecTransformConnectTransforms(pass_through, kSecTransformOutputAttributeName, null_abort, kSecTransformAbortAttributeName, test_null_abort_via_connection, NULL);
1414
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);
1418
1419
1420 CFErrorRef err = NULL;
1421 CFTypeRef not_null = SecTransformExecute(test_null_abort_via_connection, &err);
1422
1423 STAssertNotNil((id)not_null, @"aborted via a NULL from a connection? err=%@", err);
1424
1425 if (err)
1426 {
1427 CFRelease(err);
1428 }
1429
1430 CFRelease(test_null_abort_via_connection);
1431 CFRelease(pass_through);
1432 CFRelease(null_abort);
1433 CFRelease(delay_null);
1434
1435 CFReadStreamClose(dev_null_stream);
1436 CFRelease(dev_null_stream);
1437 }
1438
1439
1440 -(void)testDisconnect
1441 {
1442 SecTransformRef a = SecNullTransformCreate();
1443 SecTransformRef b = SecNullTransformCreate();
1444 SecTransformRef c = SecNullTransformCreate();
1445 SecGroupTransformRef g = SecTransformCreateGroupTransform();
1446
1447 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, g, NULL);
1448 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName, g, NULL);
1449
1450 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName);
1451 STAssertTrue(SecGroupTransformHasMember(g, a), @"A should still be in the group, but isn't");
1452
1453 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, c, kSecTransformInputAttributeName);
1454 STAssertFalse(SecGroupTransformHasMember(g, a), @"A should no longer be in the group, but is");
1455
1456 CFRelease(g);
1457 CFRelease(c);
1458 CFRelease(b);
1459 CFRelease(a);
1460 }
1461
1462
1463 -(void)testAbort
1464 {
1465 CFStringRef abort_test_name = CFSTR("com.apple.security.unit-test.abortTest");
1466
1467 SecTransformCreateBlock setupBlock =
1468 ^(CFStringRef name, SecTransformRef new_transform, const SecTransformCreateBlockParameters *params)
1469 {
1470 params->send(kSecTransformInputAttributeName, kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
1471
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;
1476 });
1477 };
1478
1479
1480 SecTransformRef a;
1481 SecTransformRef dt;
1482 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1483
1484 // make two of these transforms and link them together
1485 a = custom_transform(abort_test_name, setupBlock);
1486 STAssertNotNil((id) a, @"SecCustomTransformCreate failed");
1487
1488 dt = delay_transform(NSEC_PER_SEC / 10);
1489 STAssertNotNil((id) dt, @"SecCustomTransformCreate failed");
1490
1491 // connect the two transforms
1492 CFErrorRef error;
1493
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.");
1497
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.");
1501
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};
1504
1505 CFDataRef dataRef = CFDataCreateWithBytesNoCopy(NULL, data, sizeof(data), kCFAllocatorNull);
1506 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, dataRef, NULL);
1507
1508 CFStringRef str = CFStringCreateMutable(NULL, 0);
1509 SecTransformSetAttribute(a, CFSTR("PB"), str, NULL);
1510
1511 CFTypeRef er = SecTransformExecute(a, &error);
1512
1513 STAssertNil((id)er, @"Didn't expect an result from aborted transform");
1514 STAssertNotNil((id)error, @"Expected error from execute");
1515
1516 if (error)
1517 {
1518 CFShow(error);
1519
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.");
1523 CFRelease(error);
1524 }
1525
1526 CFRelease(a);
1527 CFRelease(dt);
1528 CFRelease(group);
1529 CFRelease(dataRef);
1530
1531 /*
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");
1535 */
1536 }
1537
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");
1546 CFRelease(error);
1547 }
1548
1549 #ifdef DEBUG
1550 -(void)testFireAndForget
1551 {
1552 bool isGC = false;
1553 NSGarbageCollector* gc = [NSGarbageCollector defaultCollector];
1554 if (gc)
1555 {
1556 isGC = [gc isEnabled];
1557 }
1558
1559 CFIndex retCount = 0;
1560
1561 // make transforms
1562 SecNullTransformRef a = SecNullTransformCreate();
1563 SecNullTransformRef b = SecNullTransformCreate();
1564 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1565 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL);
1566
1567 if (!isGC)
1568 {
1569 retCount = CFGetRetainCount(group);
1570 }
1571
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);
1576 CFRelease(dataRef);
1577
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);
1585
1586 // launch the chain
1587 SecTransformExecuteAsync(group, queue,
1588 ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
1589 {
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()));
1592 if (isFinal)
1593 {
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);
1597 }
1598 });
1599 CFRelease(a);
1600 CFRelease(b);
1601 CFRelease(group);
1602 dispatch_semaphore_signal(semaphore2);
1603 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
1604
1605 // no crash? Life is good.
1606 }
1607 #endif
1608
1609 -(void)testExternalSource
1610 {
1611 CFErrorRef err = NULL;
1612 SecTransformRef xs = SecExternalSourceTransformCreate(&err);
1613 SecTransformRef tee = SecNullTransformCreate();
1614 SecTransformRef group = SecTransformCreateGroupTransform();
1615
1616 SecTransformConnectTransforms(xs, kSecTransformOutputAttributeName, tee, kSecTransformInputAttributeName, group, &err);
1617
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;
1622
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);
1625
1626 if (message) {
1627 if (CFEqual(message, CFSTR("PING"))) {
1628 got_ping = true;
1629 } else {
1630 STFail(@"expected ping, got: %@", message);
1631 }
1632 }
1633
1634 if (error) {
1635 STFail(@"unexpected error: %@", error);
1636 }
1637
1638 if (isFinal) {
1639 if (!got_ping) {
1640 STFail(@"never got ping");
1641 }
1642 dispatch_group_leave(dg);
1643 }
1644 });
1645
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);
1649 CFRelease(err);
1650 err = NULL;
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);
1656
1657 dispatch_release(dg);
1658 dispatch_release(q);
1659 CFRelease(xs);
1660 CFRelease(tee);
1661 CFRelease(group);
1662 }
1663
1664 -(void)testFindLastAndMonitor
1665 {
1666 SecNullTransformRef a = delay_transform(NSEC_PER_SEC / 10);
1667 SecNullTransformRef b = SecNullTransformCreate();
1668
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.");
1675
1676
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");
1682
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)
1689 {
1690 if (isFinal)
1691 {
1692 dispatch_semaphore_signal(last_block_run);
1693 dispatch_semaphore_wait(last_assert_run, DISPATCH_TIME_FOREVER);
1694 dispatch_release(last_assert_run);
1695 }
1696
1697 });
1698
1699 dispatch_semaphore_wait(last_block_run, DISPATCH_TIME_FOREVER);
1700
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");
1706
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");
1712
1713 dispatch_semaphore_signal(last_assert_run);
1714 dispatch_release(queue);
1715 dispatch_release(last_block_run);
1716 CFRelease(a);
1717 CFRelease(b);
1718 CFRelease(groupRef);
1719 }
1720
1721
1722 -(void)testConnectUnsetAttributes /* <rdar://problem/7769955> Can't connect transform attributes with no setting */
1723 {
1724 SecNullTransformRef a = SecNullTransformCreate();
1725 SecNullTransformRef b = SecNullTransformCreate();
1726
1727 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1728 CFErrorRef error = NULL;
1729 SecTransformConnectTransforms(a, CFSTR("RANDOM_NAME"), b, CFSTR("RANDOM_DESTINATION"), group, &error);
1730 CFRelease(group);
1731 CFRelease(b);
1732 CFRelease(a);
1733 STAssertNil((id) error, @"An error was returned when none was expected.");
1734 }
1735
1736 -(void)testNoDataFlowPriorToInit /* <rdar://problem/8163542> Monitor must be attached before the data flow becomes active */
1737 {
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"));
1746
1747 params->overrideTransform(kSecTransformActionStartingExecution, ^{
1748 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("x-start"));
1749 inited = true;
1750 return (CFTypeRef)NULL;
1751 });
1752
1753 params->overrideTransform(kSecTransformActionCanExecute, ^{
1754 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("can-x"));
1755 return (CFTypeRef)NULL;
1756 });
1757
1758 params->overrideAttribute(kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^(SecTransformAttributeRef ah, CFTypeRef value) {
1759 if (inited) {
1760 if (value) {
1761 if (!saw_x_start) {
1762 saw_x_start = CFStringHasPrefix((CFStringRef)value, CFSTR("x-start"));
1763 }
1764 if (saw_null) {
1765 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 88, "saw %@ after NULL", value));
1766 }
1767 if (post_send_left--) {
1768 params->send(out_ah, kSecTransformMetaAttributeValue, CFSTR("post-init"));
1769 }
1770 } else {
1771 saw_null = true;
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)) {
1775 if (saw_x_start) {
1776 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "saw bogus x-start on FIRST flow transform"));
1777 } else {
1778 params->send(out_ah, kSecTransformMetaAttributeValue, value);
1779 }
1780 } else {
1781 if (saw_x_start) {
1782 params->send(out_ah, kSecTransformMetaAttributeValue, value);
1783 } else {
1784 params->send(kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateGenericErrorRef(name, 42, "never saw x-start before EOS"));
1785 return (CFTypeRef)kCFNull;
1786 }
1787 }
1788 }
1789 } else {
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;
1793 }
1794 return (CFTypeRef)value;
1795 });
1796 };
1797
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;
1802
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");
1806 }
1807
1808 int i;
1809 CFMutableArrayRef ta = CFArrayCreateMutable(NULL, n_transforms, &kCFTypeArrayCallBacks);
1810 CFErrorRef err = NULL;
1811
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);
1819 }
1820 CFRelease(l);
1821 STAssertNil((id)err, @"Can't set name %@", err);
1822 CFArrayAppendValue(ta, tr);
1823 assert(CFArrayGetCount(ta));
1824 assert(CFArrayGetCount(ta) == i+1);
1825 }
1826
1827 SecTransformRef prev_tr = NULL;
1828 SecTransformRef group = SecTransformCreateGroupTransform();
1829 CFIndex cnt;
1830
1831 while ((cnt = CFArrayGetCount(ta))) {
1832 CFIndex r = arc4random() % cnt;
1833 SecTransformRef tr = CFArrayGetValueAtIndex(ta, r);
1834 if (prev_tr) {
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");
1838 CFRelease(prev_tr);
1839 }
1840 prev_tr = tr;
1841 CFArrayRemoveValueAtIndex(ta, r);
1842
1843 if (0 == cnt % 1000) {
1844 CFfprintf(stderr, "%d left to hook up\n", cnt);
1845 }
1846 }
1847
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");
1857 CFRelease(group);
1858 CFRelease(prev_tr);
1859 }
1860
1861 -(void)testNoDataDescription /* <rdar://problem/7791122> CFShow(SecCustomTransformNoData()) crashes */
1862 {
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");
1865 CFRelease(result);
1866 }
1867
1868 static SecTransformInstanceBlock KnownProblemPlumbing(CFStringRef name,
1869 SecTransformRef newTransform,
1870 SecTransformImplementationRef ref)
1871 {
1872 SecTransformInstanceBlock instanceBlock =
1873 ^{
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);
1879
1880 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName,
1881 ^(SecTransformAttributeRef ah, CFTypeRef value)
1882 {
1883 return (CFTypeRef)CFErrorCreate(NULL, kCFErrorDomainPOSIX, EOPNOTSUPP, NULL);
1884 });
1885 return result;
1886 };
1887
1888 return Block_copy(instanceBlock);
1889 }
1890
1891 -(void)knownProblemPlumbing // note, this test has been disconnected!
1892 {
1893 SecNullTransformRef a = SecNullTransformCreate();
1894 CFStringRef name = CFSTR("com.apple.security.unit-test.error+outputless");
1895 CFErrorRef err = NULL;
1896
1897 SecTransformRegister(name, &KnownProblemPlumbing, &err);
1898
1899 SecTransformRef b = SecTransformCreate(name, NULL);
1900 SecGroupTransformRef group = SecTransformCreateGroupTransform();
1901
1902 SecTransformConnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName, group, NULL);
1903 SecTransformDisconnectTransforms(a, kSecTransformOutputAttributeName, b, kSecTransformInputAttributeName);
1904
1905
1906 CFStringRef data = CFSTR("Test");
1907
1908 SecTransformSetAttribute(a, kSecTransformInputAttributeName, data, NULL);
1909 CFTypeRef result = SecTransformExecute(a, &err);
1910
1911 STAssertEqualObjects((id)data, (id)result, @"Plumbing disconnect failed.");
1912 STAssertNil((id)err, @"Unexpected error=%@", err);
1913 CFRelease(a);
1914 CFRelease(b);
1915 CFRelease(group);
1916 }
1917
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);
1926 err1 = NULL;
1927
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);
1932
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);
1937 if (err3) {
1938 CFRelease(err3);
1939 err3 = NULL;
1940 }
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);
1945
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);
1952 } else {
1953 STFail(@"Unable to run some tests");
1954 }
1955
1956 CFRelease(no_type_at_create);
1957 CFRelease(invalid_encode_type);
1958 }
1959
1960 -(void)testNoUnderscores
1961 {
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);
1970 CFRelease(err);
1971 CFRelease(zt);
1972 }
1973
1974 -(void)testCanFetchDigestSizes
1975 {
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,
1982 nil];
1983 NSData *zero = [NSData dataWithBytes:"" length:1];
1984
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);
1994
1995 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, zero, &err);
1996 STAssertNil((id)err, @"Unexpected error: %@", err);
1997
1998 NSData *output = (NSData *)SecTransformExecute(digest, &err);
1999 STAssertNil((id)err, @"Unexpected error: %@", err);
2000 STAssertNotNil((id)output, @"No output");
2001
2002 STAssertEquals([actualLength intValue], (int)[output length], @"Actual output not expected length");
2003
2004 [output release];
2005 CFRelease(digest);
2006 }
2007 }
2008
2009 -(void)testBadTransformTypeNames
2010 {
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);
2015
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);
2019
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);
2023
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);
2027
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);
2030 }
2031
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];
2037
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;
2044
2045 SecTransformExecuteAsync(zt, q, ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
2046 if ([empty length]) {
2047 NSLog(@"Empty data not so empty");
2048 }
2049 STAssertTrue(dispatch_get_current_queue() == q, @"block dispatched to proper queue");
2050
2051 if (!ran_block) {
2052 usleep(200);
2053 ran_block = YES;
2054 }
2055
2056 if (message == NULL) {
2057 dispatch_resume((dispatch_object_t)q_sync);
2058 }
2059 });
2060
2061 STAssertTrue(ecnt < [empty retainCount], @"SecTransformExecute retained block");
2062 dispatch_sync(q_sync, ^{ });
2063 STAssertTrue(ran_block, @"Block executed");
2064
2065 dispatch_release(q_sync);
2066 dispatch_release(q);
2067 CFRelease(zt);
2068
2069 // test for 7735698
2070 // STAssertTrue(ecnt == [empty retainCount], @"SecTransformExecute released block");
2071 }
2072
2073 static SecTransformInstanceBlock ConnectionCheck(CFStringRef name,
2074 SecTransformRef newTransform,
2075 SecTransformImplementationRef ref)
2076 {
2077 SecTransformInstanceBlock instanceBlock =
2078 ^{
2079 CFErrorRef result = NULL;
2080 __block SecTransformMetaAttributeType dir = kSecTransformMetaAttributeValue;
2081
2082 SecTransformAttributeRef out_ah =
2083 SecTranformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef);
2084
2085 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DIRECTION"),
2086 ^(SecTransformAttributeRef ah, CFTypeRef value)
2087 {
2088 if (CFEqual(value, CFSTR("<")))
2089 {
2090 dir = kSecTransformMetaAttributeHasInboundConnection;
2091 }
2092 else if (CFEqual(value, CFSTR(">")))
2093 {
2094 dir = kSecTransformMetaAttributeHasOutboundConnections;
2095 }
2096 else
2097 {
2098 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unsupported direction %@, expected < or >", value);
2099 }
2100 return value;
2101 });
2102
2103 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2104 ^(SecTransformAttributeRef ah, CFTypeRef value)
2105 {
2106 if (dir != kSecTransformMetaAttributeValue)
2107 {
2108 if (value)
2109 {
2110 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue,
2111 SecTranformCustomGetAttribute(ref, value, dir));
2112 }
2113 else
2114 {
2115 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, NULL);
2116 }
2117 }
2118 else
2119 {
2120 SecTransformPushbackAttribute(ref, ah, value);
2121 }
2122
2123 return value;
2124 });
2125
2126 return result;
2127 };
2128
2129 return Block_copy(instanceBlock);
2130 }
2131
2132 -(void)testConnectionChecks {
2133
2134 CFStringRef name = CFSTR("com.apple.security.unit-test.connection-checks");
2135 CFErrorRef error = NULL;
2136 SecTransformRegister(name, &*ConnectionCheck, &error);
2137
2138 struct test_case {
2139 NSString *attr, *dir;
2140 CFBooleanRef expect;
2141 } cases[] = {
2142 {@"INPUT", @"<", kCFBooleanTrue},
2143 {@"OUTPUT", @">", kCFBooleanTrue},
2144 {@"INPUT", @">", kCFBooleanFalse},
2145 {@"OUTPUT", @"<", kCFBooleanFalse},
2146 {@"DIRECTION", @"<", kCFBooleanFalse},
2147 {@"DIRECTION", @">", kCFBooleanFalse},
2148 };
2149
2150 CFIndex i, n = sizeof(cases)/sizeof(test_case);
2151 for(i = 0; i < n; ++i)
2152 {
2153 test_case *t = cases + i;
2154
2155 SecTransformRef cct = SecTransformCreate(name, NULL);
2156 SecTransformRef tee0 = SecNullTransformCreate();
2157 SecTransformRef tee1 = SecNullTransformCreate();
2158 SecTransformRef group = SecTransformCreateGroupTransform();
2159
2160 SecTransformSetAttribute(cct, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2161 SecTransformSetAttribute(tee0, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2162 SecTransformSetAttribute(tee1, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2163
2164 SecTransformSetAttribute(tee0, CFSTR("NAME"), CFSTR("tee0"), NULL);
2165 SecTransformSetAttribute(tee1, CFSTR("NAME"), CFSTR("tee1"), NULL);
2166
2167 SecTransformConnectTransforms(cct, CFSTR("OUTPUT"), tee1, CFSTR("INPUT"), group, NULL);
2168 SecTransformConnectTransforms(tee0, CFSTR("OUTPUT"), cct, CFSTR("INPUT"), group, NULL);
2169
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);
2177
2178 CFRelease(cct);
2179 CFRelease(tee0);
2180 CFRelease(tee1);
2181 CFRelease(group);
2182 }
2183
2184 }
2185
2186 static SecTransformInstanceBlock PushBackTest(CFStringRef name,
2187 SecTransformRef newTransform,
2188 SecTransformImplementationRef ref)
2189 {
2190 SecTransformInstanceBlock instanceBlock =
2191 ^{
2192 CFErrorRef result = NULL;
2193 __block CFStringRef input_d = NULL;
2194 __block CFStringRef data_d = NULL;
2195
2196 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("DATA"),
2197 ^(SecTransformAttributeRef ah, CFTypeRef value)
2198 {
2199 if (!input_d)
2200 {
2201 SecTransformPushbackAttribute(ref, ah, value);
2202 }
2203 else
2204 {
2205 if (data_d)
2206 {
2207 CFRelease(data_d);
2208 }
2209 data_d = (CFStringRef)CFRetain(value);
2210 }
2211 return value;
2212 });
2213
2214 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2215 ^(SecTransformAttributeRef ah, CFTypeRef value)
2216 {
2217 if (value)
2218 {
2219 if (input_d)
2220 {
2221 CFRelease(input_d);
2222 }
2223 input_d = (CFStringRef)CFRetain(value);
2224 if (!data_d)
2225 {
2226 SecTransformPushbackAttribute(ref, ah, value);
2227 return value;
2228 }
2229 }
2230 else
2231 {
2232 if (data_d)
2233 {
2234 SecTransformPushbackAttribute(ref, ah, NULL);
2235 value = data_d;
2236 data_d = NULL;
2237 }
2238 }
2239 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
2240 return value;
2241 });
2242
2243 return result;
2244 };
2245
2246 return Block_copy(instanceBlock);
2247 }
2248
2249 -(void)testPushback {
2250
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");
2255
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.
2260
2261 CFErrorRef error = NULL;
2262 SecTransformRegister(name, &PushBackTest, &error);
2263
2264 SecTransformRef pt = SecTransformCreate(name, NULL);
2265
2266 SecTransformSetAttribute(pt, CFSTR("DATA"), two, NULL);
2267 SecTransformSetAttribute(pt, CFSTR("INPUT"), one, NULL);
2268
2269 CFTypeRef result = SecTransformExecute(pt, NULL);
2270
2271 STAssertEqualObjects((id)result, (id)expect, @"Testing pushback");
2272
2273 CFRelease(pt);
2274
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
2276
2277 }
2278
2279 static SecTransformInstanceBlock CustomExternalization(CFStringRef name,
2280 SecTransformRef newTransform,
2281 SecTransformImplementationRef ref)
2282 {
2283 SecTransformInstanceBlock instanceBlock =
2284 ^{
2285 CFErrorRef result = NULL;
2286 // Create a non-attribute 'instance' variable which will contain
2287 // the version number of this class
2288
2289 __block float versionNumber = 1.0;
2290
2291 // Register the custom externalize override
2292 SecTransformActionBlock ExternalizeExtraDataOverride =
2293 ^{
2294 CFStringRef key = CFSTR("VersionNumber");
2295 CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &versionNumber);
2296
2297 CFDictionaryRef result = CFDictionaryCreate(kCFAllocatorDefault,
2298 (const void **)&key, (const void **)&value,
2299 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2300
2301 CFRelease(value);
2302
2303
2304 return (CFTypeRef)result;
2305
2306 };
2307 SecTransformSetTransformAction(ref, kSecTransformActionExternalizeExtraData, ExternalizeExtraDataOverride);
2308
2309 // Register the custom internalize override
2310 SecTransformDataBlock InternalizeExtraDataOverride =
2311 ^(CFTypeRef d)
2312 {
2313 CFTypeRef internalizeResult = NULL;
2314 id testObj = (id)d;
2315
2316 //STAssertNotNil(testObj, @"Internalize did NOT get a dictionary!");
2317
2318 if (CFDictionaryGetTypeID() == CFGetTypeID(d))
2319 {
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)
2326 {
2327 Boolean numResult = CFNumberGetValue(varsNum, kCFNumberFloatType, &versionNumber);
2328 // STAssertTrue(numResult, @"Could not get the version number from the CFNumberRef");
2329 if (numResult)
2330 {
2331 float knownVersion = 1.0;
2332 // STAssertTrue(knownVersion == versionNumber, @"Versions do not Match!");
2333 }
2334 }
2335 }
2336 return internalizeResult;
2337 };
2338 SecTransformSetDataAction(ref, kSecTransformActionInternalizeExtraData,
2339 InternalizeExtraDataOverride);
2340
2341 return result;
2342 };
2343
2344 return Block_copy(instanceBlock);
2345 }
2346
2347 /* --------------------------------------------------------------------------
2348 method: testCustomExternalization
2349 description: Test the ability to write out custom external data
2350 -------------------------------------------------------------------------- */
2351 - (void)testCustomExternalization
2352 {
2353 NSString* ctName = @"com.apple.security.unit-test-customExternalization";
2354 NSError* error = nil;
2355
2356 CFStringRef aName = (CFStringRef)ctName;
2357 CFErrorRef* anError = (CFErrorRef *)&error;
2358
2359 Boolean registerResult = SecTransformRegister(aName, &CustomExternalization, anError);
2360 STAssertTrue(registerResult, @"Unable to register the custom externalization transform");
2361
2362 SecTransformRef externalTrans = SecTransformCreate((CFStringRef)ctName,
2363 (CFErrorRef *)&error);
2364
2365 STAssertNotNil((id)externalTrans, @"Could not create the custom externalization transform");
2366
2367 CFDictionaryRef externalData = SecTransformCopyExternalRepresentation(externalTrans);
2368 STAssertNotNil((NSDictionary *)externalData, @"Did not get a dictionary from SecTransformCopyExternalRepresentation");
2369
2370 CFRelease(externalTrans);
2371
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)
2377 {
2378 CFRelease(externalTrans);
2379 }
2380 }
2381
2382 static SecTransformInstanceBlock TestString(CFStringRef name,
2383 SecTransformRef newTransform,
2384 SecTransformImplementationRef ref)
2385 {
2386 SecTransformInstanceBlock instanceBlock =
2387 ^{
2388 CFErrorRef result = NULL;
2389 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
2390 ^(CFTypeRef value)
2391 {
2392 CFDataRef d = (CFDataRef)value;
2393 if (d) {
2394 return (CFTypeRef)CFStringCreateWithBytes(NULL, CFDataGetBytePtr(d), CFDataGetLength(d), kCFStringEncodingMacRoman, FALSE);
2395 } else {
2396 return (CFTypeRef)d;
2397 }
2398 });
2399 return result;
2400 };
2401
2402 return Block_copy(instanceBlock);
2403 }
2404
2405 -(void)testStringResults {
2406 CFStringRef name = CFSTR("com.apple.security.unit-test.string-converter");
2407 CFErrorRef error = NULL;
2408 SecTransformRegister(name, &TestString, &error);
2409
2410 SecTransformRef sr = SecTransformCreate(name, NULL);
2411
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];
2415
2416 SecTransformRef er = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
2417 SecTransformRef dr = SecDecodeTransformCreate(kSecBase32Encoding, NULL);
2418
2419 SecTransformSetAttribute(er, kSecTransformInputAttributeName, data, NULL);
2420
2421 SecGroupTransformRef group = SecTransformCreateGroupTransform();
2422 SecTransformConnectTransforms(er, kSecTransformOutputAttributeName, dr, kSecTransformInputAttributeName, group, NULL);
2423 SecTransformConnectTransforms(dr, kSecTransformOutputAttributeName, sr, kSecTransformInputAttributeName, group, NULL);
2424
2425
2426 CFStringRef result = (CFStringRef)SecTransformExecute(sr, NULL);
2427 STAssertEqualObjects(ns_msg, (NSString *)result, @"string results");
2428
2429 CFRelease(result);
2430 CFRelease(group);
2431 CFRelease(dr);
2432 CFRelease(er);
2433 CFRelease(sr);
2434 if (error)
2435 {
2436 CFRelease(error);
2437 }
2438 }
2439
2440 CFNumberRef MakeNumber1(long n)
2441 {
2442 return CFNumberCreate(NULL, kCFNumberLongType, &n);
2443 }
2444
2445
2446
2447 static SecTransformInstanceBlock TestRegisterCreate(CFStringRef name,
2448 SecTransformRef newTransform,
2449 SecTransformImplementationRef ref)
2450 {
2451
2452
2453 SecTransformInstanceBlock instanceBlock =
2454 ^{
2455 __block long count = 0;
2456
2457 __block CFNumberRef countNum = MakeNumber1(count);;
2458 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum);
2459 CFRelease(countNum);
2460 fprintf(stderr, "countNum = %p\n", countNum);
2461
2462 CFErrorRef result = NULL;
2463 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
2464 ^(CFTypeRef value)
2465 {
2466 CFDataRef d = (CFDataRef)value;
2467 if (d)
2468 {
2469 count += CFDataGetLength(d);
2470
2471 CFNumberRef countNum2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &count);
2472 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, countNum2);
2473 CFRelease(countNum2);
2474 fprintf(stderr, "countNum = %p\n", countNum);
2475
2476 } else
2477 {
2478 SecTransformCustomSetAttribute(ref, CFSTR("Count"), kSecTransformMetaAttributeValue, NULL);
2479 }
2480 return value;
2481 });
2482
2483
2484 return result;
2485 };
2486
2487 return Block_copy(instanceBlock);
2488 }
2489
2490 - (void)testRegisterCreate
2491 {
2492 CFStringRef name = CFSTR("com.apple.security.unit-test.novel-unique-at-least-unusual-name");
2493 long count = 0;
2494 CFNumberRef countNum = NULL;
2495 CFErrorRef error = NULL;
2496 Boolean ok = SecTransformRegister(name, &TestRegisterCreate, &error);
2497 STAssertTrue(ok, @"Successful register");
2498
2499 SecTransformRef tr = SecTransformCreate(name, NULL);
2500 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
2501 SecTransformSetAttribute(tr, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2502
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));
2505
2506 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
2507
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);
2514
2515 SecTransformSetAttribute(nt, CFSTR("DEBUG"), kCFBooleanTrue, NULL);
2516
2517 usleep(100);
2518 countNum = (CFNumberRef)SecTransformGetAttribute(tr, CFSTR("Count"));
2519 CFNumberGetValue(countNum, kCFNumberLongType, &count);
2520 CFRelease(countNum);
2521 STAssertTrue(count == 0, @"length unchanged before execute");
2522
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);
2528
2529 STAssertTrue(count == CFDataGetLength(data), @"Wrong data length");
2530
2531 CFRelease(tg);
2532 CFRelease(nt);
2533 CFRelease(tr);
2534 CFRelease(data);
2535 }
2536
2537
2538 static SecTransformInstanceBlock CountTransformTest(CFStringRef name,
2539 SecTransformRef newTransform,
2540 SecTransformImplementationRef ref)
2541 {
2542 SecTransformInstanceBlock instanceBlock =
2543 ^{
2544 CFErrorRef result = NULL;
2545 SecTransformSetAttributeAction(ref,kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2546 ^(SecTransformAttributeRef ah, CFTypeRef value)
2547 {
2548 if (value) {
2549 if (CFGetTypeID(value) != CFNumberGetTypeID()) {
2550 SecTransformCustomSetAttribute(ref, CFSTR("ABORT"), kSecTransformMetaAttributeValue, CFSTR("Bad type"));
2551 return value;
2552 }
2553 CFNumberRef nr = (CFNumberRef)value;
2554 int max, i;
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);
2559 CFRelease(nr);
2560 }
2561 } else {
2562 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
2563 }
2564
2565 return value;
2566 });
2567
2568 return result;
2569 };
2570
2571 return Block_copy(instanceBlock);
2572 }
2573
2574 SecTransformRef count_transform(int n) {
2575 CFStringRef name = CFSTR("com.apple.security.unit-test.count");
2576 static dispatch_once_t once;
2577
2578 dispatch_once(&once,
2579 ^{
2580 SecTransformRegister(name, &CountTransformTest, NULL);
2581 });
2582
2583 SecTransformRef ct = SecTransformCreate(name, NULL);
2584 CFNumberRef num = CFNumberCreate(NULL, kCFNumberIntType, &n);
2585 SecTransformSetAttribute(ct, CFSTR("INPUT"), num, NULL);
2586 CFRelease(num);
2587
2588 return ct;
2589 }
2590
2591
2592 static SecTransformInstanceBlock StallTest(CFStringRef name,
2593 SecTransformRef newTransform,
2594 SecTransformImplementationRef ref)
2595 {
2596 SecTransformInstanceBlock instanceBlock =
2597 ^{
2598 CFErrorRef result = NULL;
2599 __block bool go = false;
2600
2601 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("GO"),
2602 ^(SecTransformAttributeRef ah, CFTypeRef value)
2603 {
2604 go = true;
2605 return value;
2606 });
2607
2608 SecTransformAttributeRef in_ah = SecTransformCustomGetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeRef);
2609 SecTransformAttributeRef out_ah = SecTransformCustomGetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRef);
2610
2611 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL,
2612 ^(SecTransformAttributeRef ah, CFTypeRef value)
2613 {
2614 if (!go) {
2615 SecTransformPushbackAttribute(ref, ah, value);
2616 } else {
2617 if (ah == in_ah) {
2618 SecTransformCustomSetAttribute(ref, out_ah, kSecTransformMetaAttributeValue, value);
2619 }
2620 }
2621 return value;
2622 });
2623
2624 return result;
2625 };
2626
2627 return Block_copy(instanceBlock);
2628 }
2629
2630 -(void)testStall {
2631 CFStringRef name = CFSTR("com.apple.security.unit-test.stall");
2632
2633 (void)SecTransformRegister(name, &StallTest, NULL);
2634
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);
2639
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);
2645
2646 SecTransformSetAttribute(delay, CFSTR("INPUT"), (CFNumberRef)[NSNumber numberWithInt:42], NULL);
2647
2648 CFErrorRef err = NULL;
2649 CFTypeRef r = SecTransformExecute(group, &err);
2650
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");
2655
2656 CFRelease(delay);
2657 CFRelease(group);
2658 CFRelease(seven);
2659 CFRelease(stall);
2660 }
2661
2662 -(void)testInappropriateExecution
2663 {
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.
2668
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);
2674
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();
2680
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);
2683
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)
2686 {
2687 dispatch_group_enter(outstanding_executions);
2688
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");
2693 CFRelease(err);
2694
2695 dispatch_group_leave(outstanding_executions);
2696
2697 if (isFinal)
2698 {
2699 // Give any pending executions time to get to the group_enter
2700 usleep(100);
2701 dispatch_group_wait(outstanding_executions, DISPATCH_TIME_FOREVER);
2702 dispatch_release(outstanding_executions);
2703 dispatch_group_leave(wait_for_async_to_complete);
2704 }
2705 });
2706
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.
2710
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);
2715
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");
2720
2721 no_result = SecTransformExecute(no_work_group, &err);
2722
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);
2725 CFRelease(err);
2726
2727 // Now we wait for that first batch of tests to finish, we don't want to call STFail after self goes away.
2728
2729 dispatch_group_wait(wait_for_async_to_complete, DISPATCH_TIME_FOREVER);
2730 dispatch_release(wait_for_async_to_complete);
2731
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);
2737 }
2738
2739 static SecTransformInstanceBlock ConnectionReqTest(CFStringRef name,
2740 SecTransformRef newTransform,
2741 SecTransformImplementationRef ref)
2742 {
2743 SecTransformInstanceBlock instanceBlock =
2744 ^{
2745 CFErrorRef result = NULL;
2746 SecTransformAttributeRef xah =
2747 (SecTransformAttributeRef)SecTranformCustomGetAttribute(ref, CFSTR("XYZZY"), kSecTransformMetaAttributeRef);
2748
2749 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanTrue);
2750 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeRequiresOutboundConnection, kCFBooleanFalse);
2751 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2752 ^(SecTransformAttributeRef ah, CFTypeRef value)
2753 {
2754 SecTransformCustomSetAttribute(ref, xah, kSecTransformMetaAttributeValue, value);
2755 return value;
2756 });
2757
2758 return result;
2759 };
2760
2761 return Block_copy(instanceBlock);
2762 }
2763
2764
2765 -(void)testConnectionReq {
2766
2767 CFStringRef req_xyzzy_name = CFSTR("com.apple.security.unit-test.req_xyzzy");
2768
2769 (void)SecTransformRegister(req_xyzzy_name, &ConnectionReqTest, NULL);
2770
2771 SecTransformRef tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL);
2772
2773 CFTypeRef in_value = (CFTypeRef)@"Fnord";
2774 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL);
2775
2776 CFErrorRef err = NULL;
2777 CFTypeRef r = SecTransformExecute(tr_req_xyzzy, &err);
2778
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);
2783
2784 CFRelease(err);
2785 CFRelease(tr_req_xyzzy);
2786 if (r) CFRelease(r);
2787
2788 /*
2789
2790 Note For Josh:
2791
2792 To make this work we need Josh's fix for FindLastTransform!
2793
2794 CFRelease(tr_req_xyzzy);
2795 tr_req_xyzzy = SecTransformCreate(req_xyzzy_name, NULL);
2796 SecTransformSetAttribute(tr_req_xyzzy, CFSTR("INPUT"), in_value, NULL);
2797
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");
2806
2807 */
2808 }
2809
2810 static SecTransformInstanceBlock DeferredTest(CFStringRef name,
2811 SecTransformRef newTransform,
2812 SecTransformImplementationRef ref)
2813 {
2814 SecTransformInstanceBlock instanceBlock =
2815 ^{
2816 CFErrorRef result = NULL;
2817 SecTransformCustomSetAttribute(ref, CFSTR("LATE"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
2818 SecTransformCustomSetAttribute(ref, CFSTR("INPUT"), kSecTransformMetaAttributeDeferred, kCFBooleanFalse);
2819
2820 __block CFTypeRef in_v = NULL, late_v = NULL;
2821
2822 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
2823 ^(SecTransformAttributeRef ah, CFTypeRef value)
2824 {
2825 if (NULL != late_v) {
2826 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue,
2827 CreateGenericErrorRef(CFSTR("FAIL"), 1, "LATE (%@) should process after INPUT (%@)", late_v, value));
2828 }
2829 in_v = value;
2830 return value;
2831 });
2832
2833 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("LATE"),
2834 ^(SecTransformAttributeRef ah, CFTypeRef value)
2835 {
2836 if (NULL == in_v) {
2837 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue,
2838 CreateGenericErrorRef(CFSTR("FAIL"), 1, "INPUT (%@) should process before LATE (%@)", in_v, value));
2839 }
2840
2841 late_v = value;
2842 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, NULL);
2843 return value;
2844 });
2845
2846 return result;
2847 };
2848
2849 return Block_copy(instanceBlock);
2850 }
2851
2852
2853 -(void)testDeferred {
2854 CFStringRef deferred_name = CFSTR("com.apple.security.unit-test.deferred");
2855
2856 (void)SecTransformRegister(deferred_name, &DeferredTest, NULL);
2857
2858 SecTransformRef dt = SecTransformCreate(deferred_name, NULL);
2859
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);
2866
2867 if (err) CFRelease(err);
2868 // CFRelease(dt);
2869 }
2870
2871 static SecTransformInstanceBlock SaveRestoreTest(CFStringRef name,
2872 SecTransformRef newTransform,
2873 SecTransformImplementationRef ref)
2874 {
2875 SecTransformInstanceBlock instanceBlock =
2876 ^{
2877 CFErrorRef result = NULL;
2878 SecTransformCustomSetAttribute(ref, CFSTR("Needed"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
2879 SecTransformCustomSetAttribute(ref, CFSTR("NoSaves"), kSecTransformMetaAttributeExternalize, kCFBooleanFalse);
2880
2881 return result;
2882 };
2883
2884 return Block_copy(instanceBlock);
2885 }
2886
2887 -(void)testSaveRestore
2888 {
2889
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;
2893
2894 CFStringRef name = CFSTR("com.apple.security.unit-test.SaveRestoreTest");
2895
2896 (void)SecTransformRegister(name, &SaveRestoreTest, NULL);
2897
2898 SecTransformRef tr1 = SecTransformCreate(name, NULL);
2899
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);
2903
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");
2912
2913 CFDataRef d = (CFDataRef)SecTransformExecute((NSObject *)tr2, &err);
2914
2915 STAssertNotNil((NSData * )d, @"execute result (err=%@)", err);
2916
2917 if (err) {
2918 CFRelease(err);
2919 }
2920
2921 CFRelease(tr1);
2922 CFRelease(tr2);
2923 CFRelease(xr);
2924
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);
2930
2931
2932
2933 //tr2 = SecTransformCreateFromExternalRepresentation(xr, NULL);
2934 SecTransformRef tga = SecTransformCreateGroupTransform();
2935 SecTransformSetAttribute(tr1, kSecTransformInputAttributeName, data, NULL);
2936
2937 // XXX did not swap
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);
2946
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);
2951
2952 CFStringRef new_name2 = CFSTR("SaveRestoreTestThingie#2");
2953 CFStringRef fetched_name;
2954 int attempts;
2955
2956 for(attempts = 0; attempts < 20; ++attempts)
2957 {
2958 SecTransformSetAttribute(tr2, CFSTR("NAME"), new_name2, &err);
2959 fetched_name = (CFStringRef)SecTransformGetAttribute(tr2, CFSTR("NAME"));
2960
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))
2964 {
2965 break;
2966 }
2967 if (attempts > 10)
2968 {
2969 usleep(1000);
2970 }
2971 }
2972
2973 xr = SecTransformCopyExternalRepresentation(tr1);
2974 STAssertNotNil((NSDictionary *)xr, @"external rep for 2, take 2");
2975 NSLog(@"xr=%@", xr);
2976
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);
2980
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");
2985
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");
2990
2991 STAssertEqualObjects((id)has1, (id)has1b, @"has1 == has1b");
2992 STAssertEqualObjects((id)has2, (id)has2b, @"has2 == has2b");
2993
2994 }
2995
2996 -(void)testRequiredAttributes
2997 {
2998 CFStringRef name = CFSTR("com.apple.security.unit-test.requiresStuffThings");
2999 CFErrorRef error;
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;
3003
3004 __block state_t state = S_INITED;
3005 dispatch_group_t leave_on_finalize = dispatch_group_create();
3006
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.
3010 if (value)
3011 {
3012 STAssertTrue(state == S_STARTED, @"Init'ed for data (state=%d)", state);
3013 state = S_RUN;
3014 } else {
3015 STAssertTrue(state == S_RUN, @"In run state at EOS (state=%d)", state);
3016 state = S_EOS;
3017 }
3018 params->send(kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
3019 return value;
3020 });
3021
3022 params->send(CFSTR("Stuff"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
3023 params->send(CFSTR("Things"), kSecTransformMetaAttributeRequired, kCFBooleanTrue);
3024
3025 params->overrideTransform(kSecTransformActionStartingExecution, ^{
3026 STAssertTrue(state == S_INITED, @"Inited (state=%d)");
3027 state = S_STARTED;
3028 return (CFTypeRef)NULL;
3029 });
3030
3031 params->overrideTransform(kSecTransformActionFinalize, ^{
3032 state = S_GONE;
3033 dispatch_group_leave(leave_on_finalize);
3034 return (CFTypeRef)NULL;
3035 });
3036 };
3037
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");
3041
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);
3045 usleep(100);
3046 STAssertTrue(state == S_INITED, @"not run yet");
3047 CFDataRef rdata = (CFDataRef)SecTransformExecute((NSObject *)tr, &error);
3048
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);
3054
3055 if (error) {
3056 CFRelease(error);
3057 }
3058 CFRelease(tr);
3059
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);
3062
3063 dispatch_group_enter(leave_on_finalize);
3064 state = S_INITED;
3065 tr = custom_transform(name, required_attributes_create_block);
3066 STAssertNotNil((NSObject *)tr, @"newly created custom transform");
3067
3068 error = NULL;
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);
3073
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");
3078
3079 CFRelease(tr);
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);
3084 });
3085 }
3086
3087 static SecTransformInstanceBlock AttributeNotificationTest(CFStringRef name,
3088 SecTransformRef newTransform,
3089 SecTransformImplementationRef ref)
3090 {
3091 SecTransformInstanceBlock instanceBlock =
3092 ^{
3093 CFErrorRef result = NULL;
3094
3095
3096 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, NULL,
3097 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3098 {
3099 SecTransformCustomSetAttribute(ref, CFSTR("Generic"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3100 return value;
3101 });
3102
3103 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("Specific"),
3104 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3105 {
3106 SecTransformCustomSetAttribute(ref, CFSTR("Specific"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3107 return value;
3108
3109 });
3110
3111 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("AlsoSpecific"),
3112 ^(SecTransformStringOrAttributeRef ah, CFTypeRef value)
3113 {
3114 SecTransformCustomSetAttribute(ref, CFSTR("AlsoSpecific"), kSecTransformMetaAttributeValue, kCFBooleanTrue);
3115
3116 return value;
3117 });
3118
3119 return result;
3120 };
3121
3122 return Block_copy(instanceBlock);
3123 }
3124
3125 -(void)testAttributeNotifications
3126 {
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;
3131
3132 Boolean ok = SecTransformRegister((CFStringRef)name, &AttributeNotificationTest, NULL);
3133
3134 STAssertTrue(ok, @"Successful register");
3135
3136 SecTransformRef tr = SecTransformCreate((CFStringRef)name, NULL);
3137
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);
3142
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")));
3146
3147
3148 STAssertTrue(generic_called, @"generic called");
3149 STAssertTrue(specific_called, @"specific called");
3150 STAssertTrue(also_specific_called, @"also specific called");
3151
3152 CFRelease(tr);
3153 }
3154
3155 -(void)testEncryptAndDecryptTransforms
3156 {
3157 NSAutoreleasePool *pool = [NSAutoreleasePool new];
3158
3159 // generate a symmetrical key for testing
3160 OSStatus err = errSecSuccess;
3161
3162 NSString* algNames[] =
3163 {
3164 @"AES 128",
3165 @"AES 192",
3166 @"AES 256",
3167 @"DES",
3168 @"3DES",
3169 @"CAST",
3170 @"RC4"
3171 };
3172
3173 CSSM_ALGORITHMS symmetricalAlgos[] =
3174 {
3175 CSSM_ALGID_AES,
3176 CSSM_ALGID_AES,
3177 CSSM_ALGID_AES,
3178 CSSM_ALGID_DES,
3179 CSSM_ALGID_3DES_3KEY_EDE,
3180 CSSM_ALGID_CAST,
3181 CSSM_ALGID_RC4
3182 };
3183
3184 uint32 keySizes[] =
3185 {
3186 128,
3187 192,
3188 256,
3189 64,
3190 192,
3191 40,
3192 8
3193 };
3194
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);
3199
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.";
3214
3215 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
3216 int numItems = (sizeof(symmetricalAlgos) / sizeof(CSSM_ALGORITHMS));
3217 int iCnt = 0;
3218
3219 for (iCnt = 0; iCnt < numItems; iCnt++)
3220 {
3221 SecKeyRef testKey = NULL;
3222 CSSM_ALGORITHMS algoToUse = symmetricalAlgos[iCnt];
3223 uint32 keySizeInBits = keySizes[iCnt];
3224
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)
3228 {
3229 continue;
3230 }
3231 __block CFErrorRef error = NULL;
3232
3233 SecTransformRef encryptSymRef = NULL;
3234 encryptSymRef = SecEncryptTransformCreate(testKey, &error);
3235 if (NULL != error)
3236 {
3237 CFRelease(testKey);
3238 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key %@", algNames[iCnt]]);
3239 continue;
3240 }
3241
3242 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error);
3243 if (NULL != error)
3244 {
3245 CFRelease(testKey);
3246 CFRelease(encryptSymRef);
3247 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key %@", algNames[iCnt]]);
3248 continue;
3249 }
3250
3251 // connect the output of the encryption to the input of the decryption transform
3252
3253 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3254 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName,
3255 decryptSymRef, kSecTransformInputAttributeName,
3256 group, &error);
3257 if (NULL != error)
3258 {
3259 CFRelease(testKey);
3260 CFRelease(encryptSymRef);
3261 CFRelease(decryptSymRef);
3262 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key %@", algNames[iCnt]]);
3263 continue;
3264 }
3265
3266
3267 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3268 [dataStream open];
3269
3270 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3271 if (NULL != error)
3272 {
3273 CFRelease(testKey);
3274 CFRelease(encryptSymRef);
3275 CFRelease(decryptSymRef);
3276 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to set the input for key %@", algNames[iCnt]]);
3277 continue;
3278 }
3279
3280 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3281 CFRelease(group);
3282 CFRelease(encryptSymRef);
3283 CFRelease(decryptSymRef);
3284
3285 if (NULL != error)
3286 {
3287 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for algo %@", algNames[iCnt]]);
3288 continue;
3289 CFRelease(error);
3290 }
3291
3292 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3293 {
3294 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for %@", algNames[iCnt]]);
3295 continue;
3296 }
3297
3298 NSData* resultData = nil;
3299 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3300 {
3301 resultData = (NSData*)transformResult;
3302 [resultData autorelease];
3303 }
3304
3305 CFRelease(testKey);
3306
3307 STAssertTrue([testData isEqualToData:resultData], @"The output of the decrypt transform does NOT match the original input!");
3308 }
3309
3310
3311 SecKeyRef publicKey = NULL;
3312 SecKeyRef privateKey = NULL;
3313
3314 keyAttrFlags = CSSM_KEYATTR_RETURN_REF;
3315
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;
3318
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;
3321
3322
3323 err = SecKeyCreatePair(NULL, CSSM_ALGID_RSA, 2048, ((CSSM_CC_HANDLE)0),
3324 pubKeyUse, publicKeyAttributes,
3325 privKeyUse, privateKeyAttributes,
3326 NULL, &publicKey, &privateKey);
3327
3328 STAssertTrue(errSecSuccess == err, @"Unable to create a key pair");
3329 if (errSecSuccess != err)
3330 {
3331 cssmPerror(NULL, err);
3332 return;
3333 }
3334
3335 CFErrorRef error = NULL;
3336 SecTransformRef encryptSymRef = SecEncryptTransformCreate(publicKey , &error);
3337 if (NULL != error)
3338 {
3339 CFRelease(publicKey);
3340 CFRelease(privateKey);
3341 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the encrypt transform for key RSA"]);
3342 return;
3343 }
3344
3345 SecTransformRef decryptSymRef = SecDecryptTransformCreate(privateKey, &error);
3346 if (NULL != error)
3347 {
3348 CFRelease(publicKey);
3349 CFRelease(privateKey);
3350 CFRelease(encryptSymRef);
3351 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to create the decrypt transform for key RSA"]);
3352 return;
3353 }
3354
3355 // connect the output of the encryption to the input of the decryption transform
3356
3357 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3358 (void)SecTransformConnectTransforms( encryptSymRef, kSecTransformOutputAttributeName,
3359 decryptSymRef, kSecTransformInputAttributeName,
3360 group, &error);
3361 if (NULL != error)
3362 {
3363 CFRelease(publicKey);
3364 CFRelease(privateKey);
3365 CFRelease(encryptSymRef);
3366 CFRelease(decryptSymRef);
3367 STAssertTrue(NO, [NSString stringWithFormat:@"Unable to connect transforms for key RSA"]);
3368 return;
3369 }
3370
3371 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3372 [dataStream open];
3373
3374 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3375 if (NULL != error)
3376 {
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"]);
3382 return;
3383 }
3384 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3385 if (NULL != error)
3386 {
3387 STAssertTrue(NO, [NSString stringWithFormat:@"returned an error for RSA"]);
3388 CFRelease(error);
3389 return;
3390 }
3391
3392 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3393 {
3394 STAssertTrue(NO, [NSString stringWithFormat:@"transformResult was NULL or empty for RSA"]);
3395 return;
3396 }
3397
3398 NSData* resultData = nil;
3399 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3400 {
3401 resultData = (NSData*)transformResult;
3402 [resultData autorelease];
3403 }
3404
3405 CFRelease(publicKey);
3406 CFRelease(privateKey);
3407 CFRelease(encryptSymRef);
3408 CFRelease(decryptSymRef);
3409
3410 STAssertTrue([testData isEqualToData:resultData], @"(RSA)The output of the decrypt transform does NOT match the original input!");
3411
3412 [pool drain];
3413 }
3414
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);
3424
3425 NSString* dataStr = @"Reduce, reuse, recycle. No crashes please.";
3426 NSData* testData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
3427
3428 SecKeyRef testKey = NULL;
3429 {
3430 OSStatus err;
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);
3433 }
3434
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;
3440
3441 SecTransformRef encryptSymRef = NULL;
3442 encryptSymRef = SecEncryptTransformCreate(testKey, &error);
3443 if (NULL != error)
3444 {
3445 STFail(@"Unable to create the encrypt transform iteration#%d error=%@", i, error);
3446 return;
3447 }
3448 if (NULL == encryptSymRef) {
3449 STFail(@"Unable to create the encrypt transform iteration#%d, error=NULL", i);
3450 return;
3451 }
3452
3453 SecTransformRef decryptSymRef = SecDecryptTransformCreate(testKey, &error);
3454 if (NULL != error)
3455 {
3456 CFRelease(encryptSymRef);
3457 STFail(@"Unable to create the decrypt transform iteration#%d error=%@", i, error);
3458 return;
3459 }
3460 if (NULL == decryptSymRef) {
3461 CFRelease(encryptSymRef);
3462 STFail(@"Unable to create the decrypt transform iteration#%d, error=NULL", i);
3463 return;
3464 }
3465
3466 // connect the output of the encryption to the input of the decryption transform
3467
3468 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3469 (void)SecTransformConnectTransforms(encryptSymRef, kSecTransformOutputAttributeName,
3470 decryptSymRef, kSecTransformInputAttributeName,
3471 group, &error);
3472 if (NULL != error)
3473 {
3474 CFRelease(encryptSymRef);
3475 CFRelease(decryptSymRef);
3476 STFail(@"Unable to connect transforms on iteration %d error=%@", i, error);
3477 return;
3478 }
3479
3480
3481 NSInputStream* dataStream = [NSInputStream inputStreamWithData:testData];
3482 [dataStream open];
3483
3484 SecTransformSetAttribute(encryptSymRef, kSecTransformInputAttributeName, (CFTypeRef)dataStream, &error);
3485 if (NULL != error)
3486 {
3487 CFRelease(encryptSymRef);
3488 CFRelease(decryptSymRef);
3489 STFail(@"Unable to set the input on iteration %d error=%@", i, error);
3490 return;
3491 }
3492
3493 CFTypeRef transformResult = SecTransformExecute(encryptSymRef, &error);
3494 CFRelease(group);
3495
3496 if (NULL != error)
3497 {
3498 STFail(@"returned an error on iteration %d error=%@", i, error);
3499 CFRelease(error);
3500 return;
3501 }
3502
3503 if (NULL == transformResult || 0 == [(NSData*)transformResult length])
3504 {
3505 STFail(@"transformResult was NULL or empty for iteration %d", i);
3506 return;
3507 }
3508
3509 NSData* resultData = nil;
3510 if (CFGetTypeID(transformResult) == CFDataGetTypeID())
3511 {
3512 resultData = (NSData*)transformResult;
3513 [resultData autorelease];
3514 }
3515
3516 CFRelease(encryptSymRef);
3517 CFRelease(decryptSymRef);
3518
3519 STAssertEqualObjects(testData, resultData, @"The output of the decrypt transform does NOT match the original input iteration %d", i);
3520 });
3521
3522 CFRelease(testKey);
3523 }
3524
3525 static SecTransformInstanceBlock RoundTripCheck(CFStringRef name,
3526 SecTransformRef newTransform,
3527 SecTransformImplementationRef ref)
3528 {
3529 SecTransformInstanceBlock instanceBlock =
3530 ^{
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;
3536
3537 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeDeferred, kCFBooleanTrue);
3538 SecTransformCustomSetAttribute(ref, CFSTR("INPUT2"), kSecTransformMetaAttributeStream, kCFBooleanTrue);
3539
3540 dispatch_block_t not_equal =
3541 ^{
3542 // not equal
3543 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, kCFBooleanFalse);
3544 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL);
3545 drain = true;
3546 };
3547
3548 SecTransformAttributeActionBlock action =
3549 ^(SecTransformAttributeRef ah, CFTypeRef value)
3550 {
3551 if (drain)
3552 {
3553 return (CFTypeRef)NULL;
3554 }
3555
3556 if (ahead == ah)
3557 {
3558 SecTransformPushbackAttribute(ref, ah, value);
3559 }
3560 else if (value)
3561 {
3562 CFDataRef d = (CFDataRef)value;
3563 if (remainder)
3564 {
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;
3570
3571 if (remainder_length == d_length)
3572 {
3573 compare_length = d_length;
3574 }
3575 else if (remainder_length < d_length)
3576 {
3577 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(d) + remainder_length, d_length - remainder_length);
3578 compare_length = remainder_length;
3579 new_ahead = ah;
3580 } else
3581 {
3582 new_remainder = CFDataCreate(NULL, CFDataGetBytePtr(remainder) + d_length, remainder_length - d_length);
3583 compare_length = d_length;
3584 new_ahead = ahead;
3585 }
3586
3587 if (bcmp(CFDataGetBytePtr(d), CFDataGetBytePtr(remainder), compare_length)) {
3588 not_equal();
3589 } else
3590 {
3591 // same, keep going
3592 CFRelease(remainder);
3593 remainder = new_remainder;
3594 ahead = new_ahead;
3595 }
3596 }
3597 else
3598 {
3599 if (!eof_count)
3600 {
3601 ahead = ah;
3602 remainder = CFDataCreateCopy(NULL, d);
3603 }
3604 else
3605 {
3606 if (CFDataGetLength(d))
3607 {
3608 not_equal();
3609 }
3610 }
3611 }
3612 }
3613 else
3614 { // EOF case
3615 ahead = NULL;
3616 if (++eof_count == 2)
3617 {
3618 if (remainder)
3619 {
3620 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3621 kSecTransformMetaAttributeValue,
3622 CFDataGetLength(remainder) ? kCFBooleanFalse : kCFBooleanTrue);
3623
3624 CFRelease(remainder);
3625 }
3626 else
3627 {
3628 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3629 kSecTransformMetaAttributeValue, kCFBooleanTrue);
3630 }
3631
3632 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
3633 kSecTransformMetaAttributeValue, NULL);
3634 }
3635 }
3636
3637 return (CFTypeRef)NULL;
3638 };
3639
3640 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT2"), action);
3641 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, action);
3642
3643 return result;
3644 };
3645
3646 return Block_copy(instanceBlock);
3647 }
3648
3649 BOOL RoundTrip(CFStringRef fname, SecTransformRef in, SecTransformRef out, BOOL share)
3650 {
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
3654
3655 dispatch_once(&once,
3656 ^{
3657 SecTransformRegister(name, &RoundTripCheck, NULL);
3658 });
3659
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
3667 [is open];
3668
3669 NSInputStream *is2 = nil;
3670
3671 if (share)
3672 {
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);
3677 CFRelease(tee);
3678 } else {
3679 is2 = [NSInputStream inputStreamWithFileAtPath:(NSString *)fname];
3680 [is2 open];
3681 SecTransformSetAttribute(in, kSecTransformInputAttributeName, (CFTypeRef)is, &err);
3682 SecTransformSetAttribute(cmp, CFSTR("INPUT2"), (CFTypeRef)is2, &err);
3683 }
3684
3685 assert(err == NULL);
3686 CFTypeRef r = SecTransformExecute(group, &err);
3687
3688 if (err)
3689 {
3690 CFRelease(err);
3691 }
3692
3693 CFRelease(group);
3694 CFRelease(cmp);
3695
3696 if (is2)
3697 {
3698 [is2 close];
3699 }
3700
3701 if (is)
3702 {
3703 [is close];
3704 }
3705
3706 if (r)
3707 {
3708 return r == kCFBooleanTrue;
3709 }
3710 else
3711 {
3712 CFfprintf(stderr, "round trip error: %@", err);
3713 return NO;
3714 }
3715 }
3716
3717 static SecTransformInstanceBlock LineLengthCheck(CFStringRef name, SecTransformRef newTransform, SecTransformImplementationRef ref)
3718 {
3719 SecTransformInstanceBlock instanceBlock = ^{
3720 CFErrorRef result = NULL;
3721 __block int bytesPastLastEOL = 0;
3722 __block int max = 0;
3723
3724 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("MAX"), ^(SecTransformAttributeRef ah, CFTypeRef value) {
3725 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &max);
3726 return value;
3727 });
3728
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);
3734
3735 for(int i = 0; i < len; i++) {
3736 if (bytes[i] == '\n') {
3737 bytesPastLastEOL = 0;
3738 } else {
3739 bytesPastLastEOL++;
3740 if (bytesPastLastEOL > max) {
3741 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "MAX line length of %d exceeded", max));
3742 break;
3743 }
3744 }
3745 }
3746 }
3747 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
3748 return value;
3749 });
3750
3751 return result;
3752 };
3753
3754 return Block_copy(instanceBlock);
3755 }
3756
3757 -(void)testLargeChunkEncode
3758 {
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};
3763
3764 dispatch_group_t dg = dispatch_group_create();
3765
3766 CFStringRef lengthCheckName = CFSTR("com.apple.security.unit-test.lineLengthCheck");
3767 SecTransformRegister(lengthCheckName, LineLengthCheck, (CFErrorRef *)&err);
3768 STAssertNil(err, @"Expected to register %@", lengthCheckName);
3769
3770 for(int i = 0; types[i]; i++) {
3771 int max_j = 80;
3772 CFStringRef etype = types[i];
3773
3774 void (^trial)(NSString *testName, id lineLength, int maxLineLength) = ^(NSString *testName, id lineLength, int maxLineLength) {
3775 SecGroupTransformRef group = SecTransformCreateGroupTransform();
3776
3777 SecTransformRef et = SecEncodeTransformCreate(etype, (CFErrorRef *)&err);
3778 SecTransformRef dt = SecDecodeTransformCreate(etype, (CFErrorRef *)&err);
3779
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);
3783
3784 SecTransformConnectTransforms(et, kSecTransformOutputAttributeName, lineLengthChecker, kSecTransformInputAttributeName, group, (CFErrorRef *)&err);
3785 SecTransformConnectTransforms(lineLengthChecker, kSecTransformOutputAttributeName, dt, kSecTransformInputAttributeName, group, (CFErrorRef *)&err);
3786
3787 SecTransformSetAttribute(et, kSecTransformInputAttributeName, (CFDataRef)d, (CFErrorRef *)&err);
3788 SecTransformSetAttribute(et, kSecEncodeLineLengthAttribute, lineLength, (CFErrorRef *)&err);
3789 SecTransformSetAttribute(et, CFSTR("NAME"), (CFStringRef)testName, (CFErrorRef *)&err);
3790
3791 dispatch_group_async(dg, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
3792 CFDataRef result = (CFDataRef)SecTransformExecute(group, (CFErrorRef *)&err);
3793
3794 STAssertNil(err, @"execute for %@ got %@", testName, err);
3795 STAssertNotNil((id)result, @"No result from execute of %@", testName);
3796
3797 if (result) {
3798 STAssertEqualObjects(d, (id)result, @"test %@ failed", testName);
3799 }
3800 });
3801 };
3802
3803 for(int j = max_j; j > 70; --j) {
3804 if (etype == kSecZLibEncoding && j != max_j) {
3805 break;
3806 }
3807 trial([NSString stringWithFormat:@"%@-%d", etype, j], [NSNumber numberWithInt:j], j);
3808 }
3809
3810 if (etype != kSecZLibEncoding) {
3811 trial([NSString stringWithFormat:@"%@-LL64", etype], (id)kSecLineLength64, 64);
3812 trial([NSString stringWithFormat:@"%@-LL76", etype], (id)kSecLineLength76, 76);
3813 }
3814 }
3815
3816 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
3817 }
3818
3819 -(void)testZLib {
3820 SecTransformRef et = SecEncodeTransformCreate(kSecZLibEncoding, NULL);
3821 SecTransformRef dt = SecDecodeTransformCreate(kSecZLibEncoding, NULL);
3822
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");
3825
3826 CFRelease(et);
3827 CFRelease(dt);
3828
3829 /*
3830 If we want this we need a 'new' custom transform that will get receive the ratio data and be able to
3831 query that data.
3832
3833 CFNumberRef r1 = (CFNumberRef)SecTransformGetAttribute(et, kSecCompressionRatio);
3834 CFNumberRef r2 = (CFNumberRef)SecTransformGetAttribute(dt, kSecCompressionRatio);
3835
3836 STAssertNotNil((NSNumber *)r1, @"encode ratio");
3837 STAssertNotNil((NSNumber *)r2, @"decode ratio");
3838 STAssertEqualObjects((NSNumber *)r1, (NSNumber *)r2, @"same ratios");
3839 */
3840 }
3841
3842 static SecTransformInstanceBlock CycleCheckTest(CFStringRef name,
3843 SecTransformRef newTransform,
3844 SecTransformImplementationRef ref)
3845 {
3846 SecTransformInstanceBlock instanceBlock =
3847 ^{
3848 CFErrorRef result = NULL;
3849 int zero = 0;
3850 __block CFNumberRef feedback = CFNumberCreate(NULL, kCFNumberIntType, &zero);
3851
3852 SecTransformCustomSetAttribute(ref, CFSTR("FEEDBACK"), kSecTransformMetaAttributeCanCycle, kCFBooleanTrue);
3853
3854 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("INPUT"),
3855 ^(SecTransformAttributeRef ah, CFTypeRef value)
3856 {
3857 if (value == NULL) {
3858 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, value);
3859 return value;
3860 }
3861 if (feedback == NULL) {
3862 SecTransformPushbackAttribute(ref, ah, value);
3863 return (CFTypeRef)NULL;
3864 }
3865
3866 int x, y;
3867 CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &x);
3868 CFNumberGetValue(feedback, kCFNumberIntType, &y);
3869 x ^= y;
3870 CFNumberRef res = CFNumberCreate(NULL, kCFNumberIntType, &x);
3871 SecTransformCustomSetAttribute(ref, CFSTR("OUTPUT"), kSecTransformMetaAttributeValue, res);
3872 CFRelease(res);
3873 CFRelease(feedback);
3874 feedback = NULL;
3875 return (CFTypeRef)NULL;
3876 });
3877
3878 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, CFSTR("FEEDBACK"),
3879 ^(SecTransformAttributeRef ah, CFTypeRef value)
3880 {
3881 if (value) {
3882 if (feedback) {
3883 SecTransformPushbackAttribute(ref, ah, value);
3884 } else {
3885 feedback = (CFNumberRef)CFRetain(value);
3886 }
3887 }
3888
3889 return (CFTypeRef)NULL;
3890 });
3891
3892 return result;
3893
3894 };
3895
3896 return Block_copy(instanceBlock);
3897 }
3898
3899 -(void)testCycleCheck {
3900
3901 SecTransformRef cat = SecNullTransformCreate();
3902 SecTransformRef group = SecTransformCreateGroupTransform();
3903 CFErrorRef err = NULL;
3904
3905 CFStringRef name = CFSTR("com.apple.examples.unit-test.loop-test");
3906
3907 SecTransformRegister(name, &CycleCheckTest, NULL);
3908
3909 SecTransformRef twenty = count_transform(20);
3910
3911 // this is getting an internal error, but it's being ignored.
3912 SecTransformRef xxor = SecTransformCreate(name, &err);
3913
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");
3920
3921 //SecTransformSetAttribute(xxor, CFSTR("DEBUG"), kCFBooleanTrue, &err);
3922
3923 CFTypeRef r = SecTransformExecute(group, &err);
3924 STAssertNil((id)err, @"execute err=%@", err);
3925 STAssertNotNil((id)r, @"no results from execute");
3926
3927 if (r) {
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);
3932 }
3933
3934 CFRelease(r);
3935 CFRelease(group);
3936 CFRelease(twenty);
3937 CFRelease(xxor);
3938 CFRelease(cat);
3939 }
3940
3941 -(void)testValidate {
3942 SecTransformRef group = SecTransformCreateGroupTransform();
3943 CFErrorRef err = NULL;
3944
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));
3948 };
3949
3950
3951 SecTransformRef makes_numbers = count_transform(20);
3952 SecTransformRef wants_data = custom_transform(data_or_null_name, data_or_null);
3953
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");
3962
3963 if (err) {
3964 CFRelease(err);
3965 }
3966 err = NULL;
3967 CFRelease(wants_data);
3968
3969 wants_data = custom_transform(data_or_null_name, data_or_null);
3970
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);
3975
3976 STAssertNil((id)err, @"unexpected set error: %@", err);
3977 r = SecTransformExecute(wants_data, &err);
3978 STAssertNotNil((id)r, @"Expected a result, got error: %@", err);
3979 if (r) {
3980 STAssertEqualObjects((id)the_data, (id)r, @"Invalid result");
3981 }
3982
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));
3986 };
3987
3988 CFRelease(group);
3989 CFRelease(makes_numbers);
3990 CFRelease(wants_data);
3991
3992 group = SecTransformCreateGroupTransform();
3993 makes_numbers = count_transform(20);
3994 SecTransformRef wants_numbers = custom_transform(numbers_only_name, numbers_only);
3995
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");
4005
4006 CFRelease(err);
4007 CFRelease(group);
4008 CFRelease(makes_numbers);
4009 CFRelease(wants_numbers);
4010 }
4011
4012 -(void)testCodeBase32 {
4013 struct base32_test_vector {
4014 const char *plain_text;
4015 const char *base32_rfc4648;
4016 const char *base32_fde;
4017 };
4018
4019 // RFC 4648 test vectors
4020 static base32_test_vector base32_test_vectors[] = {
4021 {"", "", ""},
4022 {"f", "MY======", "MY======"},
4023 {"fo", "MZXQ====", "MZXQ===="},
4024 {"foo", "MZXW6===", "MZXW6==="},
4025 {"foob", "MZXW6YQ=", "MZXW6YQ="},
4026 {"fooba", "MZXW6YTB", "MZXW6YTB"},
4027 {"foobar", "MZXW6YTBOI======", "MZXW6YTBO8======"}};
4028
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)
4031 {
4032 if (!transform) {
4033 STFail(@"No transform for %@", test_name);
4034 return;
4035 }
4036
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);
4046 if (output_data) {
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);
4052 }
4053 CFRelease(transform);
4054 };
4055
4056 for(int idx = 0; idx < sizeof(base32_test_vectors)/sizeof(*base32_test_vectors); idx++)
4057 {
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$@\"");
4060
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$@\"");
4063
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$@\"");
4066
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$@\"");
4069 }
4070
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");
4076
4077 CFRelease(bet);
4078 CFRelease(bdt);
4079
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");
4086
4087 CFRelease(FDE_encode_transform);
4088 CFRelease(FDE_decode_transform);
4089 }
4090
4091 -(void)testCodeBase64 {
4092 CFErrorRef error = NULL;
4093
4094 #if 0
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);
4099 #endif
4100
4101 SecTransformRef dt = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
4102 STAssertNotNil((id)dt, @"Got decoder");
4103
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);
4109
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");
4113
4114 SecTransformRef et = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4115 STAssertNotNil((id)et, @"Got encoder");
4116
4117 SecTransformSetAttribute(et, kSecTransformInputAttributeName, data1, NULL);
4118
4119 CFDataRef encoded_data = (CFDataRef)SecTransformExecute(et, NULL);
4120 STAssertNotNil((NSData *)encoded_data, @"Got an encode result");
4121
4122 STAssertEqualObjects((NSData *)encoded_data, (NSData *)data0, @"Proper encode results");
4123
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.
4125
4126 SecTransformRef dt2 = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
4127 SecTransformRef et2 = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
4128 int ll = 75;
4129 SecTransformSetAttribute(et2, kSecEncodeLineLengthAttribute, CFNumberCreate(NULL, kCFNumberIntType, &ll), NULL);
4130
4131 STAssertTrue(RoundTrip((CFStringRef)@"/usr/share/dict/words", et2, dt2, YES), @"Roundtrip base64 /usr/share/dict/words");
4132
4133 CFRelease(et2);
4134 CFRelease(dt2);
4135 }
4136
4137 static SecTransformInstanceBlock ErrorResultsTest(CFStringRef name,
4138 SecTransformRef newTransform,
4139 SecTransformImplementationRef ref)
4140 {
4141 SecTransformInstanceBlock instanceBlock =
4142 ^{
4143 CFErrorRef result = NULL;
4144 SecTransformSetDataAction(ref, kSecTransformActionProcessData,
4145 ^(CFTypeRef value)
4146 {
4147 if (value != NULL)
4148 {
4149 return (CFTypeRef)CFErrorCreate(NULL, CFSTR("expected error"), 42, NULL);
4150 }
4151 else
4152 {
4153 return SecTransformNoData();
4154 }
4155 });
4156
4157 return result;
4158 };
4159
4160 return Block_copy(instanceBlock);
4161 }
4162
4163
4164 -(void)testErrorResults {
4165 CFStringRef name = CFSTR("com.apple.security.unit-test.error-results");
4166 SecTransformRegister(name, &ErrorResultsTest, NULL);
4167
4168 SecTransformRef tr = SecTransformCreate(name, NULL);
4169 CFDataRef data = CFDataCreate(NULL, NULL, 0);
4170 SecTransformSetAttribute(tr, kSecTransformInputAttributeName, data, NULL);
4171
4172 CFErrorRef err = NULL;
4173 CFTypeRef no_result = SecTransformExecute(tr, &err);
4174
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");
4178 CFRelease(data);
4179 CFRelease(tr);
4180 CFRelease(err);
4181 }
4182
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).
4186
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;
4193
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);
4198 if (isFinal) {
4199 dispatch_group_leave(got_final);
4200 }
4201 });
4202
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)");
4206
4207 CFRelease(unassigned_input);
4208 dispatch_group_notify(got_final, q, ^{
4209 dispatch_release(got_final);
4210 dispatch_release(q);
4211 });
4212
4213 }
4214
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;
4226
4227 char *tmp_dir;
4228 asprintf(&tmp_dir, "%s/sign-verify-test-keychain-", getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
4229
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));
4232
4233 // when safe replace with a concurrent queue
4234 dispatch_queue_t key_q = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
4235
4236 dispatch_group_async(dg, key_q,
4237 ^{
4238 NSAutoreleasePool *pool = [NSAutoreleasePool new];
4239
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,
4245 nil];
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);
4248 [pool drain];
4249 });
4250
4251 dispatch_group_async(dg, key_q,
4252 ^{
4253 OSStatus gp_status;
4254 #if 0
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,
4260 nil];
4261 gp_status = SecKeyGeneratePair((CFDictionaryRef)key_opts, &ecdsa_pub_key, &ecdsa_priv_key);
4262 #else
4263 {
4264 SecKeychainRef tmp_keychain = NULL;
4265 gp_status = SecKeyCreatePair(tmp_keychain, CSSM_ALGID_ECDSA, 256, NULL,
4266 CSSM_KEYUSE_VERIFY,
4267 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT,
4268 CSSM_KEYUSE_SIGN,
4269 CSSM_KEYATTR_EXTRACTABLE|CSSM_KEYATTR_PERMANENT,
4270 NULL, &ecdsa_pub_key, &ecdsa_priv_key);
4271 }
4272 #endif
4273 if (gp_status)
4274 {
4275 STAssertTrue(gp_status == 0, @"ECDSA (gp_status=0x%x)", gp_status);
4276 }
4277 });
4278
4279 dispatch_group_async(dg, key_q,
4280 ^{
4281 OSStatus gp_status;
4282 #if 0
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);
4287 #else
4288 {
4289 const char *passwd = "this is not secret";
4290 SecKeychainRef tmp_keychain = NULL;
4291 char *kcfname;
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)
4295 mktemp(kcfname);
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);
4304 free(kcfname);
4305 }
4306 #endif
4307 STAssertTrue(gp_status == 0, @"DSA (gp_status=0x%x)", gp_status);
4308 });
4309
4310 struct sv_test {
4311 NSString *name;
4312 SecKeyRef pub_key, priv_key;
4313 CFDataRef msg_sign, msg_verify;
4314 CFTypeRef dalgo_sign, dalgo_verify;
4315 int dlen_sign, dlen_verify;
4316 BOOL pass;
4317 };
4318
4319 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
4320
4321 struct sv_test sv_tests[] =
4322 {
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},
4326
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},
4329
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},
4332
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},
4335
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},
4339
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},
4342
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},
4345
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},
4348
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},
4351
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},
4355
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},
4358
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},
4361
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},
4364
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},
4367
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},
4370
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},
4373
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
4377
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},
4380 };
4381
4382 free(tmp_dir);
4383
4384 int i;
4385 for(i = 0; i < sizeof(sv_tests)/sizeof(sv_test); i++)
4386 {
4387 CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest};
4388 //CFStringRef input_cases[] = {kSecInputIsPlainText, kSecInputIsDigest, kSecInputIsRaw};
4389 const int ilim = sizeof(input_cases)/sizeof(input_cases[0]);
4390 int ii = 0, ij = 0;
4391 for(; ii < ilim; ++ii)
4392 {
4393 for(ij = 0; ij < ilim; ++ij)
4394 {
4395 err = NULL;
4396 struct sv_test *tst = sv_tests + i;
4397 NSString *tname = [NSString stringWithFormat:@"%@ %@ %@", tst->name, input_cases[ii], input_cases[ij]];
4398
4399 CFStringRef sign_input_is = input_cases[ii];
4400 CFStringRef verify_input_is = input_cases[ij];
4401
4402 if (sign_input_is != kSecInputIsPlainText && tst->dalgo_sign == NULL) {
4403 continue;
4404 }
4405 if (verify_input_is != kSecInputIsPlainText && tst->dalgo_verify == NULL) {
4406 continue;
4407 }
4408
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);
4412 continue;
4413 }
4414
4415 STAssertNotNil((id)tst->pub_key, @"Have pub_key for %@", tname);
4416 STAssertNotNil((id)tst->priv_key, @"Have priv_key for %@", tname);
4417
4418 if (tst->pub_key == nil || tst->priv_key == nil) {
4419 continue;
4420 }
4421
4422 SecTransformRef sign = SecSignTransformCreate(tst->priv_key, &err);
4423 STAssertNil((NSError *)err, @"creating sign for %@", tname);
4424 STAssertNotNil((id)sign, @"Creating sign for %@", tname);
4425
4426 if (sign == NULL) {
4427 continue;
4428 }
4429
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);
4433
4434 if (verify == NULL) {
4435 continue;
4436 }
4437
4438 SecTransformRef sign_digest = NULL;
4439 SecTransformRef verify_digest = NULL;
4440 SecTransformRef sign2 = NULL;
4441
4442 if (tst->dalgo_sign)
4443 {
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);
4448
4449 if (sign_input_is == kSecInputIsDigest)
4450 {
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);
4454
4455 SecTransformSetAttribute(sign, kSecInputIsAttributeName, sign_input_is, &err);
4456 STAssertNil((NSError *)err, @"Setting sign's InputIs (for %@) - err=%@", tname, err);
4457 }
4458 }
4459
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);
4465
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);
4470
4471 SecTransformSetAttribute(verify, kSecInputIsAttributeName, verify_input_is, &err);
4472 STAssertNil((NSError *)err, @"Setting verify's InputIs (for %@) - err=%@", tname, err);
4473 }
4474 }
4475
4476 SecGroupTransformRef group = SecTransformCreateGroupTransform();
4477 SecTransformSetAttribute(sign_digest ? sign_digest : sign, kSecTransformInputAttributeName, tst->msg_sign, (CFErrorRef *)&err);
4478 if (sign_digest) {
4479 STAssertNil((NSError *)err, @"Setting sign's digest's input for %@", tname);
4480 SecTransformConnectTransforms(sign_digest, kSecTransformOutputAttributeName,
4481 sign, kSecTransformInputAttributeName, group, NULL);
4482 } else {
4483 STAssertNil((NSError *)err, @"Setting sign's input for %@", tname);
4484 }
4485
4486
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);
4492 } else {
4493 STAssertNil((NSError *)err, @"Setting verify's input for %@", tname);
4494 }
4495
4496 SecTransformConnectTransforms(sign2 ? sign2 : sign, kSecTransformOutputAttributeName, verify, kSecSignatureAttributeName, group, NULL);
4497
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)
4502 {
4503 if (message)
4504 {
4505 if (tst->pass)
4506 {
4507 STAssertTrue(message == kCFBooleanTrue, @"Failed to verify proper signature %@; message = %@", tname, message);
4508 } else
4509 {
4510 STAssertTrue(message == kCFBooleanFalse, @"Failed to detect tampering %@; message = %@", tname, message);
4511 }
4512 }
4513
4514 STAssertNil((NSError *)err, @"Executed ok for %@ (err=%@)", tname, error);
4515
4516 if (isFinal)
4517 {
4518 dispatch_group_leave(dg);
4519 }
4520 });
4521
4522 CFRelease(sign);
4523 CFRelease(verify);
4524 CFRelease(group);
4525 }
4526 }
4527 }
4528
4529 struct raw_test {
4530 SecKeyRef pub, priv;
4531 NSString *name;
4532 } raw_tests[] = {
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"},
4536 };
4537
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;
4544
4545 SecTransformRef sign = SecSignTransformCreate(t->priv, &err);
4546 STAssertNil((id)err, @"%@ test sign create err=%@", t->name, err);
4547
4548 SecTransformRef verify = SecVerifyTransformCreate(t->pub, NULL, &err);
4549 STAssertNil((id)err, @"%@ test verify create err=%@", t->name, err);
4550
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);
4557 CFRetain(group);
4558 dispatch_group_async(dg, dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
4559 CFErrorRef xerr = NULL;
4560 CFTypeRef result = SecTransformExecute(group, &xerr);
4561 CFRelease(group);
4562
4563 if (result) {
4564 STAssertTrue(result == kCFBooleanTrue, @"%@ sign result=%@", t->name, result);
4565 } else {
4566 STFail(@"%@ no result", t->name);
4567 }
4568 STAssertNil((id)err, @"%@ execute error=%@", t->name, xerr);
4569 });
4570 CFRelease(group);
4571 }
4572
4573 // Test some things we want to fail for:
4574
4575 SecTransformRef tee = SecNullTransformCreate();
4576 SecTransformSetAttribute(tee, kSecTransformInputAttributeName, message, NULL);
4577 SecTransformRef vrfy = SecVerifyTransformCreate(ecdsa_pub_key, NULL, NULL);
4578
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);
4583 err = NULL;
4584 CFTypeRef no_result = SecTransformExecute(group, (CFErrorRef*)&err);
4585 CFRelease(group);
4586
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);
4592 CFRelease(vrfy);
4593
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();
4597
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);
4603 err = NULL;
4604 no_result = SecTransformExecute(group, (CFErrorRef*)&err);
4605 CFRelease(group);
4606
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);
4611
4612 dispatch_group_wait(dg, DISPATCH_TIME_FOREVER);
4613 }
4614
4615 static BOOL keyWithBytes(CFDataRef keyData, SecKeyRef* key, CFTypeRef keyClass) {
4616 CFErrorRef errorRef=NULL;
4617 CFMutableDictionaryRef parameters;
4618 parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 10, NULL, NULL);
4619
4620 /*
4621 kSecAttrKeyClass values:
4622 kSecAttrKeyClassPublic
4623 kSecAttrKeyClassPrivate
4624 kSecAttrKeyClassSymmetric
4625 */
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);
4632 }
4633
4634 -(void)testVerifyWithKeyFromBytes {
4635 static const uint8_t original_pubKeyData[] =
4636 {
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
4642 };
4643
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,
4654 };
4655 static const uint8_t signatureData[] =
4656 {
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
4661 };
4662
4663 const char *raw_data = "Data to verify";
4664 CFDataRef data = CFDataCreate(NULL, (UInt8*) raw_data, strlen(raw_data));
4665
4666 SecKeyRef key;
4667 CFDataRef cfkeybytes;
4668 CFErrorRef error;
4669 cfkeybytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pubKeyData, sizeof(pubKeyData),kCFAllocatorNull);
4670
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);
4677
4678 CFRelease(vt);
4679 CFRelease(key);
4680 CFRelease(signature);
4681 CFRelease(data);
4682 CFRelease(cfkeybytes);
4683
4684 NSLog(@"STE result %@, err=%@", signature_ok, error);
4685 STAssertNil((id)error, @"Error from SecTransformExecute: %@", error);
4686 } else {
4687 STFail(@"Can't get SecKeyCreateFromData to work");
4688 }
4689 }
4690
4691 -(void)testAESAndCastKeysFromBytes {
4692 CFErrorRef err = NULL;
4693 struct tcase {
4694 const char *name;
4695 CFTypeRef key_type;
4696 NSData *key_data;
4697 };
4698 const char *aes_kbytes = "0123456789012345";
4699 const char *cast_kbytes = "01234567";
4700
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)]},
4704 };
4705
4706 int i;
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,
4712 NULL];
4713
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);
4717
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);
4721
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);
4725
4726 if (k) {
4727 BOOL rt_ok = RoundTrip(CFSTR("/usr/share/dict/propernames"), et, dt, YES);
4728 CFRelease(et);
4729 CFRelease(dt);
4730 STAssertTrue(rt_ok, @"%s's round trip", cases[i].name);
4731 }
4732 }
4733 }
4734
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
4738 // and has changed.
4739
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;
4743
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);
4748 });
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");
4752
4753
4754 }
4755
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();
4765
4766 CFErrorRef err = NULL;
4767
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);
4776
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);
4785
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);
4792
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);
4801
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);
4807
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);
4812
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);
4817
4818 SecTransformSetAttribute(g1, kSecTransformInputAttributeName, input_data, &err);
4819 STAssertNil((id)err, @"Can't set g1's input: %@", err);
4820
4821
4822 CFRelease(e64);
4823 CFRelease(ezlib);
4824 CFRelease(dzlib);
4825 CFRelease(d64);
4826 CFRelease(g1);
4827 CFRelease(g2);
4828 CFRelease(g3);
4829 return outer;
4830 }
4831
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));
4835
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);
4842
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);
4846 CFRelease(outer);
4847 if (err) {
4848 CFRelease(err);
4849 }
4850 }
4851
4852 {
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);
4860 if (err) {
4861 // It can fail right away
4862 ErrorHas((NSError*)err, @"Unsupported decode type");
4863 } else {
4864 // Or later (see below)
4865 STAssertNil((id)err, @"Expected to set decode type: %@", err);
4866 }
4867
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);
4877 err = NULL;
4878 SecTransformConnectTransforms(d64, any, e64, any, bad_outer, &err);
4879 STAssertNotNil((id)err, @"Expected error on cross group connect (in %@)", group_name);
4880 if (err) {
4881 STAssertEquals(CFErrorGetCode(err), (CFIndex)kSecTransformErrorInvalidConnection, @"error code (in %@)", group_name);
4882 STAssertEqualObjects((id)CFErrorGetDomain(err), (id)kSecTransformErrorDomain, @"error domain (in %@)", group_name);
4883 CFRelease(err);
4884 err = NULL;
4885 }
4886
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");
4894 if (err) {
4895 CFRelease(err);
4896 err = NULL;
4897 }
4898 }
4899
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);
4905
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");
4915 if (err) {
4916 CFRelease(err);
4917 err = NULL;
4918 }
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");
4922 if (err) {
4923 CFRelease(err);
4924 err = NULL;
4925 }
4926
4927 CFRelease(bad_outer);
4928 CFRelease(appendix);
4929 }
4930 }
4931
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));
4938
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");
4943
4944 CFDictionaryRef freezeDriedNestedGroups = SecTransformCopyExternalRepresentation(d64);
4945 STAssertNotNil((id)freezeDriedNestedGroups, @"Expected to externalize group");
4946
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));
4951
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");
4955 }
4956
4957 NSString *CopyLeakLine()
4958 {
4959 static char os_build[16];
4960 static dispatch_once_t get_os_build_once;
4961 static BOOL broken_leaks_command = NO;
4962
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);
4967
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
4971 // recover.
4972 broken_leaks_command = YES;
4973 }
4974 });
4975
4976 if (broken_leaks_command) {
4977 return [NSString stringWithFormat:@"Leaks command is broken in %s", os_build];
4978 }
4979
4980 NSRegularExpression *matchLeaksLine = [NSRegularExpression regularExpressionWithPattern:@"^Process \\d+: \\d+ leaks for \\d+ total leaked bytes.$" options:NSRegularExpressionAnchorsMatchLines error:NULL];
4981
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);
4986 free(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) {
4990 return NULL;
4991 }
4992 NSRange matchRange = result.range;
4993 return [output substringWithRange:matchRange];
4994 }
4995
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());
5001 }
5002
5003 NSString *current_leaks = NULL;
5004
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]) {
5010 break;
5011 } else {
5012 sleep(1);
5013 }
5014 }
5015
5016 STAssertNotNil(current_leaks, @"Found current leaks");
5017 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks");
5018 }
5019
5020 -(void)testAAASimpleishLeakTest {
5021 NSLog(@"pid=%d", getpid());
5022 NSString *starting_leaks = CopyLeakLine();
5023 STAssertNotNil(starting_leaks, @"Found initial leaks");
5024 CFErrorRef err = NULL;
5025
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);
5036 CFRelease(data);
5037 CFTypeRef output = SecTransformExecute(b64encode, &err);
5038 STAssertNotNil((id)output, @"Expected result");
5039 STAssertNil((id)err, @"Expected no execute error, got: %@", err);
5040 CFRelease(output);
5041 CFRelease(b64encode);
5042
5043 NSString *current_leaks = NULL;
5044
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]) {
5050 break;
5051 } else {
5052 sleep(1);
5053 }
5054 }
5055
5056 STAssertNotNil(current_leaks, @"Found current leaks");
5057 STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks");
5058 }
5059
5060 @end