]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
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 | ||
b1ab9ed8 A |
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" | |
d8f41ccd A |
55 | #include <CoreFoundation/CFBase.h> |
56 | #include <CoreFoundation/CFData.h> | |
57 | #include <CoreFoundation/CFRuntime.h> | |
b1ab9ed8 A |
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. | |
d8f41ccd | 116 | static SecTransformRef custom_transform(CFStringRef base_name, SecTransformCreateBlock cb) |
b1ab9ed8 A |
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 | ||
d8f41ccd | 148 | static BOOL ErrorHas(NSError *error, NSString *rx) { |
b1ab9ed8 A |
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); | |
d8f41ccd | 181 | usleep((useconds_t)(n / NSEC_PER_USEC)); |
b1ab9ed8 A |
182 | } |
183 | ||
184 | return value; | |
185 | }); | |
186 | return result; | |
187 | }; | |
188 | ||
189 | return Block_copy(instanceBlock); | |
190 | } | |
191 | ||
d8f41ccd | 192 | static SecTransformRef delay_transform(long long nsec) { |
b1ab9ed8 A |
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 | ||
d8f41ccd | 334 | char* rBuffer = (char*) malloc((size_t)st.st_size); |
b1ab9ed8 | 335 | FILE* f = fopen(name, "r"); |
d8f41ccd | 336 | fread(rBuffer, 1, (size_t)st.st_size, f); |
b1ab9ed8 A |
337 | fclose(f); |
338 | ||
339 | // set up our output parser | |
d8f41ccd | 340 | BufferStream bStream(rBuffer, (size_t)st.st_size); |
b1ab9ed8 A |
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"); | |
d8f41ccd | 400 | fwrite(rBuffer, 1, (size_t)st.st_size, f); |
b1ab9ed8 A |
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) { | |
d8f41ccd | 527 | NSString *name = [NSString stringWithFormat:@"many%luregister", i]; |
b1ab9ed8 A |
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); | |
d8f41ccd | 544 | OSStatus status = SecKeychainCreate(kcfname, (UInt32)strlen(passwd), passwd, NO, NULL, &tmp_keychain); |
b1ab9ed8 A |
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); | |
d8f41ccd | 636 | OSStatus status = SecKeychainCreate(kcfname, (UInt32)strlen(passwd), passwd, NO, NULL, &tmp_keychain); |
b1ab9ed8 A |
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++) { | |
d8f41ccd | 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]); |
b1ab9ed8 A |
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"; | |
d8f41ccd | 2053 | //NSData *empty = [NSData dataWithBytes:NULL length:0]; |
b1ab9ed8 | 2054 | NSData *data = [NSData dataWithBytes:raw_data length:strlen((const char *)raw_data)]; |
d8f41ccd | 2055 | //NSUInteger ecnt = [empty retainCount]; |
b1ab9ed8 A |
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) { | |
d8f41ccd A |
2065 | // if ([empty length]) { |
2066 | // NSLog(@"Empty data not so empty"); | |
2067 | // } | |
b1ab9ed8 A |
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 | ||
d8f41ccd | 2080 | //STAssertTrue(ecnt < [empty retainCount], @"SecTransformExecute retained block"); |
b1ab9ed8 A |
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; | |
d8f41ccd | 2333 | //id testObj = (id)d; |
b1ab9ed8 A |
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 | { | |
d8f41ccd | 2350 | //float knownVersion = 1.0; |
b1ab9ed8 A |
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 | ||
d8f41ccd | 2459 | static CFNumberRef MakeNumber1(long n) |
b1ab9ed8 A |
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 | ||
d8f41ccd | 2593 | static SecTransformRef count_transform(int n) { |
b1ab9ed8 A |
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 | |
427c49bc | 3179 | OSStatus err = errSecSuccess; |
b1ab9ed8 A |
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); | |
427c49bc A |
3245 | STAssertTrue(err == errSecSuccess, [NSString stringWithFormat:@"Unable to create a symmetrical key %@", algNames[iCnt]]); |
3246 | if (errSecSuccess != err) | |
b1ab9ed8 A |
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 | ||
427c49bc A |
3347 | STAssertTrue(errSecSuccess == err, @"Unable to create a key pair"); |
3348 | if (errSecSuccess != err) | |
b1ab9ed8 A |
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); | |
427c49bc | 3451 | STAssertTrue(err == errSecSuccess, @"Unable to create a symmetrical key err=%x", err); |
b1ab9ed8 A |
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 | ||
d8f41ccd | 3668 | static BOOL RoundTrip(CFStringRef fname, SecTransformRef in, SecTransformRef out, BOOL share) |
b1ab9ed8 A |
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]; | |
d8f41ccd | 3948 | CFIndex n = CFArrayGetCountOfValue((CFArrayRef)r, CFRangeMake(0, CFArrayGetCount((CFArrayRef)r)), z); |
b1ab9ed8 | 3949 | // There should be six zeros in the xor->feedback chain from 0 to 19. |
d8f41ccd | 3950 | STAssertEquals(n, (CFIndex) 6, @"There should be six zeros in %@", r); |
b1ab9ed8 A |
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)); | |
d8f41ccd A |
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 | ||
b1ab9ed8 A |
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"); | |
d8f41ccd A |
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 | } | |
b1ab9ed8 A |
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); | |
d8f41ccd A |
4190 | CFRelease(et); |
4191 | CFRelease(et_neg); | |
4192 | CFRelease(dt); | |
b1ab9ed8 A |
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); | |
d8f41ccd | 4354 | gp_status = SecKeychainCreate(kcfname, (UInt32) strlen(passwd), passwd, NO, NULL, &tmp_keychain); |
b1ab9ed8 A |
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 { | |
d8f41ccd | 4693 | /* |
b1ab9ed8 A |
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 | |
d8f41ccd | 4701 | }; */ |
b1ab9ed8 A |
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. | |
d8f41ccd | 4819 | static SecTransformRef build_nested_groups(id self, CFDataRef input_data) { |
b1ab9ed8 A |
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 | ||
d8f41ccd | 5016 | static NSString *CopyLeakLine() |
b1ab9ed8 A |
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 | |
b1ab9ed8 A |
5086 | SecTransformRef b64encode = SecEncodeTransformCreate(kSecBase64Encoding, NULL); |
5087 | const int buffer_size = 1024; | |
5088 | void *buffer = malloc(buffer_size); | |
866f8763 A |
5089 | STAssert(SecRandomCopyBytes(kSecRandomDefault, buffer_size, buffer) == noErr), @"Random failed"); |
5090 | ||
b1ab9ed8 A |
5091 | CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, (UInt8*)buffer, buffer_size, kCFAllocatorMalloc); |
5092 | SecTransformSetAttribute(b64encode, kSecTransformInputAttributeName, data, &err); | |
5093 | STAssertNil((id)err, @"Expected no SecTransformSetAttribute error, got: %@", err); | |
5094 | CFRelease(data); | |
5095 | CFTypeRef output = SecTransformExecute(b64encode, &err); | |
5096 | STAssertNotNil((id)output, @"Expected result"); | |
5097 | STAssertNil((id)err, @"Expected no execute error, got: %@", err); | |
5098 | CFRelease(output); | |
5099 | CFRelease(b64encode); | |
5100 | ||
5101 | NSString *current_leaks = NULL; | |
5102 | ||
5103 | // Some of the destruction is async, so if they don't pan out the same, a little sleep and retry | |
5104 | // can legitimately fix it. | |
5105 | for(int i = 0; i < 10; i++) { | |
5106 | current_leaks = CopyLeakLine(); | |
5107 | if ([current_leaks isEqualToString:starting_leaks]) { | |
5108 | break; | |
5109 | } else { | |
5110 | sleep(1); | |
5111 | } | |
5112 | } | |
5113 | ||
5114 | STAssertNotNil(current_leaks, @"Found current leaks"); | |
5115 | STAssertEqualObjects(current_leaks, starting_leaks, @"Expected no new leaks"); | |
5116 | } | |
5117 | ||
5118 | @end |