2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #include "utilities/SecCFRelease.h"
28 #include "utilities/der_plist.h"
29 #include "utilities/der_plist_internal.h"
30 #include "utilities/SecCFWrappers.h"
32 #include <corecrypto/ccder.h>
33 #include <CoreFoundation/CoreFoundation.h>
35 static const uint8_t* der_decode_key_value(CFAllocatorRef allocator
, CFOptionFlags mutability
,
36 CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
37 const uint8_t* der
, const uint8_t *der_end
)
39 const uint8_t *payload_end
= 0;
40 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &payload_end
, der
, der_end
);
42 if (NULL
== payload
) {
43 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL
, error
);
47 CFTypeRef keyObject
= NULL
;
48 CFTypeRef valueObject
= NULL
;
51 payload
= der_decode_plist(allocator
, mutability
, &keyObject
, error
, payload
, payload_end
);
52 payload
= der_decode_plist(allocator
, mutability
, &valueObject
, error
, payload
, payload_end
);
54 if (payload
!= NULL
) {
58 CFReleaseNull(keyObject
);
59 CFReleaseNull(valueObject
);
64 const uint8_t* der_decode_dictionary(CFAllocatorRef allocator
, CFOptionFlags mutability
,
65 CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
66 const uint8_t* der
, const uint8_t *der_end
)
71 const uint8_t *payload_end
= 0;
72 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
74 if (NULL
== payload
) {
75 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
80 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
83 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create dictionary"), NULL
, error
);
88 while (payload
!= NULL
&& payload
< payload_end
) {
90 CFTypeRef value
= NULL
;
92 payload
= der_decode_key_value(allocator
, mutability
, &key
, &value
, error
, payload
, payload_end
);
95 CFDictionaryAddValue(dict
, key
, value
);
104 if (payload
== payload_end
) {
114 struct size_context
{
120 static size_t der_sizeof_key_value(CFTypeRef key
, CFTypeRef value
, CFErrorRef
*error
) {
121 size_t key_size
= der_sizeof_plist(key
, error
);
125 size_t value_size
= der_sizeof_plist(value
, error
);
126 if (value_size
== 0) {
129 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, key_size
+ value_size
);
132 static void add_key_value_size(const void *key_void
, const void *value_void
, void *context_void
)
134 CFTypeRef key
= (CFTypeRef
) key_void
;
135 CFTypeRef value
= (CFTypeRef
) value_void
;
136 struct size_context
*context
= (struct size_context
*) context_void
;
138 if (!context
->success
)
141 size_t kv_size
= der_sizeof_key_value(key
, value
, context
->error
);
143 context
->success
= false;
147 context
->size
+= kv_size
;
150 size_t der_sizeof_dictionary(CFDictionaryRef dict
, CFErrorRef
*error
)
152 struct size_context context
= { .success
= true, .size
= 0, .error
= error
};
155 CFDictionaryApplyFunction(dict
, add_key_value_size
, &context
);
157 if (!context
.success
)
160 return ccder_sizeof(CCDER_CONSTRUCTED_SET
, context
.size
);
163 static uint8_t* der_encode_key_value(CFPropertyListRef key
, CFPropertyListRef value
, CFErrorRef
*error
,
164 const uint8_t* der
, uint8_t *der_end
)
166 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
167 der_encode_plist(key
, error
, der
,
168 der_encode_plist(value
, error
, der
, der_end
)));
171 struct encode_context
{
174 CFMutableArrayRef list
;
175 CFAllocatorRef allocator
;
178 static void add_sequence_to_array(const void *key_void
, const void *value_void
, void *context_void
)
180 struct encode_context
*context
= (struct encode_context
*) context_void
;
181 if (context
->success
) {
182 CFTypeRef key
= (CFTypeRef
) key_void
;
183 CFTypeRef value
= (CFTypeRef
) value_void
;
185 size_t der_size
= der_sizeof_key_value(key
, value
, context
->error
);
187 context
-> success
= false;
189 CFMutableDataRef encoded_kv
= CFDataCreateMutable(context
->allocator
, der_size
);
190 CFDataSetLength(encoded_kv
, der_size
);
192 uint8_t* const encode_begin
= CFDataGetMutableBytePtr(encoded_kv
);
193 uint8_t* encode_end
= encode_begin
+ der_size
;
195 encode_end
= der_encode_key_value(key
, value
, context
->error
, encode_begin
, encode_end
);
197 if (encode_end
!= NULL
) {
198 CFDataDeleteBytes(encoded_kv
, CFRangeMake(0, (encode_end
- encode_begin
)));
199 CFArrayAppendValue(context
->list
, encoded_kv
);
201 context
-> success
= false;
204 CFReleaseNull(encoded_kv
);
209 static CFComparisonResult
cfdata_compare_contents(const void *val1
, const void *val2
, void *context __unused
)
211 return CFDataCompare((CFDataRef
) val1
, (CFDataRef
) val2
);
215 uint8_t* der_encode_dictionary(CFDictionaryRef dictionary
, CFErrorRef
*error
,
216 const uint8_t *der
, uint8_t *der_end
)
218 CFMutableArrayRef elements
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
220 struct encode_context context
= { .success
= true, .error
= error
, .list
= elements
};
221 CFDictionaryApplyFunction(dictionary
, add_sequence_to_array
, &context
);
223 if (!context
.success
) {
224 CFReleaseNull(elements
);
228 CFRange allOfThem
= CFRangeMake(0, CFArrayGetCount(elements
));
230 CFArraySortValues(elements
, allOfThem
, cfdata_compare_contents
, NULL
);
232 uint8_t* original_der_end
= der_end
;
234 for(CFIndex position
= CFArrayGetCount(elements
); position
> 0;) {
236 CFDataRef data
= CFArrayGetValueAtIndex(elements
, position
);
237 der_end
= ccder_encode_body(CFDataGetLength(data
), CFDataGetBytePtr(data
), der
, der_end
);
240 CFReleaseNull(elements
);
242 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET
, original_der_end
, der
, der_end
);