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