Annotation of embedaddon/strongswan/src/libstrongswan/utils/identification.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2016 Andreas Steffen
! 3: * Copyright (C) 2009-2019 Tobias Brunner
! 4: * Copyright (C) 2005-2009 Martin Willi
! 5: * Copyright (C) 2005 Jan Hutter
! 6: * HSR Hochschule fuer Technik Rapperswil
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: #include <string.h>
! 20: #include <stdio.h>
! 21: #include <errno.h>
! 22:
! 23: #include "identification.h"
! 24:
! 25: #include <utils/utils.h>
! 26: #include <asn1/oid.h>
! 27: #include <asn1/asn1.h>
! 28: #include <crypto/hashers/hasher.h>
! 29: #include <collections/array.h>
! 30:
! 31: ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS,
! 32: "MATCH_NONE",
! 33: "MATCH_ANY",
! 34: "MATCH_MAX_WILDCARDS");
! 35: ENUM_NEXT(id_match_names, ID_MATCH_PERFECT, ID_MATCH_PERFECT, ID_MATCH_MAX_WILDCARDS,
! 36: "MATCH_PERFECT");
! 37: ENUM_END(id_match_names, ID_MATCH_PERFECT);
! 38:
! 39: ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
! 40: "ID_ANY",
! 41: "ID_IPV4_ADDR",
! 42: "ID_FQDN",
! 43: "ID_RFC822_ADDR",
! 44: "ID_IPV4_ADDR_SUBNET",
! 45: "ID_IPV6_ADDR",
! 46: "ID_IPV6_ADDR_SUBNET",
! 47: "ID_IPV4_ADDR_RANGE",
! 48: "ID_IPV6_ADDR_RANGE",
! 49: "ID_DER_ASN1_DN",
! 50: "ID_DER_ASN1_GN",
! 51: "ID_KEY_ID");
! 52: ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_DER_ASN1_GN_URI, ID_KEY_ID,
! 53: "ID_DER_ASN1_GN_URI");
! 54: ENUM_END(id_type_names, ID_DER_ASN1_GN_URI);
! 55:
! 56: /**
! 57: * coding of X.501 distinguished name
! 58: */
! 59: typedef struct {
! 60: const u_char *name;
! 61: int oid;
! 62: u_char type;
! 63: } x501rdn_t;
! 64:
! 65: static const x501rdn_t x501rdns[] = {
! 66: {"ND", OID_NAME_DISTINGUISHER, ASN1_PRINTABLESTRING},
! 67: {"UID", OID_PILOT_USERID, ASN1_PRINTABLESTRING},
! 68: {"DC", OID_PILOT_DOMAIN_COMPONENT, ASN1_PRINTABLESTRING},
! 69: {"CN", OID_COMMON_NAME, ASN1_PRINTABLESTRING},
! 70: {"S", OID_SURNAME, ASN1_PRINTABLESTRING},
! 71: {"SN", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING},
! 72: {"serialNumber", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING},
! 73: {"C", OID_COUNTRY, ASN1_PRINTABLESTRING},
! 74: {"L", OID_LOCALITY, ASN1_PRINTABLESTRING},
! 75: {"ST", OID_STATE_OR_PROVINCE, ASN1_PRINTABLESTRING},
! 76: {"STREET", OID_STREET_ADDRESS, 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: {"postalAddress", OID_POSTAL_ADDRESS, ASN1_PRINTABLESTRING},
! 82: {"postalCode", OID_POSTAL_CODE, ASN1_PRINTABLESTRING},
! 83: {"N", OID_NAME, ASN1_PRINTABLESTRING},
! 84: {"G", OID_GIVEN_NAME, ASN1_PRINTABLESTRING},
! 85: {"I", OID_INITIALS, ASN1_PRINTABLESTRING},
! 86: {"dnQualifier", OID_DN_QUALIFIER, ASN1_PRINTABLESTRING},
! 87: {"dmdName", OID_DMD_NAME, ASN1_PRINTABLESTRING},
! 88: {"pseudonym", OID_PSEUDONYM, ASN1_PRINTABLESTRING},
! 89: {"ID", OID_UNIQUE_IDENTIFIER, ASN1_PRINTABLESTRING},
! 90: {"EN", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
! 91: {"employeeNumber", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING},
! 92: {"E", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
! 93: {"Email", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
! 94: {"emailAddress", OID_EMAIL_ADDRESS, ASN1_IA5STRING},
! 95: {"UN", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING},
! 96: {"unstructuredName", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING},
! 97: {"UA", OID_UNSTRUCTURED_ADDRESS, ASN1_PRINTABLESTRING},
! 98: {"unstructuredAddress", OID_UNSTRUCTURED_ADDRESS, ASN1_PRINTABLESTRING},
! 99: {"TCGID", OID_TCGID, ASN1_PRINTABLESTRING}
! 100: };
! 101:
! 102: /**
! 103: * maximum number of RDNs in atodn()
! 104: */
! 105: #define RDN_MAX 20
! 106:
! 107:
! 108: typedef struct private_identification_t private_identification_t;
! 109:
! 110: /**
! 111: * Private data of an identification_t object.
! 112: */
! 113: struct private_identification_t {
! 114: /**
! 115: * Public interface.
! 116: */
! 117: identification_t public;
! 118:
! 119: /**
! 120: * Encoded representation of this ID.
! 121: */
! 122: chunk_t encoded;
! 123:
! 124: /**
! 125: * Type of this ID.
! 126: */
! 127: id_type_t type;
! 128: };
! 129:
! 130: /**
! 131: * Enumerator over RDNs
! 132: */
! 133: typedef struct {
! 134: /* implements enumerator interface */
! 135: enumerator_t public;
! 136: /* next set to parse, if any */
! 137: chunk_t sets;
! 138: /* next sequence in set, if any */
! 139: chunk_t seqs;
! 140: } rdn_enumerator_t;
! 141:
! 142: METHOD(enumerator_t, rdn_enumerate, bool,
! 143: rdn_enumerator_t *this, va_list args)
! 144: {
! 145: chunk_t rdn, *oid, *data;
! 146: u_char *type;
! 147:
! 148: VA_ARGS_VGET(args, oid, type, data);
! 149:
! 150: /* a DN contains one or more SET, each containing one or more SEQUENCES,
! 151: * each containing a OID/value RDN */
! 152: if (!this->seqs.len)
! 153: {
! 154: /* no SEQUENCEs in current SET, parse next SET */
! 155: if (asn1_unwrap(&this->sets, &this->seqs) != ASN1_SET)
! 156: {
! 157: return FALSE;
! 158: }
! 159: }
! 160: if (asn1_unwrap(&this->seqs, &rdn) == ASN1_SEQUENCE &&
! 161: asn1_unwrap(&rdn, oid) == ASN1_OID)
! 162: {
! 163: int t = asn1_unwrap(&rdn, data);
! 164:
! 165: if (t != ASN1_INVALID)
! 166: {
! 167: *type = t;
! 168: return TRUE;
! 169: }
! 170: }
! 171: return FALSE;
! 172: }
! 173:
! 174: /**
! 175: * Create an enumerator over all RDNs (oid, string type, data) of a DN
! 176: */
! 177: static enumerator_t* create_rdn_enumerator(chunk_t dn)
! 178: {
! 179: rdn_enumerator_t *e;
! 180:
! 181: INIT(e,
! 182: .public = {
! 183: .enumerate = enumerator_enumerate_default,
! 184: .venumerate = _rdn_enumerate,
! 185: .destroy = (void*)free,
! 186: },
! 187: );
! 188:
! 189: /* a DN is a SEQUENCE, get the first SET of it */
! 190: if (asn1_unwrap(&dn, &e->sets) == ASN1_SEQUENCE)
! 191: {
! 192: e->seqs = chunk_empty;
! 193: return &e->public;
! 194: }
! 195: free(e);
! 196: return enumerator_create_empty();
! 197: }
! 198:
! 199: /**
! 200: * Part enumerator over RDNs
! 201: */
! 202: typedef struct {
! 203: /* implements enumerator interface */
! 204: enumerator_t public;
! 205: /* inner RDN enumerator */
! 206: enumerator_t *inner;
! 207: } rdn_part_enumerator_t;
! 208:
! 209: METHOD(enumerator_t, rdn_part_enumerate, bool,
! 210: rdn_part_enumerator_t *this, va_list args)
! 211: {
! 212: int i, known_oid, strtype;
! 213: chunk_t oid, inner_data, *data;
! 214: id_part_t *type;
! 215: static const struct {
! 216: int oid;
! 217: id_part_t type;
! 218: } oid2part[] = {
! 219: {OID_COMMON_NAME, ID_PART_RDN_CN},
! 220: {OID_SURNAME, ID_PART_RDN_S},
! 221: {OID_SERIAL_NUMBER, ID_PART_RDN_SN},
! 222: {OID_COUNTRY, ID_PART_RDN_C},
! 223: {OID_LOCALITY, ID_PART_RDN_L},
! 224: {OID_STATE_OR_PROVINCE, ID_PART_RDN_ST},
! 225: {OID_ORGANIZATION, ID_PART_RDN_O},
! 226: {OID_ORGANIZATION_UNIT, ID_PART_RDN_OU},
! 227: {OID_TITLE, ID_PART_RDN_T},
! 228: {OID_DESCRIPTION, ID_PART_RDN_D},
! 229: {OID_NAME, ID_PART_RDN_N},
! 230: {OID_GIVEN_NAME, ID_PART_RDN_G},
! 231: {OID_INITIALS, ID_PART_RDN_I},
! 232: {OID_DN_QUALIFIER, ID_PART_RDN_DNQ},
! 233: {OID_DMD_NAME, ID_PART_RDN_DMDN},
! 234: {OID_PSEUDONYM, ID_PART_RDN_PN},
! 235: {OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID},
! 236: {OID_EMAIL_ADDRESS, ID_PART_RDN_E},
! 237: {OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN},
! 238: };
! 239:
! 240: VA_ARGS_VGET(args, type, data);
! 241:
! 242: while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data))
! 243: {
! 244: known_oid = asn1_known_oid(oid);
! 245: for (i = 0; i < countof(oid2part); i++)
! 246: {
! 247: if (oid2part[i].oid == known_oid)
! 248: {
! 249: *type = oid2part[i].type;
! 250: *data = inner_data;
! 251: return TRUE;
! 252: }
! 253: }
! 254: }
! 255: return FALSE;
! 256: }
! 257:
! 258: METHOD(enumerator_t, rdn_part_enumerator_destroy, void,
! 259: rdn_part_enumerator_t *this)
! 260: {
! 261: this->inner->destroy(this->inner);
! 262: free(this);
! 263: }
! 264:
! 265: METHOD(identification_t, create_part_enumerator, enumerator_t*,
! 266: private_identification_t *this)
! 267: {
! 268: switch (this->type)
! 269: {
! 270: case ID_DER_ASN1_DN:
! 271: {
! 272: rdn_part_enumerator_t *e;
! 273:
! 274: INIT(e,
! 275: .inner = create_rdn_enumerator(this->encoded),
! 276: .public = {
! 277: .enumerate = enumerator_enumerate_default,
! 278: .venumerate = _rdn_part_enumerate,
! 279: .destroy = _rdn_part_enumerator_destroy,
! 280: },
! 281: );
! 282: return &e->public;
! 283: }
! 284: case ID_RFC822_ADDR:
! 285: /* TODO */
! 286: case ID_FQDN:
! 287: /* TODO */
! 288: default:
! 289: return enumerator_create_empty();
! 290: }
! 291: }
! 292:
! 293: /**
! 294: * Print a separator between two RDNs
! 295: */
! 296: static inline bool print_separator(char **buf, size_t *len)
! 297: {
! 298: int written;
! 299:
! 300: written = snprintf(*buf, *len, ", ");
! 301: if (written < 0 || written >= *len)
! 302: {
! 303: return FALSE;
! 304: }
! 305: *buf += written;
! 306: *len -= written;
! 307: return TRUE;
! 308: }
! 309:
! 310: /**
! 311: * Print a DN with all its RDN in a buffer to present it to the user
! 312: */
! 313: static void dntoa(chunk_t dn, char *buf, size_t len)
! 314: {
! 315: enumerator_t *e;
! 316: chunk_t oid_data, data, printable;
! 317: u_char type;
! 318: int oid, written;
! 319: bool finished = FALSE, empty = TRUE;
! 320:
! 321: e = create_rdn_enumerator(dn);
! 322: while (e->enumerate(e, &oid_data, &type, &data))
! 323: {
! 324: empty = FALSE;
! 325:
! 326: /* previous RDN was empty but it wasn't the last one */
! 327: if (finished && !print_separator(&buf, &len))
! 328: {
! 329: break;
! 330: }
! 331: finished = FALSE;
! 332:
! 333: oid = asn1_known_oid(oid_data);
! 334: if (oid == OID_UNKNOWN)
! 335: {
! 336: written = snprintf(buf, len, "%#B=", &oid_data);
! 337: }
! 338: else
! 339: {
! 340: written = snprintf(buf, len,"%s=", oid_names[oid].name);
! 341: }
! 342: if (written < 0 || written >= len)
! 343: {
! 344: break;
! 345: }
! 346: buf += written;
! 347: len -= written;
! 348:
! 349: written = 0;
! 350: chunk_printable(data, &printable, '?');
! 351: if (printable.ptr)
! 352: {
! 353: written = snprintf(buf, len, "%.*s", (int)printable.len,
! 354: printable.ptr);
! 355: }
! 356: chunk_free(&printable);
! 357: if (written < 0 || written >= len)
! 358: {
! 359: break;
! 360: }
! 361: buf += written;
! 362: len -= written;
! 363:
! 364: if (!data.ptr)
! 365: { /* we can't calculate if we're finished, assume we are */
! 366: finished = TRUE;
! 367: }
! 368: else if (data.ptr + data.len == dn.ptr + dn.len)
! 369: {
! 370: finished = TRUE;
! 371: break;
! 372: }
! 373: else if (!print_separator(&buf, &len))
! 374: {
! 375: break;
! 376: }
! 377: }
! 378: if (empty)
! 379: {
! 380: snprintf(buf, len, "");
! 381: }
! 382: else if (!finished)
! 383: {
! 384: snprintf(buf, len, "(invalid ID_DER_ASN1_DN)");
! 385: }
! 386: e->destroy(e);
! 387: }
! 388:
! 389: /**
! 390: * Converts an LDAP-style human-readable ASCII-encoded
! 391: * ASN.1 distinguished name into binary DER-encoded format
! 392: */
! 393: static status_t atodn(char *src, chunk_t *dn)
! 394: {
! 395: /* finite state machine for atodn */
! 396: typedef enum {
! 397: SEARCH_OID = 0,
! 398: READ_OID = 1,
! 399: SEARCH_NAME = 2,
! 400: READ_NAME = 3,
! 401: UNKNOWN_OID = 4
! 402: } state_t;
! 403:
! 404: chunk_t oid = chunk_empty;
! 405: chunk_t name = chunk_empty;
! 406: chunk_t rdns[RDN_MAX];
! 407: int rdn_count = 0;
! 408: int dn_len = 0;
! 409: int whitespace = 0;
! 410: int i = 0;
! 411: asn1_t rdn_type;
! 412: state_t state = SEARCH_OID;
! 413: status_t status = SUCCESS;
! 414: char sep = '\0';
! 415:
! 416: do
! 417: {
! 418: switch (state)
! 419: {
! 420: case SEARCH_OID:
! 421: if (!sep && *src == '/')
! 422: { /* use / as separator if the string starts with a slash */
! 423: sep = '/';
! 424: break;
! 425: }
! 426: if (*src != ' ' && *src != '\0')
! 427: {
! 428: if (!sep)
! 429: { /* use , as separator by default */
! 430: sep = ',';
! 431: }
! 432: oid.ptr = src;
! 433: oid.len = 1;
! 434: state = READ_OID;
! 435: }
! 436: break;
! 437: case READ_OID:
! 438: if (*src != ' ' && *src != '=')
! 439: {
! 440: oid.len++;
! 441: }
! 442: else
! 443: {
! 444: bool found = FALSE;
! 445:
! 446: for (i = 0; i < countof(x501rdns); i++)
! 447: {
! 448: if (strlen(x501rdns[i].name) == oid.len &&
! 449: strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0)
! 450: {
! 451: found = TRUE;
! 452: break;
! 453: }
! 454: }
! 455: if (!found)
! 456: {
! 457: status = NOT_SUPPORTED;
! 458: state = UNKNOWN_OID;
! 459: break;
! 460: }
! 461: /* reset oid and change state */
! 462: oid = chunk_empty;
! 463: state = SEARCH_NAME;
! 464: }
! 465: break;
! 466: case SEARCH_NAME:
! 467: if (*src == ' ' || *src == '=')
! 468: {
! 469: break;
! 470: }
! 471: else if (*src != sep && *src != '\0')
! 472: {
! 473: name.ptr = src;
! 474: name.len = 1;
! 475: whitespace = 0;
! 476: state = READ_NAME;
! 477: break;
! 478: }
! 479: name = chunk_empty;
! 480: whitespace = 0;
! 481: state = READ_NAME;
! 482: /* fall-through */
! 483: case READ_NAME:
! 484: if (*src != sep && *src != '\0')
! 485: {
! 486: name.len++;
! 487: if (*src == ' ')
! 488: whitespace++;
! 489: else
! 490: whitespace = 0;
! 491: }
! 492: else
! 493: {
! 494: name.len -= whitespace;
! 495: rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING
! 496: && !asn1_is_printablestring(name))
! 497: ? ASN1_UTF8STRING : x501rdns[i].type;
! 498:
! 499: if (rdn_count < RDN_MAX)
! 500: {
! 501: chunk_t rdn_oid;
! 502:
! 503: rdn_oid = asn1_build_known_oid(x501rdns[i].oid);
! 504: if (rdn_oid.len)
! 505: {
! 506: rdns[rdn_count] =
! 507: asn1_wrap(ASN1_SET, "m",
! 508: asn1_wrap(ASN1_SEQUENCE, "mm",
! 509: rdn_oid,
! 510: asn1_wrap(rdn_type, "c", name)
! 511: )
! 512: );
! 513: dn_len += rdns[rdn_count++].len;
! 514: }
! 515: else
! 516: {
! 517: status = INVALID_ARG;
! 518: }
! 519: }
! 520: else
! 521: {
! 522: status = OUT_OF_RES;
! 523: }
! 524: /* reset name and change state */
! 525: name = chunk_empty;
! 526: state = SEARCH_OID;
! 527: }
! 528: break;
! 529: case UNKNOWN_OID:
! 530: break;
! 531: }
! 532: } while (*src++ != '\0');
! 533:
! 534: if (state == READ_OID)
! 535: { /* unterminated OID */
! 536: status = INVALID_ARG;
! 537: }
! 538:
! 539: /* build the distinguished name sequence */
! 540: {
! 541: int i;
! 542: u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len);
! 543:
! 544: for (i = 0; i < rdn_count; i++)
! 545: {
! 546: memcpy(pos, rdns[i].ptr, rdns[i].len);
! 547: pos += rdns[i].len;
! 548: free(rdns[i].ptr);
! 549: }
! 550: }
! 551: if (status != SUCCESS)
! 552: {
! 553: free(dn->ptr);
! 554: *dn = chunk_empty;
! 555: }
! 556: return status;
! 557: }
! 558:
! 559: METHOD(identification_t, get_encoding, chunk_t,
! 560: private_identification_t *this)
! 561: {
! 562: return this->encoded;
! 563: }
! 564:
! 565: METHOD(identification_t, get_type, id_type_t,
! 566: private_identification_t *this)
! 567: {
! 568: return this->type;
! 569: }
! 570:
! 571: /**
! 572: * Check if this is a wildcard value
! 573: */
! 574: static inline bool is_wildcard(chunk_t data)
! 575: {
! 576: return data.len == 1 && data.ptr[0] == '*';
! 577: }
! 578:
! 579: METHOD(identification_t, contains_wildcards_dn, bool,
! 580: private_identification_t *this)
! 581: {
! 582: enumerator_t *enumerator;
! 583: bool contains = FALSE;
! 584: id_part_t type;
! 585: chunk_t data;
! 586:
! 587: enumerator = create_part_enumerator(this);
! 588: while (enumerator->enumerate(enumerator, &type, &data))
! 589: {
! 590: if (is_wildcard(data))
! 591: {
! 592: contains = TRUE;
! 593: break;
! 594: }
! 595: }
! 596: enumerator->destroy(enumerator);
! 597: return contains;
! 598: }
! 599:
! 600: METHOD(identification_t, contains_wildcards_memchr, bool,
! 601: private_identification_t *this)
! 602: {
! 603: return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
! 604: }
! 605:
! 606: METHOD(identification_t, hash_binary, u_int,
! 607: private_identification_t *this, u_int inc)
! 608: {
! 609: u_int hash;
! 610:
! 611: hash = chunk_hash_inc(chunk_from_thing(this->type), inc);
! 612: if (this->type != ID_ANY)
! 613: {
! 614: hash = chunk_hash_inc(this->encoded, hash);
! 615: }
! 616: return hash;
! 617: }
! 618:
! 619: METHOD(identification_t, equals_binary, bool,
! 620: private_identification_t *this, identification_t *other)
! 621: {
! 622: if (this->type == other->get_type(other))
! 623: {
! 624: if (this->type == ID_ANY)
! 625: {
! 626: return TRUE;
! 627: }
! 628: return chunk_equals(this->encoded, other->get_encoding(other));
! 629: }
! 630: return FALSE;
! 631: }
! 632:
! 633: /**
! 634: * Compare two RDNs for equality, comparing some string types case insensitive
! 635: */
! 636: static bool rdn_equals(chunk_t oid, u_char a_type, chunk_t a, u_char b_type,
! 637: chunk_t b)
! 638: {
! 639: if (a_type == b_type &&
! 640: (a_type == ASN1_PRINTABLESTRING ||
! 641: (a_type == ASN1_IA5STRING &&
! 642: asn1_known_oid(oid) == OID_EMAIL_ADDRESS)))
! 643: { /* ignore case for printableStrings and email RDNs */
! 644: return strncaseeq(a.ptr, b.ptr, a.len);
! 645: }
! 646: else
! 647: { /* respect case and length for everything else */
! 648: return memeq(a.ptr, b.ptr, a.len);
! 649: }
! 650: }
! 651:
! 652: /**
! 653: * RDNs when matching DNs
! 654: */
! 655: typedef struct {
! 656: chunk_t oid;
! 657: u_char type;
! 658: chunk_t data;
! 659: bool matched;
! 660: } rdn_t;
! 661:
! 662: /**
! 663: * Match DNs (o_dn may contain wildcards and RDNs in a different order, if
! 664: * allow_unmatched is TRUE, t_dn may contain unmatched RDNs)
! 665: */
! 666: static bool match_dn(chunk_t t_dn, chunk_t o_dn, int *wc, bool allow_unmatched)
! 667: {
! 668: enumerator_t *enumerator;
! 669: array_t *rdns;
! 670: rdn_t *rdn, *found;
! 671: chunk_t oid, data;
! 672: u_char type;
! 673: bool finished = FALSE;
! 674: int i, regular = 0;
! 675:
! 676: *wc = 0;
! 677:
! 678: /* try a binary compare */
! 679: if (chunk_equals(t_dn, o_dn))
! 680: {
! 681: return TRUE;
! 682: }
! 683:
! 684: rdns = array_create(0, 8);
! 685:
! 686: enumerator = create_rdn_enumerator(o_dn);
! 687: while (TRUE)
! 688: {
! 689: if (!enumerator->enumerate(enumerator, &oid, &type, &data))
! 690: {
! 691: break;
! 692: }
! 693: INIT(rdn,
! 694: .oid = oid,
! 695: .type = type,
! 696: .data = data,
! 697: );
! 698: if (is_wildcard(data))
! 699: {
! 700: /* insert wildcards at the end, to perform exact matches first */
! 701: array_insert(rdns, ARRAY_TAIL, rdn);
! 702: }
! 703: else
! 704: {
! 705: array_insert(rdns, regular++, rdn);
! 706: }
! 707: /* the enumerator returns FALSE on parse error, we are finished
! 708: * if we have reached the end of the DN only */
! 709: if ((data.ptr + data.len == o_dn.ptr + o_dn.len))
! 710: {
! 711: finished = TRUE;
! 712: }
! 713: }
! 714: enumerator->destroy(enumerator);
! 715:
! 716: if (!finished)
! 717: { /* invalid DN */
! 718: array_destroy_function(rdns, (void*)free, NULL);
! 719: return FALSE;
! 720: }
! 721: finished = FALSE;
! 722:
! 723: enumerator = create_rdn_enumerator(t_dn);
! 724: while (TRUE)
! 725: {
! 726: if (!enumerator->enumerate(enumerator, &oid, &type, &data))
! 727: {
! 728: break;
! 729: }
! 730: for (i = 0, found = NULL; i < array_count(rdns); i++)
! 731: {
! 732: array_get(rdns, i, &rdn);
! 733: if (!rdn->matched && chunk_equals(rdn->oid, oid))
! 734: {
! 735: if (is_wildcard(rdn->data))
! 736: {
! 737: (*wc)++;
! 738: }
! 739: else if (data.len != rdn->data.len ||
! 740: !rdn_equals(oid, type, data, rdn->type, rdn->data))
! 741: {
! 742: continue;
! 743: }
! 744: rdn->matched = TRUE;
! 745: found = rdn;
! 746: break;
! 747: }
! 748: }
! 749: if (!found)
! 750: {
! 751: /* treat unmatched RDNs like wildcards if allowed */
! 752: if (!allow_unmatched)
! 753: {
! 754: break;
! 755: }
! 756: (*wc)++;
! 757: }
! 758: /* the enumerator returns FALSE on parse error, we are finished
! 759: * if we have reached the end of the DN only */
! 760: if ((data.ptr + data.len == t_dn.ptr + t_dn.len))
! 761: {
! 762: finished = TRUE;
! 763: }
! 764: }
! 765: enumerator->destroy(enumerator);
! 766:
! 767: if (finished)
! 768: {
! 769: for (i = 0; i < array_count(rdns); i++)
! 770: {
! 771: array_get(rdns, i, &rdn);
! 772: if (!rdn->matched)
! 773: {
! 774: finished = FALSE;
! 775: }
! 776: }
! 777: }
! 778: array_destroy_function(rdns, (void*)free, NULL);
! 779: return finished;
! 780: }
! 781:
! 782: /**
! 783: * Reordered RDNs are fine, but match all
! 784: */
! 785: static bool match_dn_reordered(chunk_t t_dn, chunk_t o_dn, int *wc)
! 786: {
! 787: return match_dn(t_dn, o_dn, wc, FALSE);
! 788: }
! 789:
! 790: /**
! 791: * t_dn may contain more RDNs than o_dn
! 792: */
! 793: static bool match_dn_relaxed(chunk_t t_dn, chunk_t o_dn, int *wc)
! 794: {
! 795: return match_dn(t_dn, o_dn, wc, TRUE);
! 796: }
! 797:
! 798: /**
! 799: * Compare two DNs, for equality if wc == NULL, with wildcard matching otherwise
! 800: */
! 801: static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc)
! 802: {
! 803: enumerator_t *t, *o;
! 804: chunk_t t_oid, o_oid, t_data, o_data;
! 805: u_char t_type, o_type;
! 806: bool t_next, o_next, finished = FALSE;
! 807:
! 808: if (wc)
! 809: {
! 810: *wc = 0;
! 811: }
! 812: else if (t_dn.len != o_dn.len)
! 813: {
! 814: return FALSE;
! 815: }
! 816:
! 817: if (chunk_equals(t_dn, o_dn))
! 818: {
! 819: return TRUE;
! 820: }
! 821:
! 822: t = create_rdn_enumerator(t_dn);
! 823: o = create_rdn_enumerator(o_dn);
! 824: while (TRUE)
! 825: {
! 826: t_next = t->enumerate(t, &t_oid, &t_type, &t_data);
! 827: o_next = o->enumerate(o, &o_oid, &o_type, &o_data);
! 828:
! 829: if (!o_next && !t_next)
! 830: {
! 831: break;
! 832: }
! 833: finished = FALSE;
! 834: if (o_next != t_next)
! 835: {
! 836: break;
! 837: }
! 838: if (!chunk_equals(t_oid, o_oid))
! 839: {
! 840: break;
! 841: }
! 842: if (wc && is_wildcard(o_data))
! 843: {
! 844: (*wc)++;
! 845: }
! 846: else
! 847: {
! 848: if (t_data.len != o_data.len)
! 849: {
! 850: break;
! 851: }
! 852: if (!rdn_equals(t_oid, t_type, t_data, o_type, o_data))
! 853: {
! 854: break;
! 855: }
! 856: }
! 857: /* the enumerator returns FALSE on parse error, we are finished
! 858: * if we have reached the end of the DN only */
! 859: if ((t_data.ptr + t_data.len == t_dn.ptr + t_dn.len) &&
! 860: (o_data.ptr + o_data.len == o_dn.ptr + o_dn.len))
! 861: {
! 862: finished = TRUE;
! 863: }
! 864: }
! 865: t->destroy(t);
! 866: o->destroy(o);
! 867: return finished;
! 868: }
! 869:
! 870: METHOD(identification_t, equals_dn, bool,
! 871: private_identification_t *this, identification_t *other)
! 872: {
! 873: return compare_dn(this->encoded, other->get_encoding(other), NULL);
! 874: }
! 875:
! 876: METHOD(identification_t, hash_dn, u_int,
! 877: private_identification_t *this, u_int inc)
! 878: {
! 879: enumerator_t *rdns;
! 880: chunk_t oid, data;
! 881: u_char type;
! 882: u_int hash;
! 883:
! 884: hash = chunk_hash_inc(chunk_from_thing(this->type), inc);
! 885: rdns = create_rdn_enumerator(this->encoded);
! 886: while (rdns->enumerate(rdns, &oid, &type, &data))
! 887: {
! 888: hash = chunk_hash_inc(data, chunk_hash_inc(oid, hash));
! 889: }
! 890: rdns->destroy(rdns);
! 891: return hash;
! 892: }
! 893:
! 894: METHOD(identification_t, equals_strcasecmp, bool,
! 895: private_identification_t *this, identification_t *other)
! 896: {
! 897: chunk_t encoded = other->get_encoding(other);
! 898:
! 899: /* we do some extra sanity checks to check for invalid IDs with a
! 900: * terminating null in it. */
! 901: if (this->type == other->get_type(other) &&
! 902: this->encoded.len == encoded.len &&
! 903: memchr(this->encoded.ptr, 0, this->encoded.len) == NULL &&
! 904: memchr(encoded.ptr, 0, encoded.len) == NULL &&
! 905: strncasecmp(this->encoded.ptr, encoded.ptr, this->encoded.len) == 0)
! 906: {
! 907: return TRUE;
! 908: }
! 909: return FALSE;
! 910: }
! 911:
! 912: METHOD(identification_t, matches_binary, id_match_t,
! 913: private_identification_t *this, identification_t *other)
! 914: {
! 915: if (other->get_type(other) == ID_ANY)
! 916: {
! 917: return ID_MATCH_ANY;
! 918: }
! 919: if (this->type == other->get_type(other) &&
! 920: chunk_equals(this->encoded, other->get_encoding(other)))
! 921: {
! 922: return ID_MATCH_PERFECT;
! 923: }
! 924: return ID_MATCH_NONE;
! 925: }
! 926:
! 927: METHOD(identification_t, matches_string, id_match_t,
! 928: private_identification_t *this, identification_t *other)
! 929: {
! 930: chunk_t encoded = other->get_encoding(other);
! 931: u_int len = encoded.len;
! 932:
! 933: if (other->get_type(other) == ID_ANY)
! 934: {
! 935: return ID_MATCH_ANY;
! 936: }
! 937: if (this->type != other->get_type(other))
! 938: {
! 939: return ID_MATCH_NONE;
! 940: }
! 941: /* try a equals check first */
! 942: if (equals_strcasecmp(this, other))
! 943: {
! 944: return ID_MATCH_PERFECT;
! 945: }
! 946: if (len == 0 || this->encoded.len < len)
! 947: {
! 948: return ID_MATCH_NONE;
! 949: }
! 950:
! 951: /* check for single wildcard at the head of the string */
! 952: if (*encoded.ptr == '*')
! 953: {
! 954: /* single asterisk matches any string */
! 955: if (len-- == 1)
! 956: { /* not better than ID_ANY */
! 957: return ID_MATCH_ANY;
! 958: }
! 959: if (strncasecmp(this->encoded.ptr + this->encoded.len - len,
! 960: encoded.ptr + 1, len) == 0)
! 961: {
! 962: return ID_MATCH_ONE_WILDCARD;
! 963: }
! 964: }
! 965: return ID_MATCH_NONE;
! 966: }
! 967:
! 968: METHOD(identification_t, matches_any, id_match_t,
! 969: private_identification_t *this, identification_t *other)
! 970: {
! 971: if (other->get_type(other) == ID_ANY)
! 972: {
! 973: return ID_MATCH_ANY;
! 974: }
! 975: return ID_MATCH_NONE;
! 976: }
! 977:
! 978: /**
! 979: * Match DNs given the matching function
! 980: */
! 981: static id_match_t matches_dn_internal(private_identification_t *this,
! 982: identification_t *other,
! 983: bool (*match)(chunk_t,chunk_t,int*))
! 984: {
! 985: int wc;
! 986:
! 987: if (other->get_type(other) == ID_ANY)
! 988: {
! 989: return ID_MATCH_ANY;
! 990: }
! 991:
! 992: if (this->type == other->get_type(other))
! 993: {
! 994: if (match(this->encoded, other->get_encoding(other), &wc))
! 995: {
! 996: wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS);
! 997: return ID_MATCH_PERFECT - wc;
! 998: }
! 999: }
! 1000: return ID_MATCH_NONE;
! 1001: }
! 1002:
! 1003: METHOD(identification_t, matches_dn, id_match_t,
! 1004: private_identification_t *this, identification_t *other)
! 1005: {
! 1006: return matches_dn_internal(this, other, compare_dn);
! 1007: }
! 1008:
! 1009: METHOD(identification_t, matches_dn_reordered, id_match_t,
! 1010: private_identification_t *this, identification_t *other)
! 1011: {
! 1012: return matches_dn_internal(this, other, match_dn_reordered);
! 1013: }
! 1014:
! 1015: METHOD(identification_t, matches_dn_relaxed, id_match_t,
! 1016: private_identification_t *this, identification_t *other)
! 1017: {
! 1018: return matches_dn_internal(this, other, match_dn_relaxed);
! 1019: }
! 1020:
! 1021: /**
! 1022: * Transform netmask to CIDR bits
! 1023: */
! 1024: static int netmask_to_cidr(char *netmask, size_t address_size)
! 1025: {
! 1026: uint8_t byte;
! 1027: int i, netbits = 0;
! 1028:
! 1029: for (i = 0; i < address_size; i++)
! 1030: {
! 1031: byte = netmask[i];
! 1032:
! 1033: if (byte == 0x00)
! 1034: {
! 1035: break;
! 1036: }
! 1037: if (byte == 0xff)
! 1038: {
! 1039: netbits += 8;
! 1040: }
! 1041: else
! 1042: {
! 1043: while (byte & 0x80)
! 1044: {
! 1045: netbits++;
! 1046: byte <<= 1;
! 1047: }
! 1048: }
! 1049: }
! 1050: return netbits;
! 1051: }
! 1052:
! 1053: METHOD(identification_t, matches_range, id_match_t,
! 1054: private_identification_t *this, identification_t *other)
! 1055: {
! 1056: chunk_t other_encoding;
! 1057: uint8_t *address, *from, *to, *network, *netmask;
! 1058: size_t address_size = 0;
! 1059: int netbits, range_sign, i;
! 1060:
! 1061: if (other->get_type(other) == ID_ANY)
! 1062: {
! 1063: return ID_MATCH_ANY;
! 1064: }
! 1065: if (this->type == other->get_type(other) &&
! 1066: chunk_equals(this->encoded, other->get_encoding(other)))
! 1067: {
! 1068: return ID_MATCH_PERFECT;
! 1069: }
! 1070: if ((this->type == ID_IPV4_ADDR &&
! 1071: other->get_type(other) == ID_IPV4_ADDR_SUBNET))
! 1072: {
! 1073: address_size = sizeof(struct in_addr);
! 1074: }
! 1075: else if ((this->type == ID_IPV6_ADDR &&
! 1076: other->get_type(other) == ID_IPV6_ADDR_SUBNET))
! 1077: {
! 1078: address_size = sizeof(struct in6_addr);
! 1079: }
! 1080: if (address_size)
! 1081: {
! 1082: other_encoding = other->get_encoding(other);
! 1083: if (this->encoded.len != address_size ||
! 1084: other_encoding.len != 2 * address_size)
! 1085: {
! 1086: return ID_MATCH_NONE;
! 1087: }
! 1088: address = this->encoded.ptr;
! 1089: network = other_encoding.ptr;
! 1090: netmask = other_encoding.ptr + address_size;
! 1091: netbits = netmask_to_cidr(netmask, address_size);
! 1092:
! 1093: if (netbits == 0)
! 1094: {
! 1095: return ID_MATCH_MAX_WILDCARDS;
! 1096: }
! 1097: if (netbits == 8 * address_size)
! 1098: {
! 1099: return memeq(address, network, address_size) ?
! 1100: ID_MATCH_PERFECT : ID_MATCH_NONE;
! 1101: }
! 1102: for (i = 0; i < (netbits + 7)/8; i++)
! 1103: {
! 1104: if ((address[i] ^ network[i]) & netmask[i])
! 1105: {
! 1106: return ID_MATCH_NONE;
! 1107: }
! 1108: }
! 1109: return ID_MATCH_ONE_WILDCARD;
! 1110: }
! 1111: if ((this->type == ID_IPV4_ADDR &&
! 1112: other->get_type(other) == ID_IPV4_ADDR_RANGE))
! 1113: {
! 1114: address_size = sizeof(struct in_addr);
! 1115: }
! 1116: else if ((this->type == ID_IPV6_ADDR &&
! 1117: other->get_type(other) == ID_IPV6_ADDR_RANGE))
! 1118: {
! 1119: address_size = sizeof(struct in6_addr);
! 1120: }
! 1121: if (address_size)
! 1122: {
! 1123: other_encoding = other->get_encoding(other);
! 1124: if (this->encoded.len != address_size ||
! 1125: other_encoding.len != 2 * address_size)
! 1126: {
! 1127: return ID_MATCH_NONE;
! 1128: }
! 1129: address = this->encoded.ptr;
! 1130: from = other_encoding.ptr;
! 1131: to = other_encoding.ptr + address_size;
! 1132:
! 1133: range_sign = memcmp(to, from, address_size);
! 1134: if (range_sign < 0)
! 1135: { /* to is smaller than from */
! 1136: return ID_MATCH_NONE;
! 1137: }
! 1138:
! 1139: /* check lower bound */
! 1140: for (i = 0; i < address_size; i++)
! 1141: {
! 1142: if (address[i] != from[i])
! 1143: {
! 1144: if (address[i] < from[i])
! 1145: {
! 1146: return ID_MATCH_NONE;
! 1147: }
! 1148: break;
! 1149: }
! 1150: }
! 1151:
! 1152: /* check upper bound */
! 1153: for (i = 0; i < address_size; i++)
! 1154: {
! 1155: if (address[i] != to[i])
! 1156: {
! 1157: if (address[i] > to[i])
! 1158: {
! 1159: return ID_MATCH_NONE;
! 1160: }
! 1161: break;
! 1162: }
! 1163: }
! 1164: return range_sign ? ID_MATCH_ONE_WILDCARD : ID_MATCH_PERFECT;
! 1165: }
! 1166: return ID_MATCH_NONE;
! 1167: }
! 1168:
! 1169: /**
! 1170: * Described in header.
! 1171: */
! 1172: int identification_printf_hook(printf_hook_data_t *data,
! 1173: printf_hook_spec_t *spec, const void *const *args)
! 1174: {
! 1175: private_identification_t *this = *((private_identification_t**)(args[0]));
! 1176: chunk_t proper;
! 1177: char buf[BUF_LEN], *pos;
! 1178: size_t len, address_size;
! 1179: int written;
! 1180:
! 1181: if (this == NULL)
! 1182: {
! 1183: return print_in_hook(data, "%*s", spec->width, "(null)");
! 1184: }
! 1185:
! 1186: switch (this->type)
! 1187: {
! 1188: case ID_ANY:
! 1189: snprintf(buf, BUF_LEN, "%%any");
! 1190: break;
! 1191: case ID_IPV4_ADDR:
! 1192: if (this->encoded.len < sizeof(struct in_addr) ||
! 1193: inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
! 1194: {
! 1195: snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR)");
! 1196: }
! 1197: break;
! 1198: case ID_IPV4_ADDR_SUBNET:
! 1199: address_size = sizeof(struct in_addr);
! 1200: if (this->encoded.len < 2 * address_size ||
! 1201: inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
! 1202: {
! 1203: snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_SUBNET)");
! 1204: break;
! 1205: }
! 1206: written = strlen(buf);
! 1207: snprintf(buf + written, BUF_LEN - written, "/%d",
! 1208: netmask_to_cidr(this->encoded.ptr + address_size,
! 1209: address_size));
! 1210: break;
! 1211: case ID_IPV4_ADDR_RANGE:
! 1212: address_size = sizeof(struct in_addr);
! 1213: if (this->encoded.len < 2 * address_size ||
! 1214: inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
! 1215: {
! 1216: snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)");
! 1217: break;
! 1218: }
! 1219: written = strlen(buf);
! 1220: pos = buf + written;
! 1221: len = BUF_LEN - written;
! 1222: written = snprintf(pos, len, "-");
! 1223: if (written < 0 || written >= len ||
! 1224: inet_ntop(AF_INET, this->encoded.ptr + address_size,
! 1225: pos + written, len - written) == NULL)
! 1226: {
! 1227: snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)");
! 1228: }
! 1229: break;
! 1230: case ID_IPV6_ADDR:
! 1231: if (this->encoded.len < sizeof(struct in6_addr) ||
! 1232: inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
! 1233: {
! 1234: snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR)");
! 1235: }
! 1236: break;
! 1237: case ID_IPV6_ADDR_SUBNET:
! 1238: address_size = sizeof(struct in6_addr);
! 1239: if (this->encoded.len < 2 * address_size ||
! 1240: inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
! 1241: {
! 1242: snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_SUBNET)");
! 1243: }
! 1244: else
! 1245: {
! 1246: written = strlen(buf);
! 1247: snprintf(buf + written, BUF_LEN - written, "/%d",
! 1248: netmask_to_cidr(this->encoded.ptr + address_size,
! 1249: address_size));
! 1250: }
! 1251: break;
! 1252: case ID_IPV6_ADDR_RANGE:
! 1253: address_size = sizeof(struct in6_addr);
! 1254: if (this->encoded.len < 2 * address_size ||
! 1255: inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
! 1256: {
! 1257: snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)");
! 1258: break;
! 1259: }
! 1260: written = strlen(buf);
! 1261: pos = buf + written;
! 1262: len = BUF_LEN - written;
! 1263: written = snprintf(pos, len, "-");
! 1264: if (written < 0 || written >= len ||
! 1265: inet_ntop(AF_INET6, this->encoded.ptr + address_size,
! 1266: pos + written, len - written) == NULL)
! 1267: {
! 1268: snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)");
! 1269: }
! 1270: break;
! 1271: case ID_FQDN:
! 1272: case ID_RFC822_ADDR:
! 1273: case ID_DER_ASN1_GN_URI:
! 1274: chunk_printable(this->encoded, &proper, '?');
! 1275: snprintf(buf, BUF_LEN, "%.*s", (int)proper.len, proper.ptr);
! 1276: chunk_free(&proper);
! 1277: break;
! 1278: case ID_DER_ASN1_DN:
! 1279: dntoa(this->encoded, buf, BUF_LEN);
! 1280: break;
! 1281: case ID_DER_ASN1_GN:
! 1282: snprintf(buf, BUF_LEN, "(ASN.1 general name)");
! 1283: break;
! 1284: case ID_KEY_ID:
! 1285: if (chunk_printable(this->encoded, NULL, '?') &&
! 1286: this->encoded.len != HASH_SIZE_SHA1)
! 1287: { /* fully printable, use ascii version */
! 1288: snprintf(buf, BUF_LEN, "%.*s", (int)this->encoded.len,
! 1289: this->encoded.ptr);
! 1290: }
! 1291: else
! 1292: { /* not printable, hex dump */
! 1293: snprintf(buf, BUF_LEN, "%#B", &this->encoded);
! 1294: }
! 1295: break;
! 1296: default:
! 1297: snprintf(buf, BUF_LEN, "(unknown ID type: %d)", this->type);
! 1298: break;
! 1299: }
! 1300: if (spec->minus)
! 1301: {
! 1302: return print_in_hook(data, "%-*s", spec->width, buf);
! 1303: }
! 1304: return print_in_hook(data, "%*s", spec->width, buf);
! 1305: }
! 1306:
! 1307: METHOD(identification_t, clone_, identification_t*,
! 1308: private_identification_t *this)
! 1309: {
! 1310: private_identification_t *clone = malloc_thing(private_identification_t);
! 1311:
! 1312: memcpy(clone, this, sizeof(private_identification_t));
! 1313: if (this->encoded.len)
! 1314: {
! 1315: clone->encoded = chunk_clone(this->encoded);
! 1316: }
! 1317: return &clone->public;
! 1318: }
! 1319:
! 1320: METHOD(identification_t, destroy, void,
! 1321: private_identification_t *this)
! 1322: {
! 1323: chunk_free(&this->encoded);
! 1324: free(this);
! 1325: }
! 1326:
! 1327: /**
! 1328: * Generic constructor used for the other constructors.
! 1329: */
! 1330: static private_identification_t *identification_create(id_type_t type)
! 1331: {
! 1332: private_identification_t *this;
! 1333: char *rdn_matching;
! 1334:
! 1335: INIT(this,
! 1336: .public = {
! 1337: .get_encoding = _get_encoding,
! 1338: .get_type = _get_type,
! 1339: .create_part_enumerator = _create_part_enumerator,
! 1340: .clone = _clone_,
! 1341: .destroy = _destroy,
! 1342: },
! 1343: .type = type,
! 1344: );
! 1345:
! 1346: switch (type)
! 1347: {
! 1348: case ID_ANY:
! 1349: this->public.hash = _hash_binary;
! 1350: this->public.equals = _equals_binary;
! 1351: this->public.matches = _matches_any;
! 1352: this->public.contains_wildcards = return_true;
! 1353: break;
! 1354: case ID_FQDN:
! 1355: case ID_RFC822_ADDR:
! 1356: this->public.hash = _hash_binary;
! 1357: this->public.equals = _equals_strcasecmp;
! 1358: this->public.matches = _matches_string;
! 1359: this->public.contains_wildcards = _contains_wildcards_memchr;
! 1360: break;
! 1361: case ID_DER_ASN1_DN:
! 1362: this->public.hash = _hash_dn;
! 1363: this->public.equals = _equals_dn;
! 1364: this->public.matches = _matches_dn;
! 1365: this->public.contains_wildcards = _contains_wildcards_dn;
! 1366: /* check for more relaxed matching config */
! 1367: rdn_matching = lib->settings->get_str(lib->settings,
! 1368: "%s.rdn_matching", NULL, lib->ns);
! 1369: if (streq("reordered", rdn_matching))
! 1370: {
! 1371: this->public.matches = _matches_dn_reordered;
! 1372: }
! 1373: else if (streq("relaxed", rdn_matching))
! 1374: {
! 1375: this->public.matches = _matches_dn_relaxed;
! 1376: }
! 1377: break;
! 1378: case ID_IPV4_ADDR:
! 1379: case ID_IPV6_ADDR:
! 1380: this->public.hash = _hash_binary;
! 1381: this->public.equals = _equals_binary;
! 1382: this->public.matches = _matches_range;
! 1383: this->public.contains_wildcards = return_false;
! 1384: break;
! 1385: default:
! 1386: this->public.hash = _hash_binary;
! 1387: this->public.equals = _equals_binary;
! 1388: this->public.matches = _matches_binary;
! 1389: this->public.contains_wildcards = return_false;
! 1390: break;
! 1391: }
! 1392: return this;
! 1393: }
! 1394:
! 1395: /**
! 1396: * Create an identity for a specific type, determined by prefix
! 1397: */
! 1398: static private_identification_t* create_from_string_with_prefix_type(char *str)
! 1399: {
! 1400: struct {
! 1401: const char *str;
! 1402: id_type_t type;
! 1403: } prefixes[] = {
! 1404: { "ipv4:", ID_IPV4_ADDR },
! 1405: { "ipv6:", ID_IPV6_ADDR },
! 1406: { "ipv4net:", ID_IPV4_ADDR_SUBNET },
! 1407: { "ipv6net:", ID_IPV6_ADDR_SUBNET },
! 1408: { "ipv4range:", ID_IPV4_ADDR_RANGE },
! 1409: { "ipv6range:", ID_IPV6_ADDR_RANGE },
! 1410: { "rfc822:", ID_RFC822_ADDR },
! 1411: { "email:", ID_RFC822_ADDR },
! 1412: { "userfqdn:", ID_USER_FQDN },
! 1413: { "fqdn:", ID_FQDN },
! 1414: { "dns:", ID_FQDN },
! 1415: { "asn1dn:", ID_DER_ASN1_DN },
! 1416: { "asn1gn:", ID_DER_ASN1_GN },
! 1417: { "xmppaddr:", ID_DER_ASN1_GN },
! 1418: { "keyid:", ID_KEY_ID },
! 1419: };
! 1420: private_identification_t *this;
! 1421: int i;
! 1422:
! 1423: for (i = 0; i < countof(prefixes); i++)
! 1424: {
! 1425: if (strcasepfx(str, prefixes[i].str))
! 1426: {
! 1427: this = identification_create(prefixes[i].type);
! 1428: str += strlen(prefixes[i].str);
! 1429:
! 1430: if (*str == '#')
! 1431: {
! 1432: this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL);
! 1433: }
! 1434: else
! 1435: {
! 1436: this->encoded = chunk_clone(chunk_from_str(str));
! 1437: }
! 1438:
! 1439: if (prefixes[i].type == ID_DER_ASN1_GN &&
! 1440: strcasepfx(prefixes[i].str, "xmppaddr:"))
! 1441: {
! 1442: this->encoded = asn1_wrap(ASN1_CONTEXT_C_0, "mm",
! 1443: asn1_build_known_oid(OID_XMPP_ADDR),
! 1444: asn1_wrap(ASN1_CONTEXT_C_0, "m",
! 1445: asn1_wrap(ASN1_UTF8STRING, "m",
! 1446: this->encoded)));
! 1447: }
! 1448:
! 1449: return this;
! 1450: }
! 1451: }
! 1452: return NULL;
! 1453: }
! 1454:
! 1455: /**
! 1456: * Create an identity for a specific type, determined by a numerical prefix
! 1457: *
! 1458: * The prefix is of the form "{x}:", where x denotes the numerical identity
! 1459: * type.
! 1460: */
! 1461: static private_identification_t* create_from_string_with_num_type(char *str)
! 1462: {
! 1463: private_identification_t *this;
! 1464: u_long type;
! 1465:
! 1466: if (*str++ != '{')
! 1467: {
! 1468: return NULL;
! 1469: }
! 1470: errno = 0;
! 1471: type = strtoul(str, &str, 0);
! 1472: if (errno || *str++ != '}' || *str++ != ':')
! 1473: {
! 1474: return NULL;
! 1475: }
! 1476: this = identification_create(type);
! 1477: if (*str == '#')
! 1478: {
! 1479: this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL);
! 1480: }
! 1481: else
! 1482: {
! 1483: this->encoded = chunk_clone(chunk_from_str(str));
! 1484: }
! 1485: return this;
! 1486: }
! 1487:
! 1488: /**
! 1489: * Convert to an IPv4/IPv6 host address, subnet or address range
! 1490: */
! 1491: static private_identification_t* create_ip_address_from_string(char *string,
! 1492: bool is_ipv4)
! 1493: {
! 1494: private_identification_t *this;
! 1495: uint8_t encoding[32];
! 1496: uint8_t *str, *pos, *address, *to_address, *netmask;
! 1497: size_t address_size;
! 1498: int bits, bytes, i;
! 1499: bool has_subnet = FALSE, has_range = FALSE;
! 1500:
! 1501: address = encoding;
! 1502: address_size = is_ipv4 ? sizeof(struct in_addr) : sizeof(struct in6_addr);
! 1503:
! 1504: str = strdup(string);
! 1505: pos = strchr(str, '/');
! 1506: if (pos)
! 1507: { /* separate IP address from optional netmask */
! 1508:
! 1509: *pos = '\0';
! 1510: has_subnet = TRUE;
! 1511: }
! 1512: else
! 1513: {
! 1514: pos = strchr(str, '-');
! 1515: if (pos)
! 1516: { /* separate lower address from upper address of IP range */
! 1517: *pos = '\0';
! 1518: has_range = TRUE;
! 1519: }
! 1520: }
! 1521:
! 1522: if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, str, address) != 1)
! 1523: {
! 1524: free(str);
! 1525: return NULL;
! 1526: }
! 1527:
! 1528: if (has_subnet)
! 1529: { /* is IP subnet */
! 1530: bits = atoi(pos + 1);
! 1531: if (bits > 8 * address_size)
! 1532: {
! 1533: free(str);
! 1534: return NULL;
! 1535: }
! 1536: bytes = bits / 8;
! 1537: bits -= 8 * bytes;
! 1538: netmask = encoding + address_size;
! 1539:
! 1540: for (i = 0; i < address_size; i++)
! 1541: {
! 1542: if (bytes)
! 1543: {
! 1544: *netmask = 0xff;
! 1545: bytes--;
! 1546: }
! 1547: else if (bits)
! 1548: {
! 1549: *netmask = 0xff << (8 - bits);
! 1550: bits = 0;
! 1551: }
! 1552: else
! 1553: {
! 1554: *netmask = 0x00;
! 1555: }
! 1556: *address++ &= *netmask++;
! 1557: }
! 1558: this = identification_create(is_ipv4 ? ID_IPV4_ADDR_SUBNET :
! 1559: ID_IPV6_ADDR_SUBNET);
! 1560: this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size));
! 1561: }
! 1562: else if (has_range)
! 1563: { /* is IP range */
! 1564: to_address = encoding + address_size;
! 1565:
! 1566: if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, pos + 1, to_address) != 1)
! 1567: {
! 1568: free(str);
! 1569: return NULL;
! 1570: }
! 1571: for (i = 0; i < address_size; i++)
! 1572: {
! 1573: if (address[i] != to_address[i])
! 1574: {
! 1575: if (address[i] > to_address[i])
! 1576: {
! 1577: free(str);
! 1578: return NULL;
! 1579: }
! 1580: break;
! 1581: }
! 1582: }
! 1583: this = identification_create(is_ipv4 ? ID_IPV4_ADDR_RANGE :
! 1584: ID_IPV6_ADDR_RANGE);
! 1585: this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size));
! 1586: }
! 1587: else
! 1588: { /* is IP host address */
! 1589: this = identification_create(is_ipv4 ? ID_IPV4_ADDR : ID_IPV6_ADDR);
! 1590: this->encoded = chunk_clone(chunk_create(encoding, address_size));
! 1591: }
! 1592: free(str);
! 1593:
! 1594: return this;
! 1595: }
! 1596:
! 1597: /*
! 1598: * Described in header.
! 1599: */
! 1600: identification_t *identification_create_from_string(char *string)
! 1601: {
! 1602: private_identification_t *this;
! 1603: chunk_t encoded;
! 1604:
! 1605: if (string == NULL)
! 1606: {
! 1607: string = "%any";
! 1608: }
! 1609: this = create_from_string_with_prefix_type(string);
! 1610: if (this)
! 1611: {
! 1612: return &this->public;
! 1613: }
! 1614: this = create_from_string_with_num_type(string);
! 1615: if (this)
! 1616: {
! 1617: return &this->public;
! 1618: }
! 1619: if (strchr(string, '=') != NULL)
! 1620: {
! 1621: /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
! 1622: * convert from LDAP style or openssl x509 -subject style to ASN.1 DN
! 1623: */
! 1624: if (atodn(string, &encoded) == SUCCESS)
! 1625: {
! 1626: this = identification_create(ID_DER_ASN1_DN);
! 1627: this->encoded = encoded;
! 1628: }
! 1629: else
! 1630: {
! 1631: this = identification_create(ID_KEY_ID);
! 1632: this->encoded = chunk_from_str(strdup(string));
! 1633: }
! 1634: return &this->public;
! 1635: }
! 1636: else if (strchr(string, '@') == NULL)
! 1637: {
! 1638: if (streq(string, "")
! 1639: || streq(string, "%any")
! 1640: || streq(string, "%any6")
! 1641: || streq(string, "0.0.0.0")
! 1642: || streq(string, "*")
! 1643: || streq(string, "::")
! 1644: || streq(string, "0::0"))
! 1645: {
! 1646: /* any ID will be accepted */
! 1647: this = identification_create(ID_ANY);
! 1648: return &this->public;
! 1649: }
! 1650: else
! 1651: {
! 1652: if (strchr(string, ':') == NULL)
! 1653: {
! 1654: /* IPv4 address or subnet */
! 1655: this = create_ip_address_from_string(string, TRUE);
! 1656: if (!this)
! 1657: { /* not IPv4, mostly FQDN */
! 1658: this = identification_create(ID_FQDN);
! 1659: this->encoded = chunk_from_str(strdup(string));
! 1660: }
! 1661: return &this->public;
! 1662: }
! 1663: else
! 1664: {
! 1665: /* IPv6 address or subnet */
! 1666: this = create_ip_address_from_string(string, FALSE);
! 1667: if (!this)
! 1668: { /* not IPv4/6 fallback to KEY_ID */
! 1669: this = identification_create(ID_KEY_ID);
! 1670: this->encoded = chunk_from_str(strdup(string));
! 1671: }
! 1672: return &this->public;
! 1673: }
! 1674: }
! 1675: }
! 1676: else
! 1677: {
! 1678: if (*string == '@')
! 1679: {
! 1680: string++;
! 1681: if (*string == '#')
! 1682: {
! 1683: this = identification_create(ID_KEY_ID);
! 1684: this->encoded = chunk_from_hex(chunk_from_str(string + 1), NULL);
! 1685: return &this->public;
! 1686: }
! 1687: else if (*string == '@')
! 1688: {
! 1689: this = identification_create(ID_USER_FQDN);
! 1690: this->encoded = chunk_clone(chunk_from_str(string + 1));
! 1691: return &this->public;
! 1692: }
! 1693: else
! 1694: {
! 1695: this = identification_create(ID_FQDN);
! 1696: this->encoded = chunk_clone(chunk_from_str(string));
! 1697: return &this->public;
! 1698: }
! 1699: }
! 1700: else
! 1701: {
! 1702: this = identification_create(ID_RFC822_ADDR);
! 1703: this->encoded = chunk_from_str(strdup(string));
! 1704: return &this->public;
! 1705: }
! 1706: }
! 1707: }
! 1708:
! 1709: /*
! 1710: * Described in header.
! 1711: */
! 1712: identification_t * identification_create_from_data(chunk_t data)
! 1713: {
! 1714: char buf[data.len + 1];
! 1715:
! 1716: if (is_asn1(data))
! 1717: {
! 1718: return identification_create_from_encoding(ID_DER_ASN1_DN, data);
! 1719: }
! 1720: else
! 1721: {
! 1722: /* use string constructor */
! 1723: snprintf(buf, sizeof(buf), "%.*s", (int)data.len, data.ptr);
! 1724: return identification_create_from_string(buf);
! 1725: }
! 1726: }
! 1727:
! 1728: /*
! 1729: * Described in header.
! 1730: */
! 1731: identification_t *identification_create_from_encoding(id_type_t type,
! 1732: chunk_t encoded)
! 1733: {
! 1734: private_identification_t *this = identification_create(type);
! 1735:
! 1736: /* apply encoded chunk */
! 1737: if (type != ID_ANY)
! 1738: {
! 1739: this->encoded = chunk_clone(encoded);
! 1740: }
! 1741: return &(this->public);
! 1742: }
! 1743:
! 1744: /*
! 1745: * Described in header.
! 1746: */
! 1747: identification_t *identification_create_from_sockaddr(sockaddr_t *sockaddr)
! 1748: {
! 1749: switch (sockaddr->sa_family)
! 1750: {
! 1751: case AF_INET:
! 1752: {
! 1753: struct in_addr *addr = &(((struct sockaddr_in*)sockaddr)->sin_addr);
! 1754:
! 1755: return identification_create_from_encoding(ID_IPV4_ADDR,
! 1756: chunk_create((u_char*)addr, sizeof(struct in_addr)));
! 1757: }
! 1758: case AF_INET6:
! 1759: {
! 1760: struct in6_addr *addr = &(((struct sockaddr_in6*)sockaddr)->sin6_addr);
! 1761:
! 1762: return identification_create_from_encoding(ID_IPV6_ADDR,
! 1763: chunk_create((u_char*)addr, sizeof(struct in6_addr)));
! 1764: }
! 1765: default:
! 1766: {
! 1767: private_identification_t *this = identification_create(ID_ANY);
! 1768:
! 1769: return &(this->public);
! 1770: }
! 1771: }
! 1772: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>