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