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