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