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