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