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