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