]> git.saurik.com Git - apple/security.git/blob - libsecurity_transform/lib/SecTransformReadTransform.cpp
Security-55471.tar.gz
[apple/security.git] / libsecurity_transform / lib / SecTransformReadTransform.cpp
1 #include "SecTransformReadTransform.h"
2 #include "SecCustomTransform.h"
3 #include "Utilities.h"
4
5 static CFStringRef kStreamTransformName = CFSTR("SecReadStreamTransform");
6 static CFStringRef kStreamMaxSize = CFSTR("MAX_READSIZE");
7
8 static SecTransformInstanceBlock StreamTransformImplementation(CFStringRef name,
9 SecTransformRef newTransform,
10 SecTransformImplementationRef ref)
11 {
12 SecTransformInstanceBlock instanceBlock =
13 ^{
14 CFErrorRef result = NULL;
15
16 if (NULL == name || NULL == newTransform)
17 {
18 }
19
20 // define the storage for our block
21 __block CFIndex blockSize = 4096; // make a default block size
22
23 // it's not necessary to set the input stream size
24 SecTransformCustomSetAttribute(ref, kStreamMaxSize, kSecTransformMetaAttributeRequired, kCFBooleanFalse);
25
26 // define the action if we change the max read size
27 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kStreamMaxSize,
28 ^(SecTransformAttributeRef attribute, CFTypeRef value)
29 {
30 CFNumberGetValue((CFNumberRef) value, kCFNumberCFIndexType, &blockSize);
31 return value;
32 });
33
34 // define for our input action
35 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName,
36 ^(SecTransformAttributeRef attribute, CFTypeRef value)
37 {
38 if (value == NULL)
39 {
40 return (CFTypeRef) NULL;
41 }
42
43 CFArrayRef array = (CFArrayRef) value;
44 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, 0);
45
46 // Ensure that indeed we do have a CFReadStreamRef
47 if (NULL == item || CFReadStreamGetTypeID() != CFGetTypeID(item))
48 {
49 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "The input attribute item was nil or not a read stream");
50 }
51
52 // This now is a safe cast
53 CFReadStreamRef input = (CFReadStreamRef)item;
54
55 // Get the state of the stream
56 CFStreamStatus streamStatus = CFReadStreamGetStatus(input);
57 switch (streamStatus)
58 {
59 case kCFStreamStatusNotOpen:
60 {
61 if (!CFReadStreamOpen(input))
62 {
63 // We didn't open properly. Error out
64 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "An error occurred while opening the stream.");
65 }
66 }
67 break;
68
69 case kCFStreamStatusError:
70 {
71 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "The read stream is in an error state");
72 }
73 break;
74
75 default:
76 // The assumption is that the stream is ready to go as is.
77 break;
78 }
79
80 // allocate the read buffer on the heap
81 u_int8_t* buffer = (u_int8_t*) malloc(blockSize);
82
83 CFIndex bytesRead;
84
85 bytesRead = CFReadStreamRead(input, buffer, blockSize);
86 while (bytesRead > 0)
87 {
88 // make data from what was read
89 CFDataRef value = CFDataCreate(NULL, buffer, bytesRead);
90
91 // send it down the chain
92 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
93
94 // cleanup
95 CFRelease(value);
96
97 bytesRead = CFReadStreamRead(input, buffer, blockSize);
98 }
99
100 free(buffer);
101
102 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef) NULL);
103
104 return (CFTypeRef) NULL;
105 });
106
107 return result;
108 };
109
110 return Block_copy(instanceBlock);
111 }
112
113
114
115 SecTransformRef SecTransformCreateReadTransformWithReadStream(CFReadStreamRef inputStream)
116 {
117 static dispatch_once_t once = 0;
118
119 __block bool ok = true;
120 __block CFErrorRef result = NULL;
121
122 dispatch_once(&once,
123 ^{
124 ok = SecTransformRegister(kStreamTransformName, &StreamTransformImplementation, &result);
125 });
126
127 if (!ok)
128 {
129 return result;
130 }
131 else
132 {
133
134 SecTransformRef transform = SecTransformCreate(kStreamTransformName, &result);
135 if (NULL != transform)
136 {
137 // if we add the read stream directly to the transform the internal source stream
138 // will take over. This is bad. Instead, we wrap this in a CFArray so that we can
139 // pass through undetected
140 CFTypeRef arrayData[] = {inputStream};
141 CFArrayRef arrayRef = CFArrayCreate(NULL, arrayData, 1, &kCFTypeArrayCallBacks);
142
143 // add the input to the transform
144 SecTransformSetAttribute(transform, kSecTransformInputAttributeName, arrayRef, &result);
145
146 CFRelease(arrayRef);
147 }
148
149 return transform;
150 }
151 }