Annotation of embedaddon/strongswan/src/libstrongswan/plugins/x509/x509_ac.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2017 Tobias Brunner
! 3: * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
! 4: * Copyright (C) 2003 Martin Berner, Lukas Suter
! 5: * Copyright (C) 2002-2017 Andreas Steffen
! 6: * Copyright (C) 2009 Martin Willi
! 7: * HSR Hochschule fuer Technik Rapperswil
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify it
! 10: * under the terms of the GNU General Public License as published by the
! 11: * Free Software Foundation; either version 2 of the License, or (at your
! 12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 13: *
! 14: * This program is distributed in the hope that it will be useful, but
! 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 17: * for more details.
! 18: */
! 19:
! 20: #include "x509_ac.h"
! 21:
! 22: #include <time.h>
! 23:
! 24: #include <library.h>
! 25: #include <utils/debug.h>
! 26: #include <asn1/oid.h>
! 27: #include <asn1/asn1.h>
! 28: #include <asn1/asn1_parser.h>
! 29: #include <utils/identification.h>
! 30: #include <collections/linked_list.h>
! 31: #include <credentials/certificates/x509.h>
! 32: #include <credentials/keys/private_key.h>
! 33:
! 34: extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob,
! 35: int level0, chunk_t *authKeySerialNumber);
! 36:
! 37: typedef struct private_x509_ac_t private_x509_ac_t;
! 38:
! 39: /**
! 40: * private data of x509_ac_t object
! 41: */
! 42: struct private_x509_ac_t {
! 43:
! 44: /**
! 45: * public functions
! 46: */
! 47: x509_ac_t public;
! 48:
! 49: /**
! 50: * X.509 attribute certificate encoding in ASN.1 DER format
! 51: */
! 52: chunk_t encoding;
! 53:
! 54: /**
! 55: * X.509 attribute certificate body over which signature is computed
! 56: */
! 57: chunk_t certificateInfo;
! 58:
! 59: /**
! 60: * Version of the X.509 attribute certificate
! 61: */
! 62: u_int version;
! 63:
! 64: /**
! 65: * Serial number of the X.509 attribute certificate
! 66: */
! 67: chunk_t serialNumber;
! 68:
! 69: /**
! 70: * ID representing the issuer of the holder certificate
! 71: */
! 72: identification_t *holderIssuer;
! 73:
! 74: /**
! 75: * Serial number of the holder certificate
! 76: */
! 77: identification_t *holderSerial;
! 78:
! 79: /**
! 80: * ID representing the holder
! 81: */
! 82: identification_t *entityName;
! 83:
! 84: /**
! 85: * ID representing the attribute certificate issuer
! 86: */
! 87: identification_t *issuerName;
! 88:
! 89: /**
! 90: * Start time of certificate validity
! 91: */
! 92: time_t notBefore;
! 93:
! 94: /**
! 95: * End time of certificate validity
! 96: */
! 97: time_t notAfter;
! 98:
! 99: /**
! 100: * List of group attributes, as group_t
! 101: */
! 102: linked_list_t *groups;
! 103:
! 104: /**
! 105: * Authority Key Identifier
! 106: */
! 107: chunk_t authKeyIdentifier;
! 108:
! 109: /**
! 110: * Authority Key Serial Number
! 111: */
! 112: chunk_t authKeySerialNumber;
! 113:
! 114: /**
! 115: * No revocation information available
! 116: */
! 117: bool noRevAvail;
! 118:
! 119: /**
! 120: * Signature scheme
! 121: */
! 122: signature_params_t *scheme;
! 123:
! 124: /**
! 125: * Signature
! 126: */
! 127: chunk_t signature;
! 128:
! 129: /**
! 130: * Holder certificate
! 131: */
! 132: certificate_t *holderCert;
! 133:
! 134: /**
! 135: * Signer certificate
! 136: */
! 137: certificate_t *signerCert;
! 138:
! 139: /**
! 140: * Signer private key;
! 141: */
! 142: private_key_t *signerKey;
! 143:
! 144: /**
! 145: * reference count
! 146: */
! 147: refcount_t ref;
! 148: };
! 149:
! 150: /**
! 151: * Group definition, an IETF attribute
! 152: */
! 153: typedef struct {
! 154: /** Attribute type */
! 155: ac_group_type_t type;
! 156: /* attribute value */
! 157: chunk_t value;
! 158: } group_t;
! 159:
! 160: /**
! 161: * Clean up a group entry
! 162: */
! 163: static void group_destroy(group_t *group)
! 164: {
! 165: free(group->value.ptr);
! 166: free(group);
! 167: }
! 168:
! 169: static chunk_t ASN1_noRevAvail_ext = chunk_from_chars(
! 170: 0x30, 0x09,
! 171: 0x06, 0x03,
! 172: 0x55, 0x1d, 0x38,
! 173: 0x04, 0x02,
! 174: 0x05, 0x00
! 175: );
! 176:
! 177: /**
! 178: * declaration of function implemented in x509_cert.c
! 179: */
! 180: extern bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
! 181: linked_list_t *list);
! 182: /**
! 183: * parses a directoryName
! 184: */
! 185: static bool parse_directoryName(chunk_t blob, int level, bool implicit,
! 186: identification_t **name)
! 187: {
! 188: identification_t *directoryName;
! 189: enumerator_t *enumerator;
! 190: bool first = TRUE;
! 191: linked_list_t *list;
! 192:
! 193: list = linked_list_create();
! 194: if (!x509_parse_generalNames(blob, level, implicit, list))
! 195: {
! 196: list->destroy(list);
! 197: return FALSE;
! 198: }
! 199:
! 200: enumerator = list->create_enumerator(list);
! 201: while (enumerator->enumerate(enumerator, &directoryName))
! 202: {
! 203: if (first)
! 204: {
! 205: *name = directoryName;
! 206: first = FALSE;
! 207: }
! 208: else
! 209: {
! 210: DBG1(DBG_ASN, "more than one directory name - first selected");
! 211: directoryName->destroy(directoryName);
! 212: break;
! 213: }
! 214: }
! 215: enumerator->destroy(enumerator);
! 216: list->destroy(list);
! 217:
! 218: if (first)
! 219: {
! 220: DBG1(DBG_ASN, "no directoryName found");
! 221: return FALSE;
! 222: }
! 223: return TRUE;
! 224: }
! 225:
! 226: /**
! 227: * ASN.1 definition of roleSyntax
! 228: */
! 229: static const asn1Object_t roleSyntaxObjects[] =
! 230: {
! 231: { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 232: { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
! 233: ASN1_OBJ }, /* 1 */
! 234: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
! 235: { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ }, /* 3 */
! 236: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 237: };
! 238:
! 239: /**
! 240: * Parses roleSyntax
! 241: */
! 242: static void parse_roleSyntax(chunk_t blob, int level0)
! 243: {
! 244: asn1_parser_t *parser;
! 245: chunk_t object;
! 246: int objectID;
! 247:
! 248: parser = asn1_parser_create(roleSyntaxObjects, blob);
! 249: parser->set_top_level(parser, level0);
! 250:
! 251: while (parser->iterate(parser, &objectID, &object))
! 252: {
! 253: switch (objectID)
! 254: {
! 255: default:
! 256: break;
! 257: }
! 258: }
! 259: parser->destroy(parser);
! 260: }
! 261:
! 262: /**
! 263: * ASN.1 definition of ietfAttrSyntax
! 264: */
! 265: static const asn1Object_t ietfAttrSyntaxObjects[] =
! 266: {
! 267: { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
! 268: { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
! 269: ASN1_BODY }, /* 1 */
! 270: { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
! 271: { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
! 272: { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
! 273: ASN1_BODY }, /* 4 */
! 274: { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
! 275: { 2, "oid", ASN1_OID, ASN1_OPT |
! 276: ASN1_BODY }, /* 6 */
! 277: { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
! 278: { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
! 279: ASN1_BODY }, /* 8 */
! 280: { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
! 281: { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
! 282: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 283: };
! 284: #define IETF_ATTR_OCTETS 4
! 285: #define IETF_ATTR_OID 6
! 286: #define IETF_ATTR_STRING 8
! 287:
! 288: /**
! 289: * Parse group memberships, IETF attributes
! 290: */
! 291: static bool parse_groups(private_x509_ac_t *this, chunk_t encoded, int level0)
! 292: {
! 293: ac_group_type_t type;
! 294: group_t *group;
! 295: asn1_parser_t *parser;
! 296: chunk_t object;
! 297: int objectID;
! 298: bool success;
! 299:
! 300: parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded);
! 301: parser->set_top_level(parser, level0);
! 302: while (parser->iterate(parser, &objectID, &object))
! 303: {
! 304: switch (objectID)
! 305: {
! 306: case IETF_ATTR_OCTETS:
! 307: type = AC_GROUP_TYPE_OCTETS;
! 308: break;
! 309: case IETF_ATTR_OID:
! 310: type = AC_GROUP_TYPE_OID;
! 311: break;
! 312: case IETF_ATTR_STRING:
! 313: type = AC_GROUP_TYPE_STRING;
! 314: break;
! 315: default:
! 316: continue;
! 317: }
! 318: INIT(group,
! 319: .type = type,
! 320: .value = chunk_clone(object),
! 321: );
! 322: this->groups->insert_last(this->groups, group);
! 323: }
! 324: success = parser->success(parser);
! 325: parser->destroy(parser);
! 326:
! 327: return success;
! 328: }
! 329:
! 330: /**
! 331: * ASN.1 definition of an X509 attribute certificate
! 332: */
! 333: static const asn1Object_t acObjects[] =
! 334: {
! 335: { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
! 336: { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
! 337: { 2, "version", ASN1_INTEGER, ASN1_DEF |
! 338: ASN1_BODY }, /* 2 */
! 339: { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
! 340: { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
! 341: { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
! 342: { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
! 343: { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
! 344: ASN1_BODY }, /* 7 */
! 345: { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
! 346: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
! 347: { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
! 348: ASN1_OBJ }, /* 10 */
! 349: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
! 350: { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
! 351: { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */
! 352: { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
! 353: ASN1_BODY }, /* 14 */
! 354: { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
! 355: { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
! 356: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
! 357: { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
! 358: { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
! 359: ASN1_OBJ }, /* 19 */
! 360: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
! 361: { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
! 362: { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
! 363: { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
! 364: { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
! 365: { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
! 366: ASN1_BODY }, /* 25 */
! 367: { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
! 368: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
! 369: { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
! 370: { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
! 371: { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
! 372: { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
! 373: ASN1_BODY }, /* 31 */
! 374: { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
! 375: { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
! 376: { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
! 377: { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
! 378: { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
! 379: { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
! 380: { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
! 381: { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
! 382: { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
! 383: { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
! 384: { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
! 385: { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
! 386: { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
! 387: { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
! 388: { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
! 389: { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
! 390: { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
! 391: { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
! 392: { 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
! 393: ASN1_BODY }, /* 50 */
! 394: { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
! 395: { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
! 396: { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
! 397: { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 54 */
! 398: { 0, "exit", ASN1_EOC, ASN1_EXIT }
! 399: };
! 400: #define AC_OBJ_CERTIFICATE_INFO 1
! 401: #define AC_OBJ_VERSION 2
! 402: #define AC_OBJ_HOLDER_ISSUER 5
! 403: #define AC_OBJ_HOLDER_SERIAL 6
! 404: #define AC_OBJ_ENTITY_NAME 10
! 405: #define AC_OBJ_ISSUER_NAME 19
! 406: #define AC_OBJ_ISSUER 23
! 407: #define AC_OBJ_SIG_ALG 35
! 408: #define AC_OBJ_SERIAL_NUMBER 36
! 409: #define AC_OBJ_NOT_BEFORE 38
! 410: #define AC_OBJ_NOT_AFTER 39
! 411: #define AC_OBJ_ATTRIBUTE_TYPE 42
! 412: #define AC_OBJ_ATTRIBUTE_VALUE 44
! 413: #define AC_OBJ_EXTN_ID 49
! 414: #define AC_OBJ_CRITICAL 50
! 415: #define AC_OBJ_EXTN_VALUE 51
! 416: #define AC_OBJ_ALGORITHM 53
! 417: #define AC_OBJ_SIGNATURE 54
! 418:
! 419: /**
! 420: * Parses an X.509 attribute certificate
! 421: */
! 422: static bool parse_certificate(private_x509_ac_t *this)
! 423: {
! 424: asn1_parser_t *parser;
! 425: chunk_t object;
! 426: int objectID;
! 427: int type = OID_UNKNOWN;
! 428: int extn_oid = OID_UNKNOWN;
! 429: signature_params_t sig_alg = {};
! 430: bool success = FALSE;
! 431: bool critical;
! 432:
! 433: parser = asn1_parser_create(acObjects, this->encoding);
! 434:
! 435: while (parser->iterate(parser, &objectID, &object))
! 436: {
! 437: u_int level = parser->get_level(parser)+1;
! 438:
! 439: switch (objectID)
! 440: {
! 441: case AC_OBJ_CERTIFICATE_INFO:
! 442: this->certificateInfo = object;
! 443: break;
! 444: case AC_OBJ_VERSION:
! 445: this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1;
! 446: DBG2(DBG_ASN, " v%d", this->version);
! 447: if (this->version != 2)
! 448: {
! 449: DBG1(DBG_ASN, "v%d attribute certificates are not "
! 450: "supported", this->version);
! 451: goto end;
! 452: }
! 453: break;
! 454: case AC_OBJ_HOLDER_ISSUER:
! 455: if (!parse_directoryName(object, level, FALSE,
! 456: &this->holderIssuer))
! 457: {
! 458: goto end;
! 459: }
! 460: break;
! 461: case AC_OBJ_HOLDER_SERIAL:
! 462: this->holderSerial = identification_create_from_encoding(
! 463: ID_KEY_ID, object);
! 464: break;
! 465: case AC_OBJ_ENTITY_NAME:
! 466: if (!parse_directoryName(object, level, TRUE,
! 467: &this->entityName))
! 468: {
! 469: goto end;
! 470: }
! 471: break;
! 472: case AC_OBJ_ISSUER_NAME:
! 473: if (!parse_directoryName(object, level, FALSE,
! 474: &this->issuerName))
! 475: {
! 476: goto end;
! 477: }
! 478: break;
! 479: case AC_OBJ_SIG_ALG:
! 480: if (!signature_params_parse(object, level, &sig_alg))
! 481: {
! 482: DBG1(DBG_ASN, " unable to parse signature algorithm");
! 483: goto end;
! 484: }
! 485: break;
! 486: case AC_OBJ_SERIAL_NUMBER:
! 487: this->serialNumber = chunk_clone(object);
! 488: break;
! 489: case AC_OBJ_NOT_BEFORE:
! 490: this->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
! 491: break;
! 492: case AC_OBJ_NOT_AFTER:
! 493: this->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
! 494: break;
! 495: case AC_OBJ_ATTRIBUTE_TYPE:
! 496: type = asn1_known_oid(object);
! 497: break;
! 498: case AC_OBJ_ATTRIBUTE_VALUE:
! 499: {
! 500: switch (type)
! 501: {
! 502: case OID_AUTHENTICATION_INFO:
! 503: DBG2(DBG_ASN, " need to parse authenticationInfo");
! 504: break;
! 505: case OID_ACCESS_IDENTITY:
! 506: DBG2(DBG_ASN, " need to parse accessIdentity");
! 507: break;
! 508: case OID_CHARGING_IDENTITY:
! 509: DBG2(DBG_ASN, " need to parse chargingIdentity");
! 510: break;
! 511: case OID_GROUP:
! 512: DBG2(DBG_ASN, "-- > --");
! 513: if (!parse_groups(this, object, level))
! 514: {
! 515: goto end;
! 516: }
! 517: DBG2(DBG_ASN, "-- < --");
! 518: break;
! 519: case OID_ROLE:
! 520: parse_roleSyntax(object, level);
! 521: break;
! 522: default:
! 523: break;
! 524: }
! 525: break;
! 526: }
! 527: case AC_OBJ_EXTN_ID:
! 528: extn_oid = asn1_known_oid(object);
! 529: break;
! 530: case AC_OBJ_CRITICAL:
! 531: critical = object.len && *object.ptr;
! 532: DBG2(DBG_ASN, " %s",(critical)?"TRUE":"FALSE");
! 533: break;
! 534: case AC_OBJ_EXTN_VALUE:
! 535: {
! 536: switch (extn_oid)
! 537: {
! 538: case OID_CRL_DISTRIBUTION_POINTS:
! 539: DBG2(DBG_ASN, " need to parse crlDistributionPoints");
! 540: break;
! 541: case OID_AUTHORITY_KEY_ID:
! 542: this->authKeyIdentifier =
! 543: x509_parse_authorityKeyIdentifier(object,
! 544: level, &this->authKeySerialNumber);
! 545: break;
! 546: case OID_TARGET_INFORMATION:
! 547: DBG2(DBG_ASN, " need to parse targetInformation");
! 548: break;
! 549: case OID_NO_REV_AVAIL:
! 550: this->noRevAvail = TRUE;
! 551: break;
! 552: default:
! 553: break;
! 554: }
! 555: break;
! 556: }
! 557: case AC_OBJ_ALGORITHM:
! 558: INIT(this->scheme);
! 559: if (!signature_params_parse(object, level, this->scheme))
! 560: {
! 561: DBG1(DBG_ASN, " unable to parse signature algorithm");
! 562: goto end;
! 563: }
! 564: if (!signature_params_equal(this->scheme, &sig_alg))
! 565: {
! 566: DBG1(DBG_ASN, " signature algorithms do not agree");
! 567: goto end;
! 568: }
! 569: break;
! 570: case AC_OBJ_SIGNATURE:
! 571: this->signature = chunk_skip(object, 1);
! 572: break;
! 573: default:
! 574: break;
! 575: }
! 576: }
! 577: success = parser->success(parser);
! 578:
! 579: end:
! 580: parser->destroy(parser);
! 581: signature_params_clear(&sig_alg);
! 582: return success;
! 583: }
! 584:
! 585: /**
! 586: * build directoryName
! 587: */
! 588: static chunk_t build_directoryName(asn1_t tag, chunk_t name)
! 589: {
! 590: return asn1_wrap(tag, "m",
! 591: asn1_simple_object(ASN1_CONTEXT_C_4, name));
! 592: }
! 593:
! 594: /**
! 595: * build holder
! 596: */
! 597: static chunk_t build_holder(private_x509_ac_t *this)
! 598: {
! 599: x509_t* x509 = (x509_t*)this->holderCert;
! 600: identification_t *issuer, *subject;
! 601:
! 602: issuer = this->holderCert->get_issuer(this->holderCert);
! 603: subject = this->holderCert->get_subject(this->holderCert);
! 604:
! 605: return asn1_wrap(ASN1_SEQUENCE, "mm",
! 606: asn1_wrap(ASN1_CONTEXT_C_0, "mm",
! 607: build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)),
! 608: asn1_simple_object(ASN1_INTEGER, x509->get_serial(x509))),
! 609: build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject)));
! 610: }
! 611:
! 612: /**
! 613: * build v2Form
! 614: */
! 615: static chunk_t build_v2_form(private_x509_ac_t *this)
! 616: {
! 617: identification_t *subject;
! 618:
! 619: subject = this->signerCert->get_subject(this->signerCert);
! 620: return asn1_wrap(ASN1_CONTEXT_C_0, "m",
! 621: build_directoryName(ASN1_SEQUENCE,
! 622: subject->get_encoding(subject)));
! 623: }
! 624:
! 625: /**
! 626: * build attrCertValidityPeriod
! 627: */
! 628: static chunk_t build_attr_cert_validity(private_x509_ac_t *this)
! 629: {
! 630: return asn1_wrap(ASN1_SEQUENCE, "mm",
! 631: asn1_from_time(&this->notBefore, ASN1_GENERALIZEDTIME),
! 632: asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME));
! 633: }
! 634:
! 635: /**
! 636: * build attribute type
! 637: */
! 638: static chunk_t build_attribute_type(int type, chunk_t content)
! 639: {
! 640: return asn1_wrap(ASN1_SEQUENCE, "mm",
! 641: asn1_build_known_oid(type),
! 642: asn1_wrap(ASN1_SET, "m", content));
! 643: }
! 644:
! 645: /**
! 646: * build attributes
! 647: */
! 648: static chunk_t build_attributes(private_x509_ac_t *this)
! 649: {
! 650: enumerator_t *enumerator;
! 651: group_t *group;
! 652: chunk_t values;
! 653: size_t size = 0, len;
! 654: u_char *pos;
! 655:
! 656: /* precalculate the total size of all values */
! 657: enumerator = this->groups->create_enumerator(this->groups);
! 658: while (enumerator->enumerate(enumerator, &group))
! 659: {
! 660: len = group->value.len;
! 661: size += 1 + (len > 0) + (len >= 128) +
! 662: (len >= 256) + (len >= 65536) + len;
! 663: }
! 664: enumerator->destroy(enumerator);
! 665:
! 666: pos = asn1_build_object(&values, ASN1_SEQUENCE, size);
! 667:
! 668: enumerator = this->groups->create_enumerator(this->groups);
! 669: while (enumerator->enumerate(enumerator, &group))
! 670: {
! 671: chunk_t attr;
! 672: asn1_t type;
! 673:
! 674: switch (group->type)
! 675: {
! 676: case AC_GROUP_TYPE_OCTETS:
! 677: type = ASN1_OCTET_STRING;
! 678: break;
! 679: case AC_GROUP_TYPE_STRING:
! 680: type = ASN1_UTF8STRING;
! 681: break;
! 682: case AC_GROUP_TYPE_OID:
! 683: type = ASN1_OID;
! 684: break;
! 685: default:
! 686: continue;
! 687: }
! 688: attr = asn1_simple_object(type, group->value);
! 689:
! 690: memcpy(pos, attr.ptr, attr.len);
! 691: pos += attr.len;
! 692: free(attr.ptr);
! 693: }
! 694: enumerator->destroy(enumerator);
! 695:
! 696: return asn1_wrap(ASN1_SEQUENCE, "m",
! 697: build_attribute_type(OID_GROUP,
! 698: asn1_wrap(ASN1_SEQUENCE, "m", values)));
! 699: }
! 700:
! 701: /**
! 702: * build authorityKeyIdentifier
! 703: */
! 704: static chunk_t build_authorityKeyIdentifier(private_x509_ac_t *this)
! 705: {
! 706: chunk_t keyIdentifier = chunk_empty;
! 707: chunk_t authorityCertIssuer;
! 708: chunk_t authorityCertSerialNumber;
! 709: identification_t *issuer;
! 710: public_key_t *public;
! 711: x509_t *x509;
! 712:
! 713: x509 = (x509_t*)this->signerCert;
! 714: issuer = this->signerCert->get_issuer(this->signerCert);
! 715: public = this->signerCert->get_public_key(this->signerCert);
! 716: if (public)
! 717: {
! 718: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyIdentifier))
! 719: {
! 720: this->authKeyIdentifier = chunk_clone(keyIdentifier);
! 721: keyIdentifier = asn1_simple_object(ASN1_CONTEXT_S_0, keyIdentifier);
! 722: }
! 723: public->destroy(public);
! 724: }
! 725: authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1,
! 726: issuer->get_encoding(issuer));
! 727: authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2,
! 728: x509->get_serial(x509));
! 729: return asn1_wrap(ASN1_SEQUENCE, "mm",
! 730: asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
! 731: asn1_wrap(ASN1_OCTET_STRING, "m",
! 732: asn1_wrap(ASN1_SEQUENCE, "mmm",
! 733: keyIdentifier,
! 734: authorityCertIssuer,
! 735: authorityCertSerialNumber
! 736: )
! 737: )
! 738: );
! 739: }
! 740:
! 741: /**
! 742: * build extensions
! 743: */
! 744: static chunk_t build_extensions(private_x509_ac_t *this)
! 745: {
! 746: return asn1_wrap(ASN1_SEQUENCE, "mc",
! 747: build_authorityKeyIdentifier(this),
! 748: ASN1_noRevAvail_ext);
! 749: }
! 750:
! 751: /**
! 752: * build attributeCertificateInfo
! 753: */
! 754: static chunk_t build_attr_cert_info(private_x509_ac_t *this, chunk_t sig_scheme)
! 755: {
! 756: return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm",
! 757: ASN1_INTEGER_1,
! 758: build_holder(this),
! 759: build_v2_form(this),
! 760: sig_scheme,
! 761: asn1_simple_object(ASN1_INTEGER, this->serialNumber),
! 762: build_attr_cert_validity(this),
! 763: build_attributes(this),
! 764: build_extensions(this));
! 765: }
! 766:
! 767: /**
! 768: * build an X.509 attribute certificate
! 769: */
! 770: static bool build_ac(private_x509_ac_t *this, hash_algorithm_t digest_alg)
! 771: {
! 772: chunk_t signatureValue, attributeCertificateInfo, sig_scheme;
! 773: private_key_t *key = this->signerKey;
! 774:
! 775: if (!this->scheme)
! 776: {
! 777: INIT(this->scheme,
! 778: .scheme = signature_scheme_from_oid(
! 779: hasher_signature_algorithm_to_oid(digest_alg,
! 780: key->get_type(key))),
! 781: );
! 782: }
! 783: if (this->scheme->scheme == SIGN_UNKNOWN)
! 784: {
! 785: return FALSE;
! 786: }
! 787: if (!signature_params_build(this->scheme, &sig_scheme))
! 788: {
! 789: return FALSE;
! 790: }
! 791:
! 792: attributeCertificateInfo = build_attr_cert_info(this, sig_scheme);
! 793: if (!key->sign(key, this->scheme->scheme, this->scheme->params,
! 794: attributeCertificateInfo, &signatureValue))
! 795: {
! 796: free(attributeCertificateInfo.ptr);
! 797: free(sig_scheme.ptr);
! 798: return FALSE;
! 799: }
! 800: this->encoding = asn1_wrap(ASN1_SEQUENCE, "mmm",
! 801: attributeCertificateInfo,
! 802: sig_scheme,
! 803: asn1_bitstring("m", signatureValue));
! 804: return TRUE;
! 805: }
! 806:
! 807: METHOD(ac_t, get_serial, chunk_t,
! 808: private_x509_ac_t *this)
! 809: {
! 810: return this->serialNumber;
! 811: }
! 812:
! 813: METHOD(ac_t, get_holderSerial, chunk_t,
! 814: private_x509_ac_t *this)
! 815: {
! 816: if (this->holderSerial)
! 817: {
! 818: return this->holderSerial->get_encoding(this->holderSerial);
! 819: }
! 820: return chunk_empty;
! 821: }
! 822:
! 823: METHOD(ac_t, get_holderIssuer, identification_t*,
! 824: private_x509_ac_t *this)
! 825: {
! 826: return this->holderIssuer;
! 827: }
! 828:
! 829: METHOD(ac_t, get_authKeyIdentifier, chunk_t,
! 830: private_x509_ac_t *this)
! 831: {
! 832: return this->authKeyIdentifier;
! 833: }
! 834:
! 835: CALLBACK(attr_filter, bool,
! 836: void *null, enumerator_t *orig, va_list args)
! 837: {
! 838: group_t *group;
! 839: ac_group_type_t *type;
! 840: chunk_t *out;
! 841:
! 842: VA_ARGS_VGET(args, type, out);
! 843:
! 844: while (orig->enumerate(orig, &group))
! 845: {
! 846: if (group->type == AC_GROUP_TYPE_STRING &&
! 847: !chunk_printable(group->value, NULL, 0))
! 848: { /* skip non-printable strings */
! 849: continue;
! 850: }
! 851: *type = group->type;
! 852: *out = group->value;
! 853: return TRUE;
! 854: }
! 855: return FALSE;
! 856: }
! 857:
! 858: METHOD(ac_t, create_group_enumerator, enumerator_t*,
! 859: private_x509_ac_t *this)
! 860: {
! 861: return enumerator_create_filter(
! 862: this->groups->create_enumerator(this->groups),
! 863: attr_filter, NULL, NULL);
! 864: }
! 865:
! 866: METHOD(certificate_t, get_type, certificate_type_t,
! 867: private_x509_ac_t *this)
! 868: {
! 869: return CERT_X509_AC;
! 870: }
! 871:
! 872: METHOD(certificate_t, get_subject, identification_t*,
! 873: private_x509_ac_t *this)
! 874: {
! 875: if (this->entityName)
! 876: {
! 877: return this->entityName;
! 878: }
! 879: return this->holderSerial;
! 880: }
! 881:
! 882: METHOD(certificate_t, get_issuer, identification_t*,
! 883: private_x509_ac_t *this)
! 884: {
! 885: return this->issuerName;
! 886: }
! 887:
! 888: METHOD(certificate_t, has_subject, id_match_t,
! 889: private_x509_ac_t *this, identification_t *subject)
! 890: {
! 891: id_match_t entity = ID_MATCH_NONE, serial = ID_MATCH_NONE;
! 892:
! 893: if (this->entityName)
! 894: {
! 895: entity = this->entityName->matches(this->entityName, subject);
! 896: }
! 897: if (this->holderSerial)
! 898: {
! 899: serial = this->holderSerial->matches(this->holderSerial, subject);
! 900: }
! 901: return max(entity, serial);
! 902: }
! 903:
! 904: METHOD(certificate_t, has_issuer, id_match_t,
! 905: private_x509_ac_t *this, identification_t *issuer)
! 906: {
! 907: if (issuer->get_type(issuer) == ID_KEY_ID &&
! 908: this->authKeyIdentifier.ptr &&
! 909: chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer)))
! 910: {
! 911: return ID_MATCH_PERFECT;
! 912: }
! 913: return this->issuerName->matches(this->issuerName, issuer);
! 914: }
! 915:
! 916: METHOD(certificate_t, issued_by, bool,
! 917: private_x509_ac_t *this, certificate_t *issuer,
! 918: signature_params_t **scheme)
! 919: {
! 920: public_key_t *key;
! 921: bool valid;
! 922: x509_t *x509 = (x509_t*)issuer;
! 923:
! 924: /* check if issuer is an X.509 AA certificate */
! 925: if (issuer->get_type(issuer) != CERT_X509)
! 926: {
! 927: return FALSE;
! 928: }
! 929: if (!(x509->get_flags(x509) & X509_AA))
! 930: {
! 931: return FALSE;
! 932: }
! 933:
! 934: /* get the public key of the issuer */
! 935: key = issuer->get_public_key(issuer);
! 936:
! 937: /* compare keyIdentifiers if available, otherwise use DNs */
! 938: if (this->authKeyIdentifier.ptr && key)
! 939: {
! 940: chunk_t fingerprint;
! 941:
! 942: if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) ||
! 943: !chunk_equals(fingerprint, this->authKeyIdentifier))
! 944: {
! 945: return FALSE;
! 946: }
! 947: }
! 948: else
! 949: {
! 950: if (!this->issuerName->equals(this->issuerName,
! 951: issuer->get_subject(issuer)))
! 952: {
! 953: return FALSE;
! 954: }
! 955: }
! 956:
! 957: if (!key)
! 958: {
! 959: return FALSE;
! 960: }
! 961: valid = key->verify(key, this->scheme->scheme, this->scheme->params,
! 962: this->certificateInfo, this->signature);
! 963: key->destroy(key);
! 964: if (valid && scheme)
! 965: {
! 966: *scheme = signature_params_clone(this->scheme);
! 967: }
! 968: return valid;
! 969: }
! 970:
! 971: METHOD(certificate_t, get_public_key, public_key_t*,
! 972: private_x509_ac_t *this)
! 973: {
! 974: return NULL;
! 975: }
! 976:
! 977: METHOD(certificate_t, get_ref, certificate_t*,
! 978: private_x509_ac_t *this)
! 979: {
! 980: ref_get(&this->ref);
! 981: return &this->public.interface.certificate;
! 982: }
! 983:
! 984: METHOD(certificate_t, get_validity, bool,
! 985: private_x509_ac_t *this, time_t *when, time_t *not_before, time_t *not_after)
! 986: {
! 987: time_t t = when ? *when : time(NULL);
! 988:
! 989: if (not_before)
! 990: {
! 991: *not_before = this->notBefore;
! 992: }
! 993: if (not_after)
! 994: {
! 995: *not_after = this->notAfter;
! 996: }
! 997: return (t >= this->notBefore && t <= this->notAfter);
! 998: }
! 999:
! 1000: METHOD(certificate_t, get_encoding, bool,
! 1001: private_x509_ac_t *this, cred_encoding_type_t type, chunk_t *encoding)
! 1002: {
! 1003: if (type == CERT_ASN1_DER)
! 1004: {
! 1005: *encoding = chunk_clone(this->encoding);
! 1006: return TRUE;
! 1007: }
! 1008: return lib->encoding->encode(lib->encoding, type, NULL, encoding,
! 1009: CRED_PART_X509_AC_ASN1_DER, this->encoding, CRED_PART_END);
! 1010: }
! 1011:
! 1012: METHOD(certificate_t, equals, bool,
! 1013: private_x509_ac_t *this, certificate_t *other)
! 1014: {
! 1015: chunk_t encoding;
! 1016: bool equal;
! 1017:
! 1018: if ((certificate_t*)this == other)
! 1019: {
! 1020: return TRUE;
! 1021: }
! 1022: if (other->equals == _equals)
! 1023: { /* skip allocation if we have the same implementation */
! 1024: return chunk_equals(this->encoding,
! 1025: ((private_x509_ac_t*)other)->encoding);
! 1026: }
! 1027: if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
! 1028: {
! 1029: return FALSE;
! 1030: }
! 1031: equal = chunk_equals(this->encoding, encoding);
! 1032: free(encoding.ptr);
! 1033: return equal;
! 1034: }
! 1035:
! 1036: METHOD(certificate_t, destroy, void,
! 1037: private_x509_ac_t *this)
! 1038: {
! 1039: if (ref_put(&this->ref))
! 1040: {
! 1041: DESTROY_IF(this->holderIssuer);
! 1042: DESTROY_IF(this->holderSerial);
! 1043: DESTROY_IF(this->entityName);
! 1044: DESTROY_IF(this->issuerName);
! 1045: DESTROY_IF(this->holderCert);
! 1046: DESTROY_IF(this->signerCert);
! 1047: DESTROY_IF(this->signerKey);
! 1048: this->groups->destroy_function(this->groups, (void*)group_destroy);
! 1049: signature_params_destroy(this->scheme);
! 1050: free(this->serialNumber.ptr);
! 1051: free(this->authKeyIdentifier.ptr);
! 1052: free(this->encoding.ptr);
! 1053: free(this);
! 1054: }
! 1055: }
! 1056:
! 1057: /**
! 1058: * create an empty but initialized X.509 attribute certificate
! 1059: */
! 1060: static private_x509_ac_t *create_empty(void)
! 1061: {
! 1062: private_x509_ac_t *this;
! 1063:
! 1064: INIT(this,
! 1065: .public = {
! 1066: .interface = {
! 1067: .certificate = {
! 1068: .get_type = _get_type,
! 1069: .get_subject = _get_subject,
! 1070: .get_issuer = _get_issuer,
! 1071: .has_subject = _has_subject,
! 1072: .has_issuer = _has_issuer,
! 1073: .issued_by = _issued_by,
! 1074: .get_public_key = _get_public_key,
! 1075: .get_validity = _get_validity,
! 1076: .get_encoding = _get_encoding,
! 1077: .equals = _equals,
! 1078: .get_ref = _get_ref,
! 1079: .destroy = _destroy,
! 1080: },
! 1081: .get_serial = _get_serial,
! 1082: .get_holderSerial = _get_holderSerial,
! 1083: .get_holderIssuer = _get_holderIssuer,
! 1084: .get_authKeyIdentifier = _get_authKeyIdentifier,
! 1085: .create_group_enumerator = _create_group_enumerator,
! 1086: },
! 1087: },
! 1088: .groups = linked_list_create(),
! 1089: .ref = 1,
! 1090: );
! 1091:
! 1092: return this;
! 1093: }
! 1094:
! 1095: /**
! 1096: * See header.
! 1097: */
! 1098: x509_ac_t *x509_ac_load(certificate_type_t type, va_list args)
! 1099: {
! 1100: chunk_t blob = chunk_empty;
! 1101:
! 1102: while (TRUE)
! 1103: {
! 1104: switch (va_arg(args, builder_part_t))
! 1105: {
! 1106: case BUILD_BLOB_ASN1_DER:
! 1107: blob = va_arg(args, chunk_t);
! 1108: continue;
! 1109: case BUILD_END:
! 1110: break;
! 1111: default:
! 1112: return NULL;
! 1113: }
! 1114: break;
! 1115: }
! 1116: if (blob.ptr)
! 1117: {
! 1118: private_x509_ac_t *ac = create_empty();
! 1119:
! 1120: ac->encoding = chunk_clone(blob);
! 1121: if (parse_certificate(ac))
! 1122: {
! 1123: return &ac->public;
! 1124: }
! 1125: destroy(ac);
! 1126: }
! 1127: return NULL;
! 1128: }
! 1129:
! 1130: /**
! 1131: * Add groups from a list into AC group memberships
! 1132: */
! 1133: static void add_groups_from_list(private_x509_ac_t *this, linked_list_t *list)
! 1134: {
! 1135: enumerator_t *enumerator;
! 1136: group_t *group;
! 1137: char *name;
! 1138:
! 1139: enumerator = list->create_enumerator(list);
! 1140: while (enumerator->enumerate(enumerator, &name))
! 1141: {
! 1142: INIT(group,
! 1143: .type = AC_GROUP_TYPE_STRING,
! 1144: .value = chunk_clone(chunk_from_str(name)),
! 1145: );
! 1146: this->groups->insert_last(this->groups, group);
! 1147: }
! 1148: enumerator->destroy(enumerator);
! 1149: }
! 1150:
! 1151: /**
! 1152: * See header.
! 1153: */
! 1154: x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args)
! 1155: {
! 1156: hash_algorithm_t digest_alg = HASH_SHA1;
! 1157: private_x509_ac_t *ac;
! 1158:
! 1159: ac = create_empty();
! 1160: while (TRUE)
! 1161: {
! 1162: switch (va_arg(args, builder_part_t))
! 1163: {
! 1164: case BUILD_NOT_BEFORE_TIME:
! 1165: ac->notBefore = va_arg(args, time_t);
! 1166: continue;
! 1167: case BUILD_NOT_AFTER_TIME:
! 1168: ac->notAfter = va_arg(args, time_t);
! 1169: continue;
! 1170: case BUILD_SERIAL:
! 1171: ac->serialNumber = chunk_clone(va_arg(args, chunk_t));
! 1172: continue;
! 1173: case BUILD_AC_GROUP_STRINGS:
! 1174: add_groups_from_list(ac, va_arg(args, linked_list_t*));
! 1175: continue;
! 1176: case BUILD_CERT:
! 1177: ac->holderCert = va_arg(args, certificate_t*);
! 1178: ac->holderCert->get_ref(ac->holderCert);
! 1179: continue;
! 1180: case BUILD_SIGNING_CERT:
! 1181: ac->signerCert = va_arg(args, certificate_t*);
! 1182: ac->signerCert->get_ref(ac->signerCert);
! 1183: continue;
! 1184: case BUILD_SIGNING_KEY:
! 1185: ac->signerKey = va_arg(args, private_key_t*);
! 1186: ac->signerKey->get_ref(ac->signerKey);
! 1187: continue;
! 1188: case BUILD_SIGNATURE_SCHEME:
! 1189: ac->scheme = va_arg(args, signature_params_t*);
! 1190: ac->scheme = signature_params_clone(ac->scheme);
! 1191: continue;
! 1192: case BUILD_DIGEST_ALG:
! 1193: digest_alg = va_arg(args, int);
! 1194: continue;
! 1195: case BUILD_END:
! 1196: break;
! 1197: default:
! 1198: destroy(ac);
! 1199: return NULL;
! 1200: }
! 1201: break;
! 1202: }
! 1203:
! 1204: if (ac->signerKey && ac->holderCert && ac->signerCert &&
! 1205: ac->holderCert->get_type(ac->holderCert) == CERT_X509 &&
! 1206: ac->signerCert->get_type(ac->signerCert) == CERT_X509)
! 1207: {
! 1208: if (build_ac(ac, digest_alg))
! 1209: {
! 1210: return &ac->public;
! 1211: }
! 1212: }
! 1213: destroy(ac);
! 1214: return NULL;
! 1215: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>