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