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