5 // Created by Mitch Adler on 6/18/12.
6 // Copyright (c) 2012 Apple Inc. All rights reserved.
11 #include "utilities/SecCFRelease.h"
12 #include "utilities/der_plist.h"
13 #include "utilities/der_plist_internal.h"
14 #include "utilities/SecCFWrappers.h"
16 #include <corecrypto/ccder.h>
17 #include <CoreFoundation/CoreFoundation.h>
19 static const uint8_t* der_decode_key_value(CFAllocatorRef allocator
, CFOptionFlags mutability
,
20 CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
21 const uint8_t* der
, const uint8_t *der_end
)
23 const uint8_t *payload_end
= 0;
24 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &payload_end
, der
, der_end
);
26 if (NULL
== payload
) {
27 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL
, error
);
31 CFTypeRef keyObject
= NULL
;
32 CFTypeRef valueObject
= NULL
;
35 payload
= der_decode_plist(allocator
, mutability
, &keyObject
, error
, payload
, payload_end
);
36 payload
= der_decode_plist(allocator
, mutability
, &valueObject
, error
, payload
, payload_end
);
38 if (payload
!= NULL
) {
42 CFReleaseNull(keyObject
);
43 CFReleaseNull(valueObject
);
48 const uint8_t* der_decode_dictionary(CFAllocatorRef allocator
, CFOptionFlags mutability
,
49 CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
50 const uint8_t* der
, const uint8_t *der_end
)
55 const uint8_t *payload_end
= 0;
56 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
58 if (NULL
== payload
) {
59 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
64 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
67 SecCFDERCreateError(kSecDERErrorUnderlyingError
, CFSTR("Failed to create data"), NULL
, error
);
72 while (payload
!= NULL
&& payload
< payload_end
) {
74 CFTypeRef value
= NULL
;
76 payload
= der_decode_key_value(allocator
, mutability
, &key
, &value
, error
, payload
, payload_end
);
79 CFDictionaryAddValue(dict
, key
, value
);
87 if (payload
== payload_end
) {
103 static size_t der_sizeof_key_value(CFTypeRef key
, CFTypeRef value
, CFErrorRef
*error
) {
104 size_t key_size
= der_sizeof_plist(key
, error
);
108 size_t value_size
= der_sizeof_plist(value
, error
);
109 if (value_size
== 0) {
112 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, key_size
+ value_size
);
115 static void add_key_value_size(const void *key_void
, const void *value_void
, void *context_void
)
117 CFTypeRef key
= (CFTypeRef
) key_void
;
118 CFTypeRef value
= (CFTypeRef
) value_void
;
119 struct size_context
*context
= (struct size_context
*) context_void
;
121 if (!context
->success
)
124 size_t kv_size
= der_sizeof_key_value(key
, value
, context
->error
);
126 context
->success
= false;
130 context
->size
+= kv_size
;
133 size_t der_sizeof_dictionary(CFDictionaryRef dict
, CFErrorRef
*error
)
135 struct size_context context
= { .success
= true, .size
= 0, .error
= error
};
138 CFDictionaryApplyFunction(dict
, add_key_value_size
, &context
);
140 if (!context
.success
)
143 return ccder_sizeof(CCDER_CONSTRUCTED_SET
, context
.size
);
146 static uint8_t* der_encode_key_value(CFPropertyListRef key
, CFPropertyListRef value
, CFErrorRef
*error
,
147 const uint8_t* der
, uint8_t *der_end
)
149 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
150 der_encode_plist(key
, error
, der
,
151 der_encode_plist(value
, error
, der
, der_end
)));
154 struct encode_context
{
157 CFMutableArrayRef list
;
158 CFAllocatorRef allocator
;
161 static void add_sequence_to_array(const void *key_void
, const void *value_void
, void *context_void
)
163 struct encode_context
*context
= (struct encode_context
*) context_void
;
164 if (context
->success
) {
165 CFTypeRef key
= (CFTypeRef
) key_void
;
166 CFTypeRef value
= (CFTypeRef
) value_void
;
168 size_t der_size
= der_sizeof_key_value(key
, value
, context
->error
);
170 context
-> success
= false;
172 CFMutableDataRef encoded_kv
= CFDataCreateMutable(context
->allocator
, der_size
);
173 CFDataSetLength(encoded_kv
, der_size
);
175 uint8_t* const encode_begin
= CFDataGetMutableBytePtr(encoded_kv
);
176 uint8_t* encode_end
= encode_begin
+ der_size
;
178 encode_end
= der_encode_key_value(key
, value
, context
->error
, encode_begin
, encode_end
);
180 if (encode_end
!= NULL
) {
181 CFDataDeleteBytes(encoded_kv
, CFRangeMake(0, (encode_end
- encode_begin
)));
182 CFArrayAppendValue(context
->list
, encoded_kv
);
184 context
-> success
= false;
187 CFReleaseNull(encoded_kv
);
192 static CFComparisonResult
cfdata_compare_contents(const void *val1
, const void *val2
, void *context __unused
)
194 return CFDataCompare((CFDataRef
) val1
, (CFDataRef
) val2
);
198 uint8_t* der_encode_dictionary(CFDictionaryRef dictionary
, CFErrorRef
*error
,
199 const uint8_t *der
, uint8_t *der_end
)
201 CFMutableArrayRef elements
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
203 struct encode_context context
= { .success
= true, .error
= error
, .list
= elements
};
204 CFDictionaryApplyFunction(dictionary
, add_sequence_to_array
, &context
);
206 if (!context
.success
) {
207 CFReleaseNull(elements
);
211 CFRange allOfThem
= CFRangeMake(0, CFArrayGetCount(elements
));
213 CFArraySortValues(elements
, allOfThem
, cfdata_compare_contents
, NULL
);
215 uint8_t* original_der_end
= der_end
;
217 for(CFIndex position
= CFArrayGetCount(elements
); position
> 0;) {
219 CFDataRef data
= CFArrayGetValueAtIndex(elements
, position
);
220 der_end
= ccder_encode_body(CFDataGetLength(data
), CFDataGetBytePtr(data
), der
, der_end
);
223 CFReleaseNull(elements
);
225 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET
, original_der_end
, der
, der_end
);