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
, CFOptionFlags mutability
,
37 CFSetRef
* set
, CFErrorRef
*error
,
38 const uint8_t* der
, const uint8_t *der_end
)
43 const uint8_t *payload_end
= 0;
44 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, &payload_end
, der
, der_end
);
46 if (NULL
== payload
) {
47 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL
, error
);
51 CFMutableSetRef theSet
= (set
&& *set
) ? CFSetCreateMutableCopy(allocator
, 0, *set
)
52 : CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
55 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create set"), NULL
, error
);
60 while (payload
!= NULL
&& payload
< payload_end
) {
61 CFTypeRef value
= NULL
;
63 payload
= der_decode_plist(allocator
, mutability
, &value
, error
, payload
, payload_end
);
66 CFSetAddValue(theSet
, value
);
73 if (payload
== payload_end
&& set
) {
74 CFTransferRetained(*set
, theSet
);
77 CFReleaseNull(theSet
);
88 static void add_value_size(const void *value_void
, void *context_void
)
90 CFTypeRef value
= (CFTypeRef
) value_void
;
91 struct size_context
*context
= (struct size_context
*) context_void
;
93 if (!context
->success
)
96 size_t kv_size
= der_sizeof_plist(value
, context
->error
);
98 context
->success
= false;
102 context
->size
+= kv_size
;
105 size_t der_sizeof_set(CFSetRef dict
, CFErrorRef
*error
)
107 struct size_context context
= { .success
= true, .size
= 0, .error
= error
};
109 CFSetApplyFunction(dict
, add_value_size
, &context
);
111 if (!context
.success
)
114 return ccder_sizeof(CCDER_CONSTRUCTED_CFSET
, context
.size
);
117 struct encode_context
{
120 CFMutableArrayRef list
;
121 CFAllocatorRef allocator
;
124 static void add_sequence_to_array(const void *value_void
, void *context_void
)
126 struct encode_context
*context
= (struct encode_context
*) context_void
;
127 if (context
->success
) {
128 size_t der_size
= der_sizeof_plist(value_void
, context
->error
);
130 context
-> success
= false;
132 CFMutableDataRef value
= CFDataCreateMutable(context
->allocator
, der_size
);
133 CFDataSetLength(value
, der_size
);
135 uint8_t* const encode_begin
= CFDataGetMutableBytePtr(value
);
136 uint8_t *encode_end
= encode_begin
+ der_size
;
138 encode_end
= der_encode_plist(value_void
, context
->error
, encode_begin
, encode_end
);
140 if (encode_end
!= NULL
) {
141 CFDataDeleteBytes(value
, CFRangeMake(0, (encode_end
- encode_begin
)));
142 CFArrayAppendValue(context
->list
, value
);
144 context
-> success
= false;
146 CFReleaseNull(value
);
151 static CFComparisonResult
cfdata_compare_contents(const void *val1
, const void *val2
, void *context __unused
)
153 return CFDataCompare((CFDataRef
) val1
, (CFDataRef
) val2
);
157 uint8_t* der_encode_set(CFSetRef set
, CFErrorRef
*error
,
158 const uint8_t *der
, uint8_t *der_end
)
160 CFMutableArrayRef elements
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
162 struct encode_context context
= { .success
= true, .error
= error
, .list
= elements
};
163 CFSetApplyFunction(set
, add_sequence_to_array
, &context
);
165 if (!context
.success
) {
166 CFReleaseNull(elements
);
170 CFRange allOfThem
= CFRangeMake(0, CFArrayGetCount(elements
));
172 CFArraySortValues(elements
, allOfThem
, cfdata_compare_contents
, NULL
);
174 uint8_t* original_der_end
= der_end
;
176 for(CFIndex position
= CFArrayGetCount(elements
); position
> 0;) {
178 CFDataRef data
= CFArrayGetValueAtIndex(elements
, position
);
179 der_end
= ccder_encode_body(CFDataGetLength(data
), CFDataGetBytePtr(data
), der
, der_end
);
182 CFReleaseNull(elements
);
184 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, original_der_end
, der
, der_end
);