added missing equals() method assignment for ID_ANY identities
[strongswan.git] / src / libstrongswan / utils / identification.c
1 /*
2 * Copyright (C) 2009 Tobias Brunner
3 * Copyright (C) 2005-2009 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #define _GNU_SOURCE
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 #include "identification.h"
26
27 #include <asn1/oid.h>
28 #include <asn1/asn1.h>
29
30 ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS,
31 "MATCH_NONE",
32 "MATCH_ANY",
33 "MATCH_MAX_WILDCARDS");
34 ENUM_NEXT(id_match_names, ID_MATCH_PERFECT, ID_MATCH_PERFECT, ID_MATCH_MAX_WILDCARDS,
35 "MATCH_PERFECT");
36 ENUM_END(id_match_names, ID_MATCH_PERFECT);
37
38 ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
39 "ID_ANY",
40 "ID_IPV4_ADDR",
41 "ID_FQDN",
42 "ID_RFC822_ADDR",
43 "ID_IPV4_ADDR_SUBNET",
44 "ID_IPV6_ADDR",
45 "ID_IPV6_ADDR_SUBNET",
46 "ID_IPV4_ADDR_RANGE",
47 "ID_IPV6_ADDR_RANGE",
48 "ID_DER_ASN1_DN",
49 "ID_DER_ASN1_GN",
50 "ID_KEY_ID");
51 ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_CERT_DER_SHA1, ID_KEY_ID,
52 "ID_DER_ASN1_GN_URI",
53 "ID_PUBKEY_INFO_SHA1",
54 "ID_PUBKEY_SHA1",
55 "ID_CERT_DER_SHA1");
56 ENUM_END(id_type_names, ID_CERT_DER_SHA1);
57
58 /**
59 * coding of X.501 distinguished name
60 */
61 typedef struct {
62 const u_char *name;
63 int oid;
64 u_char type;
65 } x501rdn_t;
66
67 static const x501rdn_t x501rdns[] = {
68 {"ND", OID_NAME_DISTINGUISHER, ASN1_PRINTABLESTRING},
69 {"UID", OID_PILOT_USERID, ASN1_PRINTABLESTRING},
70 {"DC", OID_PILOT_DOMAIN_COMPONENT, ASN1_PRINTABLESTRING},
71 {"CN", OID_COMMON_NAME, ASN1_PRINTABLESTRING},
72 {"S", OID_SURNAME, ASN1_PRINTABLESTRING},
73 {"SN", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING},
74 {"serialNumber", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING},
75 {"C", OID_COUNTRY, ASN1_PRINTABLESTRING},
76 {"L", OID_LOCALITY, ASN1_PRINTABLESTRING},
77 {"ST", OID_STATE_OR_PROVINCE, ASN1_PRINTABLESTRING},
78 {"O", OID_ORGANIZATION, ASN1_PRINTABLESTRING},
79 {"OU", OID_ORGANIZATION_UNIT, ASN1_PRINTABLESTRING},
80 {"T", OID_TITLE, ASN1_PRINTABLESTRING},
81 {"D", OID_DESCRIPTION, ASN1_PRINTABLESTRING},
82 {"N", OID_NAME, ASN1_PRINTABLESTRING},
83 {"G", OID_GIVEN_NAME, ASN1_PRINTABLESTRING},
84 {"I", OID_INITIALS, ASN1_PRINTABLESTRING},
85 {"ID", OID_UNIQUE_IDENTIFIER, ASN1_PRINTABLESTRING},
86 {"EN", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
87 {"employeeNumber", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
88 {"E", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
89 {"Email", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
90 {"emailAddress", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
91 {"UN", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING},
92 {"unstructuredName",OID_UNSTRUCTURED_NAME, ASN1_IA5STRING},
93 {"TCGID", OID_TCGID, ASN1_PRINTABLESTRING}
94 };
95
96 /**
97 * maximum number of RDNs in atodn()
98 */
99 #define RDN_MAX 20
100
101
102 typedef struct private_identification_t private_identification_t;
103
104 /**
105 * Private data of an identification_t object.
106 */
107 struct private_identification_t {
108 /**
109 * Public interface.
110 */
111 identification_t public;
112
113 /**
114 * Encoded representation of this ID.
115 */
116 chunk_t encoded;
117
118 /**
119 * Type of this ID.
120 */
121 id_type_t type;
122 };
123
124 /**
125 * Enumerator over RDNs
126 */
127 typedef struct {
128 /* implements enumerator interface */
129 enumerator_t public;
130 /* RDNs left to parse */
131 chunk_t left;
132 } rdn_enumerator_t;
133
134 /**
135 * Implementation of rdn_enumerator_t.enumerate
136 */
137 static bool rdn_enumerate(rdn_enumerator_t *this, chunk_t *oid,
138 u_char *type, chunk_t *data)
139 {
140 chunk_t rdn;
141
142 /* a RDN is a SET of attribute-values, each is a SEQUENCE ... */
143 if (asn1_unwrap(&this->left, &rdn) == ASN1_SET &&
144 asn1_unwrap(&rdn, &rdn) == ASN1_SEQUENCE)
145 {
146 /* ... of an OID */
147 if (asn1_unwrap(&rdn, oid) == ASN1_OID)
148 {
149 /* and a specific string type */
150 *type = asn1_unwrap(&rdn, data);
151 if (*type != ASN1_INVALID)
152 {
153 return TRUE;
154 }
155 }
156 }
157 return FALSE;
158 }
159
160 /**
161 * Create an enumerator over all RDNs (oid, string type, data) of a DN
162 */
163 static enumerator_t* create_rdn_enumerator(chunk_t dn)
164 {
165 rdn_enumerator_t *e = malloc_thing(rdn_enumerator_t);
166
167 e->public.enumerate = (void*)rdn_enumerate;
168 e->public.destroy = (void*)free;
169
170 /* a DN is a sequence of RDNs */
171 if (asn1_unwrap(&dn, &e->left) == ASN1_SEQUENCE)
172 {
173 return &e->public;
174 }
175 free(e);
176 return enumerator_create_empty();
177 }
178
179 /**
180 * Part enumerator over RDNs
181 */
182 typedef struct {
183 /* implements enumerator interface */
184 enumerator_t public;
185 /* inner RDN enumerator */
186 enumerator_t *inner;
187 } rdn_part_enumerator_t;
188
189 /**
190 * Implementation of rdn_part_enumerator_t.enumerate().
191 */
192 static bool rdn_part_enumerate(rdn_part_enumerator_t *this,
193 id_part_t *type, chunk_t *data)
194 {
195 int i, known_oid, strtype;
196 chunk_t oid, inner_data;
197 static const struct {
198 int oid;
199 id_part_t type;
200 } oid2part[] = {
201 {OID_COMMON_NAME, ID_PART_RDN_CN},
202 {OID_SURNAME, ID_PART_RDN_S},
203 {OID_SERIAL_NUMBER, ID_PART_RDN_SN},
204 {OID_COUNTRY, ID_PART_RDN_C},
205 {OID_LOCALITY, ID_PART_RDN_L},
206 {OID_STATE_OR_PROVINCE, ID_PART_RDN_ST},
207 {OID_ORGANIZATION, ID_PART_RDN_O},
208 {OID_ORGANIZATION_UNIT, ID_PART_RDN_OU},
209 {OID_TITLE, ID_PART_RDN_T},
210 {OID_DESCRIPTION, ID_PART_RDN_D},
211 {OID_NAME, ID_PART_RDN_N},
212 {OID_GIVEN_NAME, ID_PART_RDN_G},
213 {OID_INITIALS, ID_PART_RDN_I},
214 {OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID},
215 {OID_EMAIL_ADDRESS, ID_PART_RDN_E},
216 {OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN},
217 };
218
219 while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data))
220 {
221 known_oid = asn1_known_oid(oid);
222 for (i = 0; i < countof(oid2part); i++)
223 {
224 if (oid2part[i].oid == known_oid)
225 {
226 *type = oid2part[i].type;
227 *data = inner_data;
228 return TRUE;
229 }
230 }
231 }
232 return FALSE;
233 }
234
235 /**
236 * Implementation of rdn_part_enumerator_t.destroy().
237 */
238 static void rdn_part_enumerator_destroy(rdn_part_enumerator_t *this)
239 {
240 this->inner->destroy(this->inner);
241 free(this);
242 }
243
244 /**
245 * Implementation of identification_t.create_part_enumerator
246 */
247 static enumerator_t* create_part_enumerator(private_identification_t *this)
248 {
249 switch (this->type)
250 {
251 case ID_DER_ASN1_DN:
252 {
253 rdn_part_enumerator_t *e = malloc_thing(rdn_part_enumerator_t);
254
255 e->inner = create_rdn_enumerator(this->encoded);
256 e->public.enumerate = (void*)rdn_part_enumerate;
257 e->public.destroy = (void*)rdn_part_enumerator_destroy;
258
259 return &e->public;
260 }
261 case ID_RFC822_ADDR:
262 /* TODO */
263 case ID_FQDN:
264 /* TODO */
265 default:
266 return enumerator_create_empty();
267 }
268 }
269
270 /**
271 * Print a DN with all its RDN in a buffer to present it to the user
272 */
273 static void dntoa(chunk_t dn, char *buf, size_t len)
274 {
275 enumerator_t *e;
276 chunk_t oid_data, data;
277 u_char type;
278 int oid, written;
279 bool finished = FALSE;
280
281 e = create_rdn_enumerator(dn);
282 while (e->enumerate(e, &oid_data, &type, &data))
283 {
284 oid = asn1_known_oid(oid_data);
285
286 if (oid == OID_UNKNOWN)
287 {
288 written = snprintf(buf, len, "%#B=", &oid_data);
289 }
290 else
291 {
292 written = snprintf(buf, len,"%s=", oid_names[oid].name);
293 }
294 buf += written;
295 len -= written;
296
297 if (chunk_printable(data, NULL, '?'))
298 {
299 written = snprintf(buf, len, "%.*s", data.len, data.ptr);
300 }
301 else
302 {
303 written = snprintf(buf, len, "%#B", &data);
304 }
305 buf += written;
306 len -= written;
307
308 if (data.ptr + data.len != dn.ptr + dn.len)
309 {
310 written = snprintf(buf, len, " ");
311 buf += written;
312 len -= written;
313 }
314 else
315 {
316 finished = TRUE;
317 break;
318 }
319 }
320 if (!finished)
321 {
322 snprintf(buf, len, "(invalid ID_DER_ASN1_DN)");
323 }
324 e->destroy(e);
325 }
326
327 /**
328 * Converts an LDAP-style human-readable ASCII-encoded
329 * ASN.1 distinguished name into binary DER-encoded format
330 */
331 static status_t atodn(char *src, chunk_t *dn)
332 {
333 /* finite state machine for atodn */
334 typedef enum {
335 SEARCH_OID = 0,
336 READ_OID = 1,
337 SEARCH_NAME = 2,
338 READ_NAME = 3,
339 UNKNOWN_OID = 4
340 } state_t;
341
342 chunk_t oid = chunk_empty;
343 chunk_t name = chunk_empty;
344 chunk_t rdns[RDN_MAX];
345 int rdn_count = 0;
346 int dn_len = 0;
347 int whitespace = 0;
348 int i = 0;
349 asn1_t rdn_type;
350 state_t state = SEARCH_OID;
351 status_t status = SUCCESS;
352
353 do
354 {
355 switch (state)
356 {
357 case SEARCH_OID:
358 if (*src != ' ' && *src != '/' && *src != ',')
359 {
360 oid.ptr = src;
361 oid.len = 1;
362 state = READ_OID;
363 }
364 break;
365 case READ_OID:
366 if (*src != ' ' && *src != '=')
367 {
368 oid.len++;
369 }
370 else
371 {
372 bool found = FALSE;
373
374 for (i = 0; i < countof(x501rdns); i++)
375 {
376 if (strlen(x501rdns[i].name) == oid.len &&
377 strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0)
378 {
379 found = TRUE;
380 break;
381 }
382 }
383 if (!found)
384 {
385 status = NOT_SUPPORTED;
386 state = UNKNOWN_OID;
387 break;
388 }
389 /* reset oid and change state */
390 oid = chunk_empty;
391 state = SEARCH_NAME;
392 }
393 break;
394 case SEARCH_NAME:
395 if (*src != ' ' && *src != '=')
396 {
397 name.ptr = src;
398 name.len = 1;
399 whitespace = 0;
400 state = READ_NAME;
401 }
402 break;
403 case READ_NAME:
404 if (*src != ',' && *src != '/' && *src != '\0')
405 {
406 name.len++;
407 if (*src == ' ')
408 whitespace++;
409 else
410 whitespace = 0;
411 }
412 else
413 {
414 name.len -= whitespace;
415 rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING
416 && !asn1_is_printablestring(name))
417 ? ASN1_T61STRING : x501rdns[i].type;
418
419 if (rdn_count < RDN_MAX)
420 {
421 chunk_t rdn_oid;
422
423 rdn_oid = asn1_build_known_oid(x501rdns[i].oid);
424 if (rdn_oid.len)
425 {
426 rdns[rdn_count] =
427 asn1_wrap(ASN1_SET, "m",
428 asn1_wrap(ASN1_SEQUENCE, "mm",
429 rdn_oid,
430 asn1_wrap(rdn_type, "c", name)
431 )
432 );
433 dn_len += rdns[rdn_count++].len;
434 }
435 else
436 {
437 status = INVALID_ARG;
438 }
439 }
440 else
441 {
442 status = OUT_OF_RES;
443 }
444 /* reset name and change state */
445 name = chunk_empty;
446 state = SEARCH_OID;
447 }
448 break;
449 case UNKNOWN_OID:
450 break;
451 }
452 } while (*src++ != '\0');
453
454 /* build the distinguished name sequence */
455 {
456 int i;
457 u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len);
458
459 for (i = 0; i < rdn_count; i++)
460 {
461 memcpy(pos, rdns[i].ptr, rdns[i].len);
462 pos += rdns[i].len;
463 free(rdns[i].ptr);
464 }
465 }
466
467 if (status != SUCCESS)
468 {
469 free(dn->ptr);
470 *dn = chunk_empty;
471 }
472 return status;
473 }
474
475 /**
476 * Implementation of identification_t.get_encoding.
477 */
478 static chunk_t get_encoding(private_identification_t *this)
479 {
480 return this->encoded;
481 }
482
483 /**
484 * Implementation of identification_t.get_type.
485 */
486 static id_type_t get_type(private_identification_t *this)
487 {
488 return this->type;
489 }
490
491 /**
492 * Implementation of identification_t.contains_wildcards for ID_DER_ASN1_DN.
493 */
494 static bool contains_wildcards_dn(private_identification_t *this)
495 {
496 enumerator_t *enumerator;
497 bool contains = FALSE;
498 id_part_t type;
499 chunk_t data;
500
501 enumerator = create_part_enumerator(this);
502 while (enumerator->enumerate(enumerator, &type, &data))
503 {
504 if (data.len == 1 && data.ptr[0] == '*')
505 {
506 contains = TRUE;
507 break;
508 }
509 }
510 enumerator->destroy(enumerator);
511 return contains;
512 }
513
514 /**
515 * Implementation of identification_t.contains_wildcards using memchr(*).
516 */
517 static bool contains_wildcards_memchr(private_identification_t *this)
518 {
519 return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
520 }
521
522 /**
523 * Default implementation of identification_t.equals.
524 * compares encoded chunk for equality.
525 */
526 static bool equals_binary(private_identification_t *this, private_identification_t *other)
527 {
528 if (this->type == other->type)
529 {
530 if (this->type == ID_ANY)
531 {
532 return TRUE;
533 }
534 return chunk_equals(this->encoded, other->encoded);
535 }
536 return FALSE;
537 }
538
539 /**
540 * Compare to DNs, for equality if wc == NULL, for match otherwise
541 */
542 static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc)
543 {
544 enumerator_t *t, *o;
545 chunk_t t_oid, o_oid, t_data, o_data;
546 u_char t_type, o_type;
547 bool t_next, o_next, finished = FALSE;
548
549 if (wc)
550 {
551 *wc = 0;
552 }
553 else
554 {
555 if (t_dn.len != o_dn.len)
556 {
557 return FALSE;
558 }
559 }
560 /* try a binary compare */
561 if (memeq(t_dn.ptr, o_dn.ptr, t_dn.len))
562 {
563 return TRUE;
564 }
565
566 t = create_rdn_enumerator(t_dn);
567 o = create_rdn_enumerator(o_dn);
568 while (TRUE)
569 {
570 t_next = t->enumerate(t, &t_oid, &t_type, &t_data);
571 o_next = o->enumerate(o, &o_oid, &o_type, &o_data);
572
573 if (!o_next && !t_next)
574 {
575 break;
576 }
577 finished = FALSE;
578 if (o_next != t_next)
579 {
580 break;
581 }
582 if (!chunk_equals(t_oid, o_oid))
583 {
584 break;
585 }
586 if (wc && o_data.len == 1 && o_data.ptr[0] == '*')
587 {
588 (*wc)++;
589 }
590 else
591 {
592 if (t_data.len != o_data.len)
593 {
594 break;
595 }
596 if (t_type == o_type &&
597 (t_type == ASN1_PRINTABLESTRING ||
598 (t_type == ASN1_IA5STRING &&
599 (asn1_known_oid(t_oid) == OID_PKCS9_EMAIL ||
600 asn1_known_oid(t_oid) == OID_EMAIL_ADDRESS))))
601 { /* ignore case for printableStrings and email RDNs */
602 if (strncasecmp(t_data.ptr, o_data.ptr, t_data.len) != 0)
603 {
604 break;
605 }
606 }
607 else
608 { /* respect case and length for everything else */
609 if (!memeq(t_data.ptr, o_data.ptr, t_data.len))
610 {
611 break;
612 }
613 }
614 }
615 /* the enumerator returns FALSE on parse error, we are finished
616 * if we have reached the end of the DN only */
617 if ((t_data.ptr + t_data.len == t_dn.ptr + t_dn.len) &&
618 (o_data.ptr + o_data.len == o_dn.ptr + o_dn.len))
619 {
620 finished = TRUE;
621 }
622 }
623 t->destroy(t);
624 o->destroy(o);
625 return finished;
626 }
627
628 /**
629 * Special implementation of identification_t.equals for ID_DER_ASN1_DN.
630 */
631 static bool equals_dn(private_identification_t *this,
632 private_identification_t *other)
633 {
634 return compare_dn(this->encoded, other->encoded, NULL);
635 }
636
637 /**
638 * Special implementation of identification_t.equals for RFC822 and FQDN.
639 */
640 static bool equals_strcasecmp(private_identification_t *this,
641 private_identification_t *other)
642 {
643 /* we do some extra sanity checks to check for invalid IDs with a
644 * terminating null in it. */
645 if (this->encoded.len == other->encoded.len &&
646 memchr(this->encoded.ptr, 0, this->encoded.len) == NULL &&
647 memchr(other->encoded.ptr, 0, other->encoded.len) == NULL &&
648 strncasecmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0)
649 {
650 return TRUE;
651 }
652 return FALSE;
653 }
654
655 /**
656 * Default implementation of identification_t.matches.
657 */
658 static id_match_t matches_binary(private_identification_t *this,
659 private_identification_t *other)
660 {
661 if (other->type == ID_ANY)
662 {
663 return ID_MATCH_ANY;
664 }
665 if (this->type == other->type &&
666 chunk_equals(this->encoded, other->encoded))
667 {
668 return ID_MATCH_PERFECT;
669 }
670 return ID_MATCH_NONE;
671 }
672
673 /**
674 * Special implementation of identification_t.matches for ID_RFC822_ADDR/ID_FQDN.
675 * Checks for a wildcard in other-string, and compares it against this-string.
676 */
677 static id_match_t matches_string(private_identification_t *this,
678 private_identification_t *other)
679 {
680 u_int len = other->encoded.len;
681
682 if (other->type == ID_ANY)
683 {
684 return ID_MATCH_ANY;
685 }
686 if (this->type != other->type)
687 {
688 return ID_MATCH_NONE;
689 }
690 /* try a equals check first */
691 if (equals_strcasecmp(this, other))
692 {
693 return ID_MATCH_PERFECT;
694 }
695 if (len == 0 || this->encoded.len < len)
696 {
697 return ID_MATCH_NONE;
698 }
699
700 /* check for single wildcard at the head of the string */
701 if (*other->encoded.ptr == '*')
702 {
703 /* single asterisk matches any string */
704 if (len-- == 1)
705 { /* not better than ID_ANY */
706 return ID_MATCH_ANY;
707 }
708 if (strncasecmp(this->encoded.ptr + this->encoded.len - len,
709 other->encoded.ptr + 1, len) == 0)
710 {
711 return ID_MATCH_ONE_WILDCARD;
712 }
713 }
714 return ID_MATCH_NONE;
715 }
716
717 /**
718 * Special implementation of identification_t.matches for ID_ANY.
719 * ANY matches only another ANY, but nothing other
720 */
721 static id_match_t matches_any(private_identification_t *this,
722 private_identification_t *other)
723 {
724 if (other->type == ID_ANY)
725 {
726 return ID_MATCH_ANY;
727 }
728 return ID_MATCH_NONE;
729 }
730
731 /**
732 * Special implementation of identification_t.matches for ID_DER_ASN1_DN
733 */
734 static id_match_t matches_dn(private_identification_t *this,
735 private_identification_t *other)
736 {
737 int wc;
738
739 if (other->type == ID_ANY)
740 {
741 return ID_MATCH_ANY;
742 }
743
744 if (this->type == other->type)
745 {
746 if (compare_dn(this->encoded, other->encoded, &wc))
747 {
748 wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS);
749 return ID_MATCH_PERFECT - wc;
750 }
751 }
752 return ID_MATCH_NONE;
753 }
754
755 /**
756 * Described in header.
757 */
758 int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
759 const void *const *args)
760 {
761 private_identification_t *this = *((private_identification_t**)(args[0]));
762 chunk_t proper;
763 char buf[512];
764
765 if (this == NULL)
766 {
767 return print_in_hook(dst, len, "%*s", spec->width, "(null)");
768 }
769
770 switch (this->type)
771 {
772 case ID_ANY:
773 snprintf(buf, sizeof(buf), "%%any");
774 break;
775 case ID_IPV4_ADDR:
776 if (this->encoded.len < sizeof(struct in_addr) ||
777 inet_ntop(AF_INET, this->encoded.ptr, buf, sizeof(buf)) == NULL)
778 {
779 snprintf(buf, sizeof(buf), "(invalid ID_IPV4_ADDR)");
780 }
781 break;
782 case ID_IPV6_ADDR:
783 if (this->encoded.len < sizeof(struct in6_addr) ||
784 inet_ntop(AF_INET6, this->encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
785 {
786 snprintf(buf, sizeof(buf), "(invalid ID_IPV6_ADDR)");
787 }
788 break;
789 case ID_FQDN:
790 case ID_RFC822_ADDR:
791 case ID_DER_ASN1_GN_URI:
792 case ID_IETF_ATTR_STRING:
793 chunk_printable(this->encoded, &proper, '?');
794 snprintf(buf, sizeof(buf), "%.*s", proper.len, proper.ptr);
795 chunk_free(&proper);
796 break;
797 case ID_DER_ASN1_DN:
798 dntoa(this->encoded, buf, sizeof(buf));
799 break;
800 case ID_DER_ASN1_GN:
801 snprintf(buf, sizeof(buf), "(ASN.1 general Name");
802 break;
803 case ID_KEY_ID:
804 if (chunk_printable(this->encoded, NULL, '?'))
805 { /* fully printable, use ascii version */
806 snprintf(buf, sizeof(buf), "%.*s",
807 this->encoded.len, this->encoded.ptr);
808 }
809 else
810 { /* not printable, hex dump */
811 snprintf(buf, sizeof(buf), "%#B", &this->encoded);
812 }
813 chunk_free(&proper);
814 break;
815 case ID_PUBKEY_INFO_SHA1:
816 case ID_PUBKEY_SHA1:
817 case ID_CERT_DER_SHA1:
818 snprintf(buf, sizeof(buf), "%#B", &this->encoded);
819 break;
820 default:
821 snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type);
822 break;
823 }
824 if (spec->minus)
825 {
826 return print_in_hook(dst, len, "%-*s", spec->width, buf);
827 }
828 return print_in_hook(dst, len, "%*s", spec->width, buf);
829 }
830 /**
831 * Implementation of identification_t.clone.
832 */
833 static identification_t *clone_(private_identification_t *this)
834 {
835 private_identification_t *clone = malloc_thing(private_identification_t);
836
837 memcpy(clone, this, sizeof(private_identification_t));
838 if (this->encoded.len)
839 {
840 clone->encoded = chunk_clone(this->encoded);
841 }
842 return &clone->public;
843 }
844
845 /**
846 * Implementation of identification_t.destroy.
847 */
848 static void destroy(private_identification_t *this)
849 {
850 chunk_free(&this->encoded);
851 free(this);
852 }
853
854 /**
855 * Generic constructor used for the other constructors.
856 */
857 static private_identification_t *identification_create(id_type_t type)
858 {
859 private_identification_t *this = malloc_thing(private_identification_t);
860
861 this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding;
862 this->public.get_type = (id_type_t (*) (identification_t*))get_type;
863 this->public.create_part_enumerator = (enumerator_t*(*)(identification_t*))create_part_enumerator;
864 this->public.clone = (identification_t* (*) (identification_t*))clone_;
865 this->public.destroy = (void (*) (identification_t*))destroy;
866
867 switch (type)
868 {
869 case ID_ANY:
870 this->public.matches = (id_match_t (*)(identification_t*,identification_t*))matches_any;
871 this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary;
872 this->public.contains_wildcards = (bool (*) (identification_t *this))return_true;
873 break;
874 case ID_FQDN:
875 case ID_RFC822_ADDR:
876 this->public.matches = (id_match_t (*)(identification_t*,identification_t*))matches_string;
877 this->public.equals = (bool (*)(identification_t*,identification_t*))equals_strcasecmp;
878 this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards_memchr;
879 break;
880 case ID_DER_ASN1_DN:
881 this->public.equals = (bool (*)(identification_t*,identification_t*))equals_dn;
882 this->public.matches = (id_match_t (*)(identification_t*,identification_t*))matches_dn;
883 this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards_dn;
884 break;
885 default:
886 this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary;
887 this->public.matches = (id_match_t (*) (identification_t*,identification_t*))matches_binary;
888 this->public.contains_wildcards = (bool (*) (identification_t *this))return_false;
889 break;
890 }
891
892 this->type = type;
893 this->encoded = chunk_empty;
894
895 return this;
896 }
897
898 /*
899 * Described in header.
900 */
901 identification_t *identification_create_from_string(char *string)
902 {
903 private_identification_t *this;
904 chunk_t encoded;
905
906 if (string == NULL)
907 {
908 string = "%any";
909 }
910 if (strchr(string, '=') != NULL)
911 {
912 /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
913 * convert from LDAP style or openssl x509 -subject style to ASN.1 DN
914 */
915 if (atodn(string, &encoded) == SUCCESS)
916 {
917 this = identification_create(ID_DER_ASN1_DN);
918 this->encoded = encoded;
919 }
920 else
921 {
922 this = identification_create(ID_KEY_ID);
923 this->encoded = chunk_clone(chunk_create(string, strlen(string)));
924 }
925 return &this->public;
926 }
927 else if (strchr(string, '@') == NULL)
928 {
929 if (streq(string, "%any")
930 || streq(string, "%any6")
931 || streq(string, "0.0.0.0")
932 || streq(string, "*")
933 || streq(string, "::")
934 || streq(string, "0::0"))
935 {
936 /* any ID will be accepted */
937 this = identification_create(ID_ANY);
938 return &this->public;
939 }
940 else
941 {
942 if (strchr(string, ':') == NULL)
943 {
944 struct in_addr address;
945 chunk_t chunk = {(void*)&address, sizeof(address)};
946
947 if (inet_pton(AF_INET, string, &address) > 0)
948 { /* is IPv4 */
949 this = identification_create(ID_IPV4_ADDR);
950 this->encoded = chunk_clone(chunk);
951 }
952 else
953 { /* not IPv4, mostly FQDN */
954 this = identification_create(ID_FQDN);
955 this->encoded = chunk_create(strdup(string), strlen(string));
956 }
957 return &this->public;
958 }
959 else
960 {
961 struct in6_addr address;
962 chunk_t chunk = {(void*)&address, sizeof(address)};
963
964 if (inet_pton(AF_INET6, string, &address) > 0)
965 { /* is IPv6 */
966 this = identification_create(ID_IPV6_ADDR);
967 this->encoded = chunk_clone(chunk);
968 }
969 else
970 { /* not IPv4/6 fallback to KEY_ID */
971 this = identification_create(ID_KEY_ID);
972 this->encoded = chunk_create(strdup(string), strlen(string));
973 }
974 return &this->public;
975 }
976 }
977 }
978 else
979 {
980 if (*string == '@')
981 {
982 if (*(string + 1) == '#')
983 {
984 this = identification_create(ID_KEY_ID);
985 string += 2;
986 this->encoded = chunk_from_hex(
987 chunk_create(string, strlen(string)), NULL);
988 return &this->public;
989 }
990 else
991 {
992 this = identification_create(ID_FQDN);
993 string += 1;
994 this->encoded = chunk_create(strdup(string), strlen(string));
995 return &this->public;
996 }
997 }
998 else
999 {
1000 this = identification_create(ID_RFC822_ADDR);
1001 this->encoded = chunk_create(strdup(string), strlen(string));
1002 return &this->public;
1003 }
1004 }
1005 }
1006
1007 /*
1008 * Described in header.
1009 */
1010 identification_t *identification_create_from_encoding(id_type_t type,
1011 chunk_t encoded)
1012 {
1013 private_identification_t *this = identification_create(type);
1014
1015 /* apply encoded chunk */
1016 if (type != ID_ANY)
1017 {
1018 this->encoded = chunk_clone(encoded);
1019 }
1020 return &(this->public);
1021 }
1022