]> git.saurik.com Git - apple/security.git/blob - utilities/src/der_dictionary.c
Security-55471.14.tar.gz
[apple/security.git] / utilities / src / der_dictionary.c
1 //
2 // der_dictionary.c
3 // utilities
4 //
5 // Created by Mitch Adler on 6/18/12.
6 // Copyright (c) 2012 Apple Inc. All rights reserved.
7 //
8
9 #include <stdio.h>
10
11 #include "utilities/SecCFRelease.h"
12 #include "utilities/der_plist.h"
13 #include "utilities/der_plist_internal.h"
14 #include "utilities/SecCFWrappers.h"
15
16 #include <corecrypto/ccder.h>
17 #include <CoreFoundation/CoreFoundation.h>
18
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)
22 {
23 const uint8_t *payload_end = 0;
24 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end);
25
26 if (NULL == payload) {
27 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error);
28 return NULL;
29 }
30
31 CFTypeRef keyObject = NULL;
32 CFTypeRef valueObject = NULL;
33
34
35 payload = der_decode_plist(allocator, mutability, &keyObject, error, payload, payload_end);
36 payload = der_decode_plist(allocator, mutability, &valueObject, error, payload, payload_end);
37
38 if (payload != NULL) {
39 *key = keyObject;
40 *value = valueObject;
41 } else {
42 CFReleaseNull(keyObject);
43 CFReleaseNull(valueObject);
44 }
45 return payload;
46 }
47
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)
51 {
52 if (NULL == der)
53 return NULL;
54
55 const uint8_t *payload_end = 0;
56 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end);
57
58 if (NULL == payload) {
59 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error);
60 return NULL;
61 }
62
63
64 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
65
66 if (NULL == dict) {
67 SecCFDERCreateError(kSecDERErrorUnderlyingError, CFSTR("Failed to create data"), NULL, error);
68 payload = NULL;
69 goto exit;
70 }
71
72 while (payload != NULL && payload < payload_end) {
73 CFTypeRef key = NULL;
74 CFTypeRef value = NULL;
75
76 payload = der_decode_key_value(allocator, mutability, &key, &value, error, payload, payload_end);
77
78 if (payload) {
79 CFDictionaryAddValue(dict, key, value);
80 CFReleaseNull(key);
81 CFReleaseNull(value);
82 }
83 }
84
85
86 exit:
87 if (payload == payload_end) {
88 *dictionary = dict;
89 dict = NULL;
90 }
91
92 CFReleaseNull(dict);
93
94 return payload;
95 }
96
97 struct size_context {
98 bool success;
99 size_t size;
100 CFErrorRef *error;
101 };
102
103 static size_t der_sizeof_key_value(CFTypeRef key, CFTypeRef value, CFErrorRef *error) {
104 size_t key_size = der_sizeof_plist(key, error);
105 if (key_size == 0) {
106 return 0;
107 }
108 size_t value_size = der_sizeof_plist(value, error);
109 if (value_size == 0) {
110 return 0;
111 }
112 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, key_size + value_size);
113 }
114
115 static void add_key_value_size(const void *key_void, const void *value_void, void *context_void)
116 {
117 CFTypeRef key = (CFTypeRef) key_void;
118 CFTypeRef value = (CFTypeRef) value_void;
119 struct size_context *context = (struct size_context*) context_void;
120
121 if (!context->success)
122 return;
123
124 size_t kv_size = der_sizeof_key_value(key, value, context->error);
125 if (kv_size == 0) {
126 context->success = false;
127 return;
128 }
129
130 context->size += kv_size;
131 }
132
133 size_t der_sizeof_dictionary(CFDictionaryRef dict, CFErrorRef *error)
134 {
135 struct size_context context = { .success = true, .size = 0, .error = error };
136
137
138 CFDictionaryApplyFunction(dict, add_key_value_size, &context);
139
140 if (!context.success)
141 return 0;
142
143 return ccder_sizeof(CCDER_CONSTRUCTED_SET, context.size);
144 }
145
146 static uint8_t* der_encode_key_value(CFPropertyListRef key, CFPropertyListRef value, CFErrorRef *error,
147 const uint8_t* der, uint8_t *der_end)
148 {
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)));
152 }
153
154 struct encode_context {
155 bool success;
156 CFErrorRef * error;
157 CFMutableArrayRef list;
158 CFAllocatorRef allocator;
159 };
160
161 static void add_sequence_to_array(const void *key_void, const void *value_void, void *context_void)
162 {
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;
167
168 size_t der_size = der_sizeof_key_value(key, value, context->error);
169 if (der_size == 0) {
170 context-> success = false;
171 } else {
172 CFMutableDataRef encoded_kv = CFDataCreateMutable(context->allocator, der_size);
173 CFDataSetLength(encoded_kv, der_size);
174
175 uint8_t* const encode_begin = CFDataGetMutableBytePtr(encoded_kv);
176 uint8_t* encode_end = encode_begin + der_size;
177
178 encode_end = der_encode_key_value(key, value, context->error, encode_begin, encode_end);
179
180 if (encode_end != NULL) {
181 CFDataDeleteBytes(encoded_kv, CFRangeMake(0, (encode_end - encode_begin)));
182 CFArrayAppendValue(context->list, encoded_kv);
183 } else {
184 context-> success = false;
185 }
186
187 CFReleaseNull(encoded_kv);
188 }
189 }
190 }
191
192 static CFComparisonResult cfdata_compare_contents(const void *val1, const void *val2, void *context __unused)
193 {
194 return CFDataCompare((CFDataRef) val1, (CFDataRef) val2);
195 }
196
197
198 uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error,
199 const uint8_t *der, uint8_t *der_end)
200 {
201 CFMutableArrayRef elements = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
202
203 struct encode_context context = { .success = true, .error = error, .list = elements };
204 CFDictionaryApplyFunction(dictionary, add_sequence_to_array, &context);
205
206 if (!context.success) {
207 CFReleaseNull(elements);
208 return NULL;
209 }
210
211 CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements));
212
213 CFArraySortValues(elements, allOfThem, cfdata_compare_contents, NULL);
214
215 uint8_t* original_der_end = der_end;
216
217 for(CFIndex position = CFArrayGetCount(elements); position > 0;) {
218 --position;
219 CFDataRef data = CFArrayGetValueAtIndex(elements, position);
220 der_end = ccder_encode_body(CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end);
221 }
222
223 CFReleaseNull(elements);
224
225 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET, original_der_end, der, der_end);
226
227 }