1 #include "SecTransform.h"
2 #include "SecTransformInternal.h"
6 #include "TransformFactory.h"
7 #include "GroupTransform.h"
9 #include "SecCollectTransform.h"
16 const CFStringRef kSecTransformInputAttributeName
= CFSTR("INPUT");
17 const CFStringRef kSecTransformOutputAttributeName
= CFSTR("OUTPUT");
18 const CFStringRef kSecTransformDebugAttributeName
= CFSTR("DEBUG");
19 const CFStringRef kSecTransformTransformName
= CFSTR("NAME");
20 //const CFStringRef kSecTransformErrorTransform = CFSTR("TRANSFORM");
21 const CFStringRef kSecTransformErrorDomain
= CFSTR("com.apple.security.transforms.error");
22 const CFStringRef kSecTransformAbortAttributeName
= CFSTR("ABORT");
24 CFErrorRef
SecTransformConnectTransformsInternal(SecGroupTransformRef groupRef
,
25 SecTransformRef sourceTransformRef
,
26 CFStringRef sourceAttributeName
,
27 SecTransformRef destinationTransformRef
,
28 CFStringRef destinationAttributeName
)
30 Transform
* destination
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(destinationTransformRef
);
31 Transform
* source
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(sourceTransformRef
);
33 GroupTransform
* group
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(groupRef
);
34 CFErrorRef temp
= source
->Connect(group
, destination
, destinationAttributeName
, sourceAttributeName
);
39 CFErrorRef
SecTransformDisconnectTransforms(SecTransformRef sourceTransformRef
, CFStringRef sourceAttributeName
,
40 SecTransformRef destinationTransformRef
, CFStringRef destinationAttributeName
)
42 Transform
* destination
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(destinationTransformRef
);
43 Transform
* source
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(sourceTransformRef
);
44 return source
->Disconnect(destination
, sourceAttributeName
, destinationAttributeName
);
47 SecGroupTransformRef
SecTransformCreateGroupTransform()
49 return (SecGroupTransformRef
) GroupTransform::Make();
52 SecGroupTransformRef
SecTransformConnectTransforms(SecTransformRef sourceTransformRef
,
53 CFStringRef sourceAttributeName
,
54 SecTransformRef destinationTransformRef
,
55 CFStringRef destinationAttributeName
,
56 SecGroupTransformRef group
,
63 *error
= CreateSecTransformErrorRef(kSecTransformErrorMissingParameter
, "Group must not be NULL.");
69 if (destinationAttributeName
== NULL
)
71 destinationAttributeName
= kSecTransformInputAttributeName
;
74 if (sourceAttributeName
== NULL
)
76 sourceAttributeName
= kSecTransformOutputAttributeName
;
79 GroupTransform
* gtr
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(group
);
81 CFErrorRef temp
= SecTransformConnectTransformsInternal(gtr
->GetCFObject(),
82 sourceTransformRef
, sourceAttributeName
,
83 destinationTransformRef
, destinationAttributeName
);
90 if (temp
) // an error happened?
102 Boolean
SecTransformSetAttribute(SecTransformRef transformRef
,
107 Boolean result
= false; // Guilty until proven
108 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
110 if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID() && !transform
->getAH(key
, false))
114 *error
= CreateSecTransformErrorRef(kSecTransformOperationNotSupportedOnGroup
, "SecTransformSetAttribute on non-exported attribute: %@ (exported attributes are: %@).", key
, transform
->GetAllAH());
120 // if the caller is setting the abort attribute, a value must be supplied
121 if (NULL
== value
&& CFStringCompare(key
, kSecTransformAbortAttributeName
, 0) == kCFCompareEqualTo
)
125 // XXX: "a parameter"? It has one: NULL. What it requires is a non-NULL value.
126 *error
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
, "ABORT requires a parameter.");
132 CFErrorRef temp
= transform
->ExternalSetAttribute(key
, value
);
133 result
= (temp
== NULL
);
151 CFTypeRef
SecTransformGetAttribute(SecTransformRef transformRef
,
154 // if the transform is a group, we really want to operation on its first object
155 if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID())
160 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
161 if (transform
->mIsActive
) {
162 return CreateSecTransformErrorRef(kSecTransformTransformIsExecuting
, "Can not get the value of attributes during execution (attempt to fetch %@/%@)", transform
->GetName(), key
);
164 return transform
->GetAttribute(key
);
168 #pragma clang diagnostic push
169 #pragma clang diagnostic ignored "-Wunused-function"
170 static inline GroupTransform
* MakeGroupTransformFromTransformRef(SecTransformRef tr
)
172 GroupTransform
* gt
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(tr
);
175 #pragma clang diagnostic pop
177 static CFTypeRef
InternalSecTransformExecute(SecTransformRef transformRef
,
178 CFErrorRef
* errorRef
,
179 dispatch_queue_t deliveryQueue
,
180 SecMessageBlock deliveryBlock
)
182 if (NULL
== transformRef
|| (deliveryBlock
&& !deliveryQueue
))
184 CFErrorRef localError
= CFErrorCreate(kCFAllocatorDefault
, kSecTransformErrorDomain
,
185 kSecTransformInvalidArgument
, NULL
);
187 if (NULL
!= errorRef
)
189 *errorRef
= localError
;
193 CFRelease(localError
);
196 return (CFTypeRef
)NULL
;
199 // if our transform is a group, connect to its first member instead
200 if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID())
202 GroupTransform
* gtsrc
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
203 transformRef
= gtsrc
->GetAnyMember();
206 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
207 return transform
->Execute(deliveryQueue
, deliveryBlock
, errorRef
);
210 CFTypeRef
SecTransformExecute(SecTransformRef transformRef
, CFErrorRef
* errorRef
)
212 if (NULL
== transformRef
)
216 *errorRef
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
, "NULL transform can not be executed");
221 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
223 // transform->Execute will check this, but by then we have attached a collector which causes all manner of issues.
224 if (transform
->mIsActive
)
228 *errorRef
= CreateSecTransformErrorRef(kSecTransformTransformIsExecuting
, "The %@ transform has already executed, it may not be executed again.", transform
->GetName());
233 SecTransformRef collectTransform
= transforms_assume(SecCreateCollectTransform(errorRef
));
234 SecGroupTransformRef theGroup
= NULL
;
235 Boolean releaseTheGroup
= false;
236 GroupTransform
* myGroup
= NULL
;
237 Boolean needConnection
= true;
239 // Sniff the type of the transformRef to see if it is a group
240 if (SecGroupTransformGetTypeID() == CFGetTypeID(transformRef
))
242 theGroup
= (SecGroupTransformRef
)transformRef
;
246 // Ok TransformRef is a TransformRef so get's it group
248 myGroup
= transform
->mGroup
;
252 theGroup
= SecTransformCreateGroupTransform();
253 if (NULL
== theGroup
)
255 if (NULL
!= errorRef
)
257 *errorRef
= GetNoMemoryErrorAndRetain();
260 return (CFTypeRef
)NULL
;
264 releaseTheGroup
= true;
266 SecGroupTransformRef connectResult
=
267 SecTransformConnectTransforms(transformRef
,
268 kSecTransformOutputAttributeName
,
270 kSecTransformInputAttributeName
,
273 if (NULL
== connectResult
)
275 return (CFTypeRef
)NULL
;
278 needConnection
= false;
283 theGroup
= (SecGroupTransformRef
)myGroup
->GetCFObject();
287 if (NULL
== theGroup
|| (SecGroupTransformGetTypeID() != CFGetTypeID(theGroup
)))
289 if (NULL
!= errorRef
)
291 *errorRef
= GetNoMemoryErrorAndRetain();
294 return (CFTypeRef
)NULL
;
301 // Connect the collectTransform to the group
302 myGroup
= ((GroupTransform
*)CoreFoundationHolder::ObjectFromCFType(theGroup
))->GetRootGroup();
305 if (NULL
!= errorRef
)
307 *errorRef
= GetNoMemoryErrorAndRetain();
310 return (CFTypeRef
)NULL
;
313 SecTransformRef outputTransform
= myGroup
->FindLastTransform();
315 SecGroupTransformRef connectResult
=
316 SecTransformConnectTransforms(outputTransform
,
317 kSecTransformOutputAttributeName
,
319 kSecTransformInputAttributeName
,
320 myGroup
->GetCFObject(), errorRef
);
322 if (NULL
== connectResult
)
324 CFRelease(collectTransform
);
329 return (CFTypeRef
)NULL
;
333 __block CFTypeRef myResult
= NULL
;
334 dispatch_semaphore_t mySem
= dispatch_semaphore_create(0L);
335 dispatch_queue_t myQueue
= dispatch_queue_create("com.apple.security.sectransfrom.SecTransformExecute", NULL
);
336 SecMessageBlock myBlock
= ^(CFTypeRef message
, CFErrorRef error
, Boolean isFinal
)
340 if (NULL
!= errorRef
)
346 if (NULL
!= myResult
)
361 dispatch_semaphore_signal(mySem
);
365 SecTransformExecuteAsync(theGroup
, myQueue
, myBlock
);
366 dispatch_semaphore_wait(mySem
, DISPATCH_TIME_FOREVER
);
367 dispatch_release(mySem
);
368 dispatch_release(myQueue
);
375 CFRelease(collectTransform
);
380 void SecTransformExecuteAsync(SecTransformRef transformRef
,
381 dispatch_queue_t deliveryQueue
,
382 SecMessageBlock deliveryBlock
)
384 CFErrorRef localError
= NULL
;
385 InternalSecTransformExecute(transformRef
, &localError
, deliveryQueue
, deliveryBlock
);
387 // if we got an error (usually a transform startup error), we must deliver it
388 if (localError
!= NULL
)
390 // The monitor treats a NULL queue as running on it's own queue, which from an appication's point of view is
391 // the same as a default global queue. Chances are there is no monitor at this point, so it is best to just use the
392 // global queue for this.
393 dispatch_queue_t effectiveQueue
= deliveryQueue
? deliveryQueue
: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, NULL
);
394 dispatch_async(effectiveQueue
, ^{
395 deliveryBlock(NULL
, localError
, true);
400 CFDictionaryRef
SecTransformCopyExternalRepresentation(SecTransformRef transformRef
)
403 Transform
* tr
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
404 return tr
->Externalize(NULL
);
407 CFStringRef
SecTransformDotForDebugging(SecTransformRef transformRef
)
409 if (CFGetTypeID(transformRef
) == SecGroupTransformGetTypeID()) {
410 GroupTransform
* tr
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
411 return tr
->DotForDebugging();
413 return CFSTR("Can only dot debug a group");
417 SecTransformRef
SecTransformCreateFromExternalRepresentation(
418 CFDictionaryRef dictionary
,
421 // The incoming dictionary consists of a list of transforms and
422 // a list of connections. We start by making the individual
423 // transforms and storing them in a dictionary so that we can
424 // efficiently make connections
426 CFArrayRef transforms
= (CFArrayRef
) CFDictionaryGetValue(dictionary
, EXTERN_TRANSFORM_TRANSFORM_ARRAY
);
427 if (transforms
== NULL
)
429 // The dictionary we got is massively malformed!
430 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "%@ is missing from the dictionary. The dictionary is malformed.", EXTERN_TRANSFORM_TRANSFORM_ARRAY
);
434 CFArrayRef connections
= (CFArrayRef
) CFDictionaryGetValue(dictionary
, EXTERN_TRANSFORM_CONNECTION_ARRAY
);
435 if (connections
== NULL
)
437 // The dictionary we got is massively malformed!
438 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "%@ is missing from the dictionary. The dictionary is malformed.", EXTERN_TRANSFORM_CONNECTION_ARRAY
);
442 CFMutableDictionaryRef transformHolder
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
443 CFTypeRefHolder
_(transformHolder
);
445 CFIndex numTransforms
= CFArrayGetCount(transforms
);
448 SecTransformRef aTransform
;
450 for (n
= 0; n
< numTransforms
; ++n
)
452 // get the basic info we need
453 CFDictionaryRef xTransform
= (CFDictionaryRef
) CFArrayGetValueAtIndex(transforms
, n
);
455 CFStringRef xName
= (CFStringRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_NAME
);
457 CFStringRef xType
= (CFStringRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_TYPE
);
459 // reconstruct the transform
460 aTransform
= TransformFactory::MakeTransformWithType(xType
, error
);
461 SecTransformSetAttribute(aTransform
, kSecTransformTransformName
, xName
, NULL
);
463 // restore the transform state
464 Transform
* tr
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(aTransform
);
465 tr
->RestoreState((CFDictionaryRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_STATE
));
466 tr
->SetCustomExternalData((CFDictionaryRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY
));
468 CFIndex cnt
= CFDictionaryGetCount(transformHolder
);
470 // add the transform to the dictionary
471 CFDictionaryAddValue(transformHolder
, xName
, aTransform
);
473 if (CFDictionaryGetCount(transformHolder
) <= cnt
)
477 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
,
478 "Out of memory, or damaged input dictonary (duplicate label %@?)", xName
);
484 CFIndex numConnections
= CFArrayGetCount(connections
);
485 if (numConnections
== 0)
490 SecGroupTransformRef gt
= SecTransformCreateGroupTransform();
492 for (n
= 0; n
< numConnections
; ++n
)
494 CFDictionaryRef connection
= (CFDictionaryRef
) CFArrayGetValueAtIndex(connections
, n
);
495 CFStringRef fromTransformName
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_FROM_NAME
);
496 CFStringRef fromAttribute
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_FROM_ATTRIBUTE
);
497 CFStringRef toTransformName
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_TO_NAME
);
498 CFStringRef toAttribute
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_TO_ATTRIBUTE
);
500 SecTransformRef fromTransform
= (SecTransformRef
) CFDictionaryGetValue(transformHolder
, fromTransformName
);
501 if (!fromTransform
) {
503 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "Can't connect %@ to %@ because %@ was not found", fromTransformName
, toTransformName
, fromTransformName
);
507 SecTransformRef toTransform
= (SecTransformRef
) CFDictionaryGetValue(transformHolder
, toTransformName
);
510 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "Can't connect %@ to %@ because %@ was not found", fromTransformName
, toTransformName
, toTransformName
);
515 aTransform
= SecTransformConnectTransforms(fromTransform
, fromAttribute
, toTransform
, toAttribute
, gt
, error
);
523 SecTransformRef
SecTransformFindByName(SecTransformRef transform
, CFStringRef name
)
525 Transform
*t
= (Transform
*)CoreFoundationHolder::ObjectFromCFType(transform
);
526 GroupTransform
*g
= t
->GetRootGroup();
529 return g
->FindByName(name
);
531 // There is no group, so if transform isn't our guy nobody is.
532 return (CFStringCompare(name
, t
->GetName(), 0) == kCFCompareEqualTo
) ? transform
: NULL
;
538 CFTypeID
SecGroupTransformGetTypeID()
540 return GroupTransform::GetCFTypeID();
543 CFTypeID
SecTransformGetTypeID()
545 // Obviously this is wrong (returns same CFTypeID as SecTransformGetTypeID) Needs to be fixed
546 return GroupTransform::GetCFTypeID();