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