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
,
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
, &keyObject
, error
, payload
, payload_end
);
52 payload
= der_decode_plist(allocator
, &valueObject
, error
, payload
, payload_end
);
54 if (payload
!= NULL
) {
58 CFReleaseNull(keyObject
);
59 CFReleaseNull(valueObject
);
64 const uint8_t* der_decode_dictionary(CFAllocatorRef allocator
,
65 CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
66 const uint8_t* der
, const uint8_t *der_end
)
69 SecCFDERCreateError(kSecDERErrorNullInput
, CFSTR("null input"), NULL
, error
);
73 const uint8_t *payload_end
= 0;
74 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
76 if (NULL
== payload
) {
77 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
82 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
85 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create dictionary"), NULL
, error
);
90 while (payload
!= NULL
&& payload
< payload_end
) {
92 CFTypeRef value
= NULL
;
94 payload
= der_decode_key_value(allocator
, &key
, &value
, error
, payload
, payload_end
);
97 CFDictionaryAddValue(dict
, key
, value
);
101 CFReleaseNull(value
);
106 if (payload
== payload_end
) {
116 struct size_context
{
122 static size_t der_sizeof_key_value(CFTypeRef key
, CFTypeRef value
, CFErrorRef
*error
) {
123 size_t key_size
= der_sizeof_plist(key
, error
);
125 SecCFDERCreateError(kSecDERErrorNullInput
, CFSTR("null input"), NULL
, error
);
128 size_t value_size
= der_sizeof_plist(value
, error
);
129 if (value_size
== 0) {
130 SecCFDERCreateError(kSecDERErrorNullInput
, CFSTR("null input"), NULL
, error
);
133 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, key_size
+ value_size
);
136 static void add_key_value_size(const void *key_void
, const void *value_void
, void *context_void
)
138 CFTypeRef key
= (CFTypeRef
) key_void
;
139 CFTypeRef value
= (CFTypeRef
) value_void
;
140 struct size_context
*context
= (struct size_context
*) context_void
;
142 if (!context
->success
)
145 size_t kv_size
= der_sizeof_key_value(key
, value
, context
->error
);
147 context
->success
= false;
151 context
->size
+= kv_size
;
154 size_t der_sizeof_dictionary(CFDictionaryRef dict
, CFErrorRef
*error
)
156 struct size_context context
= { .success
= true, .size
= 0, .error
= error
};
159 CFDictionaryApplyFunction(dict
, add_key_value_size
, &context
);
161 if (!context
.success
)
164 return ccder_sizeof(CCDER_CONSTRUCTED_SET
, context
.size
);
167 static uint8_t* der_encode_key_value(CFPropertyListRef key
, CFPropertyListRef value
, CFErrorRef
*error
,
168 const uint8_t* der
, uint8_t *der_end
)
170 return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
171 der_encode_plist(key
, error
, der
,
172 der_encode_plist(value
, error
, der
, der_end
))),
176 struct encode_context
{
179 CFMutableArrayRef list
;
180 CFAllocatorRef allocator
;
183 static void add_sequence_to_array(const void *key_void
, const void *value_void
, void *context_void
)
185 struct encode_context
*context
= (struct encode_context
*) context_void
;
186 if (context
->success
) {
187 CFTypeRef key
= (CFTypeRef
) key_void
;
188 CFTypeRef value
= (CFTypeRef
) value_void
;
190 size_t der_size
= der_sizeof_key_value(key
, value
, context
->error
);
192 context
-> success
= false;
194 CFMutableDataRef encoded_kv
= CFDataCreateMutable(context
->allocator
, der_size
);
195 CFDataSetLength(encoded_kv
, der_size
);
197 uint8_t* const encode_begin
= CFDataGetMutableBytePtr(encoded_kv
);
198 uint8_t* encode_end
= encode_begin
+ der_size
;
200 encode_end
= der_encode_key_value(key
, value
, context
->error
, encode_begin
, encode_end
);
202 if (encode_end
!= NULL
) {
203 CFDataDeleteBytes(encoded_kv
, CFRangeMake(0, (encode_end
- encode_begin
)));
204 CFArrayAppendValue(context
->list
, encoded_kv
);
206 context
-> success
= false;
209 CFReleaseNull(encoded_kv
);
214 static CFComparisonResult
cfdata_compare_der_contents(const void *val1
, const void *val2
, void *context __unused
)
216 return CFDataCompareDERData((CFDataRef
) val1
, (CFDataRef
) val2
);
220 uint8_t* der_encode_dictionary(CFDictionaryRef dictionary
, CFErrorRef
*error
,
221 const uint8_t *der
, uint8_t *der_end
)
223 CFMutableArrayRef elements
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
225 struct encode_context context
= { .success
= true, .error
= error
, .list
= elements
};
226 CFDictionaryApplyFunction(dictionary
, add_sequence_to_array
, &context
);
228 if (!context
.success
) {
229 CFReleaseNull(elements
);
233 CFRange allOfThem
= CFRangeMake(0, CFArrayGetCount(elements
));
235 CFArraySortValues(elements
, allOfThem
, cfdata_compare_der_contents
, NULL
);
237 uint8_t* original_der_end
= der_end
;
239 for(CFIndex position
= CFArrayGetCount(elements
); position
> 0;) {
241 CFDataRef data
= CFArrayGetValueAtIndex(elements
, position
);
242 der_end
= ccder_encode_body(CFDataGetLength(data
), CFDataGetBytePtr(data
), der
, der_end
);
245 CFReleaseNull(elements
);
247 return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET
, original_der_end
, der
, der_end
),