2 * Copyright (c) 2015 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@
28 #include "utilities/SecCFRelease.h"
29 #include "utilities/der_plist.h"
30 #include "utilities/der_plist_internal.h"
31 #include "utilities/SecCFWrappers.h"
33 #include <corecrypto/ccder.h>
34 #include <CoreFoundation/CoreFoundation.h>
36 const uint8_t* der_decode_set(CFAllocatorRef allocator
,
37 CFSetRef
* set
, CFErrorRef
*error
,
38 const uint8_t* der
, const uint8_t *der_end
)
41 SecCFDERCreateError(kSecDERErrorNullInput
, CFSTR("null input"), NULL
, error
);
45 const uint8_t *payload_end
= 0;
46 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, &payload_end
, der
, der_end
);
48 if (NULL
== payload
) {
49 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL
, error
);
53 CFMutableSetRef theSet
= (set
&& *set
) ? CFSetCreateMutableCopy(allocator
, 0, *set
)
54 : CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
57 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create set"), NULL
, error
);
62 while (payload
!= NULL
&& payload
< payload_end
) {
63 CFTypeRef value
= NULL
;
65 payload
= der_decode_plist(allocator
, &value
, error
, payload
, payload_end
);
68 CFSetAddValue(theSet
, value
);
75 if (payload
== payload_end
&& set
) {
76 CFTransferRetained(*set
, theSet
);
79 CFReleaseNull(theSet
);
90 static void add_value_size(const void *value_void
, void *context_void
)
92 CFTypeRef value
= (CFTypeRef
) value_void
;
93 struct size_context
*context
= (struct size_context
*) context_void
;
95 if (!context
->success
)
98 size_t kv_size
= der_sizeof_plist(value
, context
->error
);
100 context
->success
= false;
104 context
->size
+= kv_size
;
107 size_t der_sizeof_set(CFSetRef dict
, CFErrorRef
*error
)
109 struct size_context context
= { .success
= true, .size
= 0, .error
= error
};
111 CFSetApplyFunction(dict
, add_value_size
, &context
);
113 if (!context
.success
)
116 return ccder_sizeof(CCDER_CONSTRUCTED_CFSET
, context
.size
);
119 struct encode_context
{
122 CFMutableArrayRef list
;
123 CFAllocatorRef allocator
;
126 static void add_sequence_to_array(const void *value_void
, void *context_void
)
128 struct encode_context
*context
= (struct encode_context
*) context_void
;
129 if (context
->success
) {
130 size_t der_size
= der_sizeof_plist(value_void
, context
->error
);
132 context
-> success
= false;
134 CFMutableDataRef value
= CFDataCreateMutable(context
->allocator
, der_size
);
135 CFDataSetLength(value
, der_size
);
137 uint8_t* const encode_begin
= CFDataGetMutableBytePtr(value
);
138 uint8_t *encode_end
= encode_begin
+ der_size
;
140 encode_end
= der_encode_plist(value_void
, context
->error
, encode_begin
, encode_end
);
142 if (encode_end
!= NULL
) {
143 CFDataDeleteBytes(value
, CFRangeMake(0, (encode_end
- encode_begin
)));
144 CFArrayAppendValue(context
->list
, value
);
146 context
-> success
= false;
148 CFReleaseNull(value
);
153 static CFComparisonResult
cfdata_compare_der_contents(const void *val1
, const void *val2
, void *context __unused
)
155 return CFDataCompareDERData((CFDataRef
) val1
, (CFDataRef
) val2
);
159 uint8_t* der_encode_set(CFSetRef set
, CFErrorRef
*error
,
160 const uint8_t *der
, uint8_t *der_end
)
162 CFMutableArrayRef elements
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
164 struct encode_context context
= { .success
= true, .error
= error
, .list
= elements
};
165 CFSetApplyFunction(set
, add_sequence_to_array
, &context
);
167 if (!context
.success
) {
168 CFReleaseNull(elements
);
172 CFRange allOfThem
= CFRangeMake(0, CFArrayGetCount(elements
));
174 CFArraySortValues(elements
, allOfThem
, cfdata_compare_der_contents
, NULL
);
176 uint8_t* original_der_end
= der_end
;
178 for(CFIndex position
= CFArrayGetCount(elements
); position
> 0;) {
180 CFDataRef data
= CFArrayGetValueAtIndex(elements
, position
);
181 der_end
= ccder_encode_body(CFDataGetLength(data
), CFDataGetBytePtr(data
), der
, der_end
);
184 CFReleaseNull(elements
);
186 return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, original_der_end
, der
, der_end
),