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