NULL string argument is treated as %any
[strongswan.git] / src / libstrongswan / utils / identification.c
1 /**
2 * @file identification.c
3 *
4 * @brief Implementation of identification_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #define _GNU_SOURCE
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <ctype.h>
30
31 #include "definitions.h"
32 #include "identification.h"
33
34 #include <asn1/asn1.h>
35
36 /**
37 * String mappings for id_type_t.
38 */
39 mapping_t id_type_m[] = {
40 {ID_IPV4_ADDR, "ID_IPV4_ADDR"},
41 {ID_FQDN, "ID_FQDN"},
42 {ID_RFC822_ADDR, "ID_RFC822_ADDR"},
43 {ID_IPV6_ADDR, "ID_IPV6_ADDR"},
44 {ID_DER_ASN1_DN, "ID_DER_ASN1_DN"},
45 {ID_DER_ASN1_GN, "ID_DER_ASN1_GN"},
46 {ID_KEY_ID, "ID_KEY_ID"},
47 {ID_ANY, "ID_ANY"},
48 {MAPPING_END, NULL}
49 };
50
51 /**
52 * X.501 acronyms for well known object identifiers (OIDs)
53 */
54 static u_char oid_ND[] = {
55 0x02, 0x82, 0x06, 0x01, 0x0A, 0x07, 0x14
56 };
57 static u_char oid_UID[] = {
58 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01
59 };
60 static u_char oid_DC[] = {
61 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19
62 };
63 static u_char oid_CN[] = {
64 0x55, 0x04, 0x03
65 };
66 static u_char oid_S[] = {
67 0x55, 0x04, 0x04
68 };
69 static u_char oid_SN[] = {
70 0x55, 0x04, 0x05
71 };
72 static u_char oid_C[] = {
73 0x55, 0x04, 0x06
74 };
75 static u_char oid_L[] = {
76 0x55, 0x04, 0x07
77 };
78 static u_char oid_ST[] = {
79 0x55, 0x04, 0x08
80 };
81 static u_char oid_O[] = {
82 0x55, 0x04, 0x0A
83 };
84 static u_char oid_OU[] = {
85 0x55, 0x04, 0x0B
86 };
87 static u_char oid_T[] = {
88 0x55, 0x04, 0x0C
89 };
90 static u_char oid_D[] = {
91 0x55, 0x04, 0x0D
92 };
93 static u_char oid_N[] = {
94 0x55, 0x04, 0x29
95 };
96 static u_char oid_G[] = {
97 0x55, 0x04, 0x2A
98 };
99 static u_char oid_I[] = {
100 0x55, 0x04, 0x2B
101 };
102 static u_char oid_ID[] = {
103 0x55, 0x04, 0x2D
104 };
105 static u_char oid_EN[] = {
106 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x42, 0x03, 0x01, 0x03
107 };
108 static u_char oid_E[] = {
109 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01
110 };
111 static u_char oid_UN[] = {
112 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x02
113 };
114 static u_char oid_TCGID[] = {
115 0x2B, 0x06, 0x01, 0x04, 0x01, 0x89, 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B
116 };
117
118 /**
119 * coding of X.501 distinguished name
120 */
121 typedef struct {
122 const u_char *name;
123 chunk_t oid;
124 u_char type;
125 } x501rdn_t;
126
127 static const x501rdn_t x501rdns[] = {
128 {"ND", {oid_ND, 7}, ASN1_PRINTABLESTRING},
129 {"UID", {oid_UID, 10}, ASN1_PRINTABLESTRING},
130 {"DC", {oid_DC, 10}, ASN1_PRINTABLESTRING},
131 {"CN", {oid_CN, 3}, ASN1_PRINTABLESTRING},
132 {"S", {oid_S, 3}, ASN1_PRINTABLESTRING},
133 {"SN", {oid_SN, 3}, ASN1_PRINTABLESTRING},
134 {"serialNumber", {oid_SN, 3}, ASN1_PRINTABLESTRING},
135 {"C", {oid_C, 3}, ASN1_PRINTABLESTRING},
136 {"L", {oid_L, 3}, ASN1_PRINTABLESTRING},
137 {"ST", {oid_ST, 3}, ASN1_PRINTABLESTRING},
138 {"O", {oid_O, 3}, ASN1_PRINTABLESTRING},
139 {"OU", {oid_OU, 3}, ASN1_PRINTABLESTRING},
140 {"T", {oid_T, 3}, ASN1_PRINTABLESTRING},
141 {"D", {oid_D, 3}, ASN1_PRINTABLESTRING},
142 {"N", {oid_N, 3}, ASN1_PRINTABLESTRING},
143 {"G", {oid_G, 3}, ASN1_PRINTABLESTRING},
144 {"I", {oid_I, 3}, ASN1_PRINTABLESTRING},
145 {"ID", {oid_ID, 3}, ASN1_PRINTABLESTRING},
146 {"EN", {oid_EN, 10}, ASN1_PRINTABLESTRING},
147 {"employeeNumber", {oid_EN, 10}, ASN1_PRINTABLESTRING},
148 {"E", {oid_E, 9}, ASN1_IA5STRING},
149 {"Email", {oid_E, 9}, ASN1_IA5STRING},
150 {"emailAddress", {oid_E, 9}, ASN1_IA5STRING},
151 {"UN", {oid_UN, 9}, ASN1_IA5STRING},
152 {"unstructuredName",{oid_UN, 9}, ASN1_IA5STRING},
153 {"TCGID", {oid_TCGID, 12}, ASN1_PRINTABLESTRING}
154 };
155 #define X501_RDN_ROOF 26
156
157 /**
158 * maximum number of RDNs in atodn()
159 */
160 #define RDN_MAX 20
161
162
163 typedef struct private_identification_t private_identification_t;
164
165 /**
166 * Private data of an identification_t object.
167 */
168 struct private_identification_t {
169 /**
170 * Public interface.
171 */
172 identification_t public;
173
174 /**
175 * String representation of this ID.
176 */
177 char *string;
178
179 /**
180 * Encoded representation of this ID.
181 */
182 chunk_t encoded;
183
184 /**
185 * Type of this ID.
186 */
187 id_type_t type;
188 };
189
190 static private_identification_t *identification_create(void);
191
192 /**
193 * updates a chunk (!????)
194 * TODO: We should reconsider this stuff, its not really clear
195 */
196 static void update_chunk(chunk_t *ch, int n)
197 {
198 n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1;
199 ch->ptr += n; ch->len -= n;
200 }
201
202 /**
203 * Prints a binary string in hexadecimal form
204 */
205 void hex_str(chunk_t bin, chunk_t *str)
206 {
207 u_int i;
208 update_chunk(str, snprintf(str->ptr,str->len,"0x"));
209 for (i = 0; i < bin.len; i++)
210 {
211 update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
212 }
213 }
214
215 /**
216 * Pointer is set to the first RDN in a DN
217 */
218 static status_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next)
219 {
220 *rdn = CHUNK_INITIALIZER;
221 *attribute = CHUNK_INITIALIZER;
222
223 /* a DN is a SEQUENCE OF RDNs */
224 if (*dn.ptr != ASN1_SEQUENCE)
225 {
226 /* DN is not a SEQUENCE */
227 return FAILED;
228 }
229
230 rdn->len = asn1_length(&dn);
231
232 if (rdn->len == ASN1_INVALID_LENGTH)
233 {
234 /* Invalid RDN length */
235 return FAILED;
236 }
237
238 rdn->ptr = dn.ptr;
239
240 /* are there any RDNs ? */
241 *next = rdn->len > 0;
242
243 return SUCCESS;
244 }
245
246 /**
247 * Fetches the next RDN in a DN
248 */
249 static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value, asn1_t *type, bool *next)
250 {
251 chunk_t body;
252
253 /* initialize return values */
254 *oid = CHUNK_INITIALIZER;
255 *value = CHUNK_INITIALIZER;
256
257 /* if all attributes have been parsed, get next rdn */
258 if (attribute->len <= 0)
259 {
260 /* an RDN is a SET OF attributeTypeAndValue */
261 if (*rdn->ptr != ASN1_SET)
262 {
263 /* RDN is not a SET */
264 return FAILED;
265 }
266 attribute->len = asn1_length(rdn);
267 if (attribute->len == ASN1_INVALID_LENGTH)
268 {
269 /* Invalid attribute length */
270 return FAILED;
271 }
272 attribute->ptr = rdn->ptr;
273 /* advance to start of next RDN */
274 rdn->ptr += attribute->len;
275 rdn->len -= attribute->len;
276 }
277
278 /* an attributeTypeAndValue is a SEQUENCE */
279 if (*attribute->ptr != ASN1_SEQUENCE)
280 {
281 /* attributeTypeAndValue is not a SEQUENCE */
282 return FAILED;
283 }
284
285 /* extract the attribute body */
286 body.len = asn1_length(attribute);
287
288 if (body.len == ASN1_INVALID_LENGTH)
289 {
290 /* Invalid attribute body length */
291 return FAILED;
292 }
293
294 body.ptr = attribute->ptr;
295
296 /* advance to start of next attribute */
297 attribute->ptr += body.len;
298 attribute->len -= body.len;
299
300 /* attribute type is an OID */
301 if (*body.ptr != ASN1_OID)
302 {
303 /* attributeType is not an OID */
304 return FAILED;
305 }
306 /* extract OID */
307 oid->len = asn1_length(&body);
308
309 if (oid->len == ASN1_INVALID_LENGTH)
310 {
311 /* Invalid attribute OID length */
312 return FAILED;
313 }
314 oid->ptr = body.ptr;
315
316 /* advance to the attribute value */
317 body.ptr += oid->len;
318 body.len -= oid->len;
319
320 /* extract string type */
321 *type = *body.ptr;
322
323 /* extract string value */
324 value->len = asn1_length(&body);
325
326 if (value->len == ASN1_INVALID_LENGTH)
327 {
328 /* Invalid attribute string length */
329 return FAILED;
330 }
331 value->ptr = body.ptr;
332
333 /* are there any RDNs left? */
334 *next = rdn->len > 0 || attribute->len > 0;
335 return SUCCESS;
336 }
337
338 /**
339 * Parses an ASN.1 distinguished name int its OID/value pairs
340 */
341 static status_t dntoa(chunk_t dn, chunk_t *str)
342 {
343 chunk_t rdn, oid, attribute, value;
344 asn1_t type;
345 int oid_code;
346 bool next;
347 bool first = TRUE;
348
349 status_t status = init_rdn(dn, &rdn, &attribute, &next);
350
351 if (status != SUCCESS)
352 return status;
353
354 while (next)
355 {
356 status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
357
358 if (status != SUCCESS)
359 return status;
360
361 if (first)
362 { /* first OID/value pair */
363 first = FALSE;
364 }
365 else
366 { /* separate OID/value pair by a comma */
367 update_chunk(str, snprintf(str->ptr,str->len,", "));
368 }
369
370 /* print OID */
371 oid_code = known_oid(oid);
372 if (oid_code == OID_UNKNOWN)
373 { /* OID not found in list */
374 hex_str(oid, str);
375 }
376 else
377 {
378 update_chunk(str, snprintf(str->ptr,str->len,"%s", oid_names[oid_code].name));
379 }
380 /* print value */
381 update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", (int)value.len,value.ptr));
382 }
383 return SUCCESS;
384 }
385
386 /**
387 * compare two distinguished names by
388 * comparing the individual RDNs
389 */
390 static bool same_dn(chunk_t a, chunk_t b)
391 {
392 chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
393 chunk_t oid_a, oid_b, value_a, value_b;
394 asn1_t type_a, type_b;
395 bool next_a, next_b;
396
397 /* same lengths for the DNs */
398 if (a.len != b.len)
399 return FALSE;
400
401 /* try a binary comparison first */
402 if (memeq(a.ptr, b.ptr, b.len))
403 return TRUE;
404
405 /* initialize DN parsing */
406 if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
407 || init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
408 {
409 return FALSE;
410 }
411
412 /* fetch next RDN pair */
413 while (next_a && next_b)
414 {
415 /* parse next RDNs and check for errors */
416 if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS
417 || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
418 {
419 return FALSE;
420 }
421
422 /* OIDs must agree */
423 if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
424 return FALSE;
425
426 /* same lengths for values */
427 if (value_a.len != value_b.len)
428 return FALSE;
429
430 /* printableStrings and email RDNs require uppercase comparison */
431 if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING
432 || (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
433 {
434 if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
435 return FALSE;
436 }
437 else
438 {
439 if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
440 return FALSE;
441 }
442 }
443 /* both DNs must have same number of RDNs */
444 if (next_a || next_b)
445 return FALSE;
446
447 /* the two DNs are equal! */
448 return TRUE;
449 }
450
451
452 /**
453 * compare two distinguished names by comparing the individual RDNs.
454 * A single'*' character designates a wildcard RDN in DN b.
455 * TODO: Add support for different RDN order in DN !!
456 */
457 bool match_dn(chunk_t a, chunk_t b, int *wildcards)
458 {
459 chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
460 chunk_t oid_a, oid_b, value_a, value_b;
461 asn1_t type_a, type_b;
462 bool next_a, next_b;
463
464 /* initialize wildcard counter */
465 *wildcards = 0;
466
467 /* initialize DN parsing */
468 if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
469 || init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
470 {
471 return FALSE;
472 }
473
474 /* fetch next RDN pair */
475 while (next_a && next_b)
476 {
477 /* parse next RDNs and check for errors */
478 if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS
479 || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
480 {
481 return FALSE;
482 }
483 /* OIDs must agree */
484 if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
485 return FALSE;
486
487 /* does rdn_b contain a wildcard? */
488 if (value_b.len == 1 && *value_b.ptr == '*')
489 {
490 (*wildcards)++;
491 continue;
492 }
493 /* same lengths for values */
494 if (value_a.len != value_b.len)
495 return FALSE;
496
497 /* printableStrings and email RDNs require uppercase comparison */
498 if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING
499 || (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
500 {
501 if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
502 return FALSE;
503 }
504 else
505 {
506 if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
507 return FALSE;
508 }
509 }
510 /* both DNs must have same number of RDNs */
511 if (next_a || next_b)
512 {
513 return FALSE;
514 }
515 /* the two DNs match! */
516 return TRUE;
517 }
518
519 /**
520 * Converts an LDAP-style human-readable ASCII-encoded
521 * ASN.1 distinguished name into binary DER-encoded format
522 */
523 static status_t atodn(char *src, chunk_t *dn)
524 {
525 /* finite state machine for atodn */
526 typedef enum {
527 SEARCH_OID = 0,
528 READ_OID = 1,
529 SEARCH_NAME = 2,
530 READ_NAME = 3,
531 UNKNOWN_OID = 4
532 } state_t;
533
534 chunk_t oid = CHUNK_INITIALIZER;
535 chunk_t name = CHUNK_INITIALIZER;
536 chunk_t rdns[RDN_MAX];
537 int rdn_count = 0;
538 int dn_len = 0;
539 int whitespace = 0;
540 int i;
541 asn1_t rdn_type;
542 state_t state = SEARCH_OID;
543 status_t status = SUCCESS;
544
545 do
546 {
547 switch (state)
548 {
549 case SEARCH_OID:
550 if (*src != ' ' && *src != '/' && *src != ',')
551 {
552 oid.ptr = src;
553 oid.len = 1;
554 state = READ_OID;
555 }
556 break;
557 case READ_OID:
558 if (*src != ' ' && *src != '=')
559 {
560 oid.len++;
561 }
562 else
563 {
564 for (i = 0; i < X501_RDN_ROOF; i++)
565 {
566 if (strlen(x501rdns[i].name) == oid.len
567 && strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0)
568 {
569 break; /* found a valid OID */
570 }
571 }
572 if (i == X501_RDN_ROOF)
573 {
574 status = NOT_SUPPORTED;
575 state = UNKNOWN_OID;
576 break;
577 }
578 /* reset oid and change state */
579 oid = CHUNK_INITIALIZER;
580 state = SEARCH_NAME;
581 }
582 break;
583 case SEARCH_NAME:
584 if (*src != ' ' && *src != '=')
585 {
586 name.ptr = src;
587 name.len = 1;
588 whitespace = 0;
589 state = READ_NAME;
590 }
591 break;
592 case READ_NAME:
593 if (*src != ',' && *src != '/' && *src != '\0')
594 {
595 name.len++;
596 if (*src == ' ')
597 whitespace++;
598 else
599 whitespace = 0;
600 }
601 else
602 {
603 name.len -= whitespace;
604 rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING
605 && !is_printablestring(name))? ASN1_T61STRING : x501rdns[i].type;
606
607 if (rdn_count < RDN_MAX)
608 {
609 rdns[rdn_count] =
610 asn1_wrap(ASN1_SET, "m",
611 asn1_wrap(ASN1_SEQUENCE, "mm",
612 asn1_wrap(ASN1_OID, "c", x501rdns[i].oid),
613 asn1_wrap(rdn_type, "c", name)
614 )
615 );
616 dn_len += rdns[rdn_count++].len;
617 }
618 else
619 {
620 status = OUT_OF_RES;
621 }
622 /* reset name and change state */
623 name = CHUNK_INITIALIZER;
624 state = SEARCH_OID;
625 }
626 break;
627 case UNKNOWN_OID:
628 break;
629 }
630 } while (*src++ != '\0');
631
632 /* build the distinguished name sequence */
633 {
634 int i;
635 u_char *pos = build_asn1_object(dn, ASN1_SEQUENCE, dn_len);
636
637 for (i = 0; i < rdn_count; i++)
638 {
639 memcpy(pos, rdns[i].ptr, rdns[i].len);
640 pos += rdns[i].len;
641 free(rdns[i].ptr);
642 }
643 }
644
645 if (status != SUCCESS)
646 {
647 free(dn->ptr);
648 *dn = CHUNK_INITIALIZER;
649 }
650 return status;
651 }
652
653 /**
654 * Implementation of identification_t.get_encoding.
655 */
656 static chunk_t get_encoding(private_identification_t *this)
657 {
658 return this->encoded;
659 }
660
661 /**
662 * Implementation of identification_t.get_type.
663 */
664 static id_type_t get_type(private_identification_t *this)
665 {
666 return this->type;
667 }
668
669 /**
670 * Implementation of identification_t.get_string.
671 */
672 static char *get_string(private_identification_t *this)
673 {
674 return this->string;
675 }
676
677 /**
678 * Implementation of identification_t.contains_wildcards.
679 */
680 static bool contains_wildcards(private_identification_t *this)
681 {
682 return this->type == ID_ANY || memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
683 }
684
685 /**
686 * Default implementation of identification_t.equals and identification_t.belongs_to.
687 * compares encoded chunk for equality.
688 */
689 static bool equals_binary(private_identification_t *this, private_identification_t *other)
690 {
691 return this->type == other->type && chunk_equals(this->encoded, other->encoded);
692 }
693
694 /**
695 * Special implementation of identification_t.equals for ID_DER_ASN1_DN
696 */
697 static bool equals_dn(private_identification_t *this, private_identification_t *other)
698 {
699 return same_dn(this->encoded, other->encoded);
700 }
701
702 /**
703 * Special implementation of identification_t.belongs_to for ID_RFC822_ADDR/ID_FQDN.
704 * checks for a wildcard in other-string, and compares it against this-string.
705 */
706 static bool belongs_to_wc_string(private_identification_t *this, private_identification_t *other)
707 {
708 char *this_str, *other_str, *pos;
709
710 if (other->type == ID_ANY)
711 {
712 return TRUE;
713 }
714
715 if (this->type == other->type)
716 {
717 /* try a binary comparison first */
718 if (equals_binary(this, other))
719 {
720 return TRUE;
721 }
722 }
723 if (other->encoded.len > 0 &&
724 *(other->encoded.ptr) == '*')
725 {
726 if (other->encoded.len == 1)
727 {
728 /* other contains just a wildcard, and therefore matches anything */
729 return TRUE;
730 }
731 /* We strdup chunks, since they are NOT null-terminated */
732 this_str = strndupa(this->encoded.ptr, this->encoded.len);
733 other_str = strndupa(other->encoded.ptr + 1, other->encoded.len - 1);
734 pos = strstr(this_str, other_str);
735 if (pos != NULL)
736 {
737 /* ok, other is contained in this, but there may be more characters, so check it */
738 if (strlen(pos) == strlen(other_str))
739 {
740 return TRUE;
741 }
742 }
743 }
744
745 return FALSE;
746 }
747
748 /**
749 * Special implementation of identification_t.belongs_to for ID_ANY.
750 * ANY matches only another ANY, but nothing other
751 */
752 static bool belongs_to_any(private_identification_t *this, private_identification_t *other)
753 {
754 return other->type == ID_ANY;
755 }
756
757 /**
758 * Special implementation of identification_t.belongs_to for ID_DER_ASN1_DN.
759 * ANY matches any, even ANY, thats why its there...
760 */
761 static bool belongs_to_dn(private_identification_t *this, private_identification_t *other)
762 {
763 int wildcards;
764
765 if (other->type == ID_ANY)
766 {
767 return TRUE;
768 }
769
770 if (this->type == other->type)
771 {
772 return match_dn(this->encoded, other->encoded, &wildcards);
773 }
774 return FALSE;
775 }
776
777 /**
778 * Implementation of identification_t.clone.
779 */
780 static identification_t *clone(private_identification_t *this)
781 {
782 private_identification_t *clone = identification_create();
783
784 clone->type = this->type;
785 clone->encoded = chunk_clone(this->encoded);
786 clone->string = malloc(strlen(this->string) + 1);
787 strcpy(clone->string, this->string);
788
789 return &clone->public;
790 }
791
792 /**
793 * Implementation of identification_t.destroy.
794 */
795 static void destroy(private_identification_t *this)
796 {
797 free(this->string);
798 free(this->encoded.ptr);
799 free(this);
800 }
801
802 /**
803 * Generic constructor used for the other constructors.
804 */
805 static private_identification_t *identification_create(void)
806 {
807 private_identification_t *this = malloc_thing(private_identification_t);
808
809 this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding;
810 this->public.get_type = (id_type_t (*) (identification_t*))get_type;
811 this->public.get_string = (char* (*) (identification_t*))get_string;
812 this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards;
813 this->public.clone = (identification_t* (*) (identification_t*))clone;
814 this->public.destroy = (void (*) (identification_t*))destroy;
815 /* we use these as defaults, the may be overloaded for special ID types */
816 this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary;
817 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))equals_binary;
818
819 this->string = NULL;
820 this->encoded = CHUNK_INITIALIZER;
821
822 return this;
823 }
824
825 /*
826 * Described in header.
827 */
828 identification_t *identification_create_from_string(char *string)
829 {
830 private_identification_t *this = identification_create();
831
832 if (string == NULL)
833 string = "%any";
834
835 if (strchr(string, '=') != NULL)
836 {
837 /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
838 * convert from LDAP style or openssl x509 -subject style to ASN.1 DN
839 */
840 if (atodn(string, &this->encoded) != SUCCESS)
841 {
842 free(this);
843 return NULL;
844 }
845 this->string = strdup(string);
846 this->type = ID_DER_ASN1_DN;
847 this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
848 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
849 return &this->public;
850 }
851 else if (strchr(string, '@') == NULL)
852 {
853 if (streq(string, "%any")
854 || streq(string, "0.0.0.0")
855 || streq(string, "*")
856 || streq(string, "::")
857 || streq(string, "0::0"))
858 {
859 /* any ID will be accepted */
860 this->type = ID_ANY;
861 this->string = strdup("%any");
862 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
863 return &this->public;
864 }
865 else
866 {
867 if (strchr(string, ':') == NULL)
868 {
869 /* try IPv4 */
870 struct in_addr address;
871 chunk_t chunk = {(void*)&address, sizeof(address)};
872
873 if (inet_pton(AF_INET, string, &address) <= 0)
874 {
875 free(this);
876 return NULL;
877 }
878 this->encoded = chunk_clone(chunk);
879 this->string = strdup(string);
880 this->type = ID_IPV4_ADDR;
881 return &(this->public);
882 }
883 else
884 {
885 /* try IPv6 */
886 struct in6_addr address;
887 chunk_t chunk = {(void*)&address, sizeof(address)};
888
889 if (inet_pton(AF_INET6, string, &address) <= 0)
890 {
891 free(this);
892 return NULL;
893 }
894 this->encoded = chunk_clone(chunk);
895 this->string = strdup(string);
896 this->type = ID_IPV6_ADDR;
897 return &(this->public);
898 }
899 }
900 }
901 else
902 {
903 if (*string == '@')
904 {
905 if (*(string + 1) == '#')
906 {
907 /* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too?
908 Yes, key IDs are needed */
909 free(this);
910 return NULL;
911 }
912 else
913 {
914 this->type = ID_FQDN;
915 this->string = strdup(string);
916 this->encoded.ptr = strdup(string + 1);
917 this->encoded.len = strlen(string + 1);
918 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
919 return &(this->public);
920 }
921 }
922 else
923 {
924 this->type = ID_RFC822_ADDR;
925 this->string = strdup(string);
926 this->encoded.ptr = strdup(string);
927 this->encoded.len = strlen(string);
928 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
929 return &(this->public);
930 }
931 }
932 }
933
934 /*
935 * Described in header.
936 */
937 identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded)
938 {
939 char *pos;
940 char buf[BUF_LEN];
941 chunk_t buf_chunk = chunk_from_buf(buf);
942 private_identification_t *this = identification_create();
943
944 this->type = type;
945 switch (type)
946 {
947 case ID_ANY:
948 this->string = strdup("%any");
949 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
950 break;
951 case ID_IPV4_ADDR:
952 if (encoded.len < sizeof(struct in_addr) ||
953 inet_ntop(AF_INET, encoded.ptr, buf, sizeof(buf)) == NULL)
954 {
955 this->string = strdup("(invalid ID_IPV4_ADDR)");
956 }
957 else
958 {
959 this->string = strdup(buf);
960 }
961 break;
962 case ID_IPV6_ADDR:
963 if (encoded.len < sizeof(struct in6_addr) ||
964 inet_ntop(AF_INET6, encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
965 {
966 this->string = strdup("(invalid ID_IPV6_ADDR)");
967 }
968 else
969 {
970 this->string = strdup(buf);
971 }
972 break;
973 case ID_FQDN:
974 snprintf(buf, sizeof(buf), "@%.*s", encoded.len, encoded.ptr);
975 this->string = strdup(buf);
976 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
977 break;
978 case ID_RFC822_ADDR:
979 snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
980 this->string = strdup(buf);
981 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
982 break;
983 case ID_DER_ASN1_DN:
984 snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
985 /* TODO: whats returned on failure */
986 dntoa(encoded, &buf_chunk);
987 this->string = strdup(buf);
988 this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
989 this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
990 break;
991 case ID_DER_ASN1_GN:
992 this->string = strdup("ASN.1 coded generalName");
993 break;
994 case ID_KEY_ID:
995 this->string = strdup("(KEY_ID)");
996 break;
997 case ID_DER_ASN1_GN_URI:
998 snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
999 this->string = strdup(buf);
1000 break;
1001 default:
1002 snprintf(buf, sizeof(buf), "(invalid ID type: %d)", type);
1003 this->string = strdup(buf);
1004 break;
1005 }
1006
1007 /* apply encoded chunk */
1008 if (type != ID_ANY)
1009 {
1010 this->encoded = chunk_clone(encoded);
1011 }
1012
1013 /* remove unprintable chars in string */
1014 for (pos = this->string; *pos != '\0'; pos++)
1015 {
1016 if (!isprint(*pos))
1017 {
1018 *pos = '?';
1019 }
1020 }
1021 return &(this->public);
1022 }