refactored openac and its attribute certificate factory
[strongswan.git] / src / libstrongswan / plugins / x509 / ietf_attr_list.c
1 /**
2 * @file ietf_attr.c
3 *
4 * @brief Implementation of ietfAttr_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Andreas Steffen, Hochschule fuer Technik Rapperswil
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 */
21
22 #include <string.h>
23 #include <stdio.h>
24
25 #include <debug.h>
26 #include <asn1/asn1.h>
27 #include <utils/lexparser.h>
28
29 #include "ietf_attr_list.h"
30
31 /**
32 * Private definition of ietfAttribute kinds
33 */
34 typedef enum {
35 IETF_ATTRIBUTE_OCTETS = 0,
36 IETF_ATTRIBUTE_OID = 1,
37 IETF_ATTRIBUTE_STRING = 2
38 } ietfAttribute_t;
39
40 typedef struct ietfAttr_t ietfAttr_t;
41
42 /**
43 * Private definition of an ietfAttribute
44 */
45 struct ietfAttr_t {
46 /**
47 * IETF attribute kind
48 */
49 ietfAttribute_t kind;
50
51 /**
52 * IETF attribute valuse
53 */
54 chunk_t value;
55
56 /**
57 * Compares two ietfAttributes
58 *
59 * return -1 if this is earlier in the alphabet than other
60 * return 0 if this equals other
61 * return +1 if this is later in the alphabet than other
62 *
63 * @param this calling object
64 * @param other other object
65 */
66 int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other);
67
68 /**
69 * Destroys the ietfAttr_t object.
70 *
71 * @param this ietfAttr_t to destroy
72 */
73 void (*destroy) (ietfAttr_t *this);
74 };
75
76 /**
77 * Implements ietfAttr_t.compare.
78 */
79 static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other)
80 {
81 int cmp_len, len, cmp_value;
82
83 /* OID attributes are appended after STRING and OCTETS attributes */
84 if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID)
85 {
86 return -1;
87 }
88 if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID)
89 {
90 return 1;
91 }
92
93 cmp_len = this->value.len - other->value.len;
94 len = (cmp_len < 0)? this->value.len : other->value.len;
95 cmp_value = memcmp(this->value.ptr, other->value.ptr, len);
96
97 return (cmp_value == 0)? cmp_len : cmp_value;
98 }
99
100 /**
101 * Implements ietfAttr_t.destroy.
102 */
103 static void ietfAttr_destroy(ietfAttr_t *this)
104 {
105 free(this->value.ptr);
106 free(this);
107 }
108
109 /**
110 * Creates an ietfAttr_t object.
111 */
112 static ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value)
113 {
114 ietfAttr_t *this = malloc_thing(ietfAttr_t);
115
116 /* initialize */
117 this->kind = kind;
118 this->value = chunk_clone(value);
119
120 /* function */
121 this->compare = ietfAttr_compare;
122 this->destroy = ietfAttr_destroy;
123
124 return this;
125 }
126
127 /**
128 * Adds an ietfAttr_t object to a sorted linked list
129 */
130 static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr)
131 {
132 iterator_t *iterator = list->create_iterator(list, TRUE);
133 ietfAttr_t *current_attr;
134 bool found = FALSE;
135
136 while (iterator->iterate(iterator, (void **)&current_attr))
137 {
138 int cmp = attr->compare(attr, current_attr);
139
140 if (cmp > 0)
141 {
142 continue;
143 }
144 if (cmp == 0)
145 {
146 attr->destroy(attr);
147 }
148 else
149 {
150 iterator->insert_before(iterator, attr);
151 }
152 found = TRUE;
153 break;
154 }
155 iterator->destroy(iterator);
156 if (!found)
157 {
158 list->insert_last(list, attr);
159 }
160 }
161
162 /*
163 * Described in header.
164 */
165 bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b)
166 {
167 bool result = TRUE;
168
169 /* lists must have the same number of attributes */
170 if (list_a->get_count(list_a) != list_b->get_count(list_b))
171 {
172 return FALSE;
173 }
174 /* empty lists - no attributes */
175 if (list_a->get_count(list_a) == 0)
176 {
177 return TRUE;
178 }
179
180 /* compare two alphabetically-sorted lists */
181 {
182 iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE);
183 iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE);
184 ietfAttr_t *attr_a, *attr_b;
185
186 while (iterator_a->iterate(iterator_a, (void **)&attr_a) &&
187 iterator_b->iterate(iterator_b, (void **)&attr_b))
188 {
189 if (attr_a->compare(attr_a, attr_b) != 0)
190 {
191 /* we have a mismatch */
192 result = FALSE;
193 break;
194 }
195 }
196 iterator_a->destroy(iterator_a);
197 iterator_b->destroy(iterator_b);
198 }
199 return result;
200 }
201
202 /*
203 * Described in header.
204 */
205 void ietfAttr_list_list(linked_list_t *list, FILE *out)
206 {
207 iterator_t *iterator = list->create_iterator(list, TRUE);
208 ietfAttr_t *attr;
209 bool first = TRUE;
210
211 while (iterator->iterate(iterator, (void **)&attr))
212 {
213 if (first)
214 {
215 first = FALSE;
216 }
217 else
218 {
219 fprintf(out, ", ");
220 }
221
222 switch (attr->kind)
223 {
224 case IETF_ATTRIBUTE_OCTETS:
225 case IETF_ATTRIBUTE_STRING:
226 fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr);
227 break;
228 case IETF_ATTRIBUTE_OID:
229 {
230 int oid = known_oid(attr->value);
231
232 if (oid == OID_UNKNOWN)
233 {
234 fprintf(out, "0x#B", &attr->value);
235 }
236 else
237 {
238 fprintf(out, "%s", oid_names[oid]);
239 }
240 }
241 break;
242 default:
243 break;
244 }
245 }
246 iterator->destroy(iterator);
247 }
248
249 /*
250 * Described in header.
251 */
252 void ietfAttr_list_create_from_string(char *msg, linked_list_t *list)
253 {
254 chunk_t line = { msg, strlen(msg) };
255
256 while (eat_whitespace(&line))
257 {
258 chunk_t group;
259
260 /* extract the next comma-separated group attribute */
261 if (!extract_token(&group, ',', &line))
262 {
263 group = line;
264 line.len = 0;
265 }
266
267 /* remove any trailing spaces */
268 while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
269 {
270 group.len--;
271 }
272
273 /* add the group attribute to the list */
274 if (group.len > 0)
275 {
276 ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group);
277
278 ietfAttr_add(list, attr);
279 }
280 }
281 }
282
283 /**
284 * ASN.1 definition of ietfAttrSyntax
285 */
286 static const asn1Object_t ietfAttrSyntaxObjects[] =
287 {
288 { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
289 { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
290 ASN1_BODY }, /* 1 */
291 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
292 { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
293 { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
294 ASN1_BODY }, /* 4 */
295 { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
296 { 2, "oid", ASN1_OID, ASN1_OPT |
297 ASN1_BODY }, /* 6 */
298 { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
299 { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
300 ASN1_BODY }, /* 8 */
301 { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
302 { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
303 };
304
305 #define IETF_ATTR_OCTETS 4
306 #define IETF_ATTR_OID 6
307 #define IETF_ATTR_STRING 8
308 #define IETF_ATTR_ROOF 11
309
310 /*
311 * Described in header.
312 */
313 void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0)
314 {
315 asn1_ctx_t ctx;
316 chunk_t object;
317 u_int level;
318 int objectID = 0;
319
320 asn1_init(&ctx, chunk, level0, FALSE, FALSE);
321
322 while (objectID < IETF_ATTR_ROOF)
323 {
324 if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
325 {
326 return;
327 }
328
329 switch (objectID)
330 {
331 case IETF_ATTR_OCTETS:
332 case IETF_ATTR_OID:
333 case IETF_ATTR_STRING:
334 {
335 ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2;
336 ietfAttr_t *attr = ietfAttr_create(kind, object);
337 ietfAttr_add(list, attr);
338 }
339 break;
340 default:
341 break;
342 }
343 objectID++;
344 }
345 }
346
347 /*
348 * Described in header.
349 */
350 chunk_t ietfAttr_list_encode(linked_list_t *list)
351 {
352 chunk_t ietfAttributes;
353 size_t size = 0;
354 u_char *pos;
355 iterator_t *iterator = list->create_iterator(list, TRUE);
356 ietfAttr_t *attr;
357
358 /* precalculate the total size of all values */
359 while (iterator->iterate(iterator, (void **)&attr))
360 {
361 size_t len = attr->value.len;
362
363 size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
364 }
365 iterator->destroy(iterator);
366
367 pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
368
369 iterator = list->create_iterator(list, TRUE);
370 while (iterator->iterate(iterator, (void **)&attr))
371 {
372 chunk_t ietfAttribute;
373 asn1_t type = ASN1_NULL;
374
375 switch (attr->kind)
376 {
377 case IETF_ATTRIBUTE_OCTETS:
378 type = ASN1_OCTET_STRING;
379 break;
380 case IETF_ATTRIBUTE_STRING:
381 type = ASN1_UTF8STRING;
382 break;
383 case IETF_ATTRIBUTE_OID:
384 type = ASN1_OID;
385 break;
386 }
387 ietfAttribute = asn1_simple_object(type, attr->value);
388
389 /* copy ietfAttribute into ietfAttributes chunk */
390 memcpy(pos, ietfAttribute.ptr, ietfAttribute.len);
391 pos += ietfAttribute.len;
392 free(ietfAttribute.ptr);
393 }
394 iterator->destroy(iterator);
395
396 return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
397 }
398
399 /*
400 * Described in header.
401 */
402 void ietfAttr_list_destroy(linked_list_t *list)
403 {
404 list->destroy_offset(list, offsetof(ietfAttr_t, destroy));
405 }