Annotation of embedaddon/strongswan/src/pki/commands/self.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2009 Martin Willi
! 3: * Copyright (C) 2015-2019 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #include <time.h>
! 18: #include <errno.h>
! 19:
! 20: #include "pki.h"
! 21:
! 22: #include <collections/linked_list.h>
! 23: #include <credentials/certificates/certificate.h>
! 24: #include <credentials/certificates/x509.h>
! 25: #include <selectors/traffic_selector.h>
! 26: #include <asn1/asn1.h>
! 27:
! 28: /**
! 29: * Free cert policy with OID
! 30: */
! 31: static void destroy_cert_policy(x509_cert_policy_t *policy)
! 32: {
! 33: free(policy->oid.ptr);
! 34: free(policy);
! 35: }
! 36:
! 37: /**
! 38: * Free policy mapping
! 39: */
! 40: static void destroy_policy_mapping(x509_policy_mapping_t *mapping)
! 41: {
! 42: free(mapping->issuer.ptr);
! 43: free(mapping->subject.ptr);
! 44: free(mapping);
! 45: }
! 46:
! 47: /**
! 48: * Create a self signed certificate.
! 49: */
! 50: static int self()
! 51: {
! 52: cred_encoding_type_t form = CERT_ASN1_DER;
! 53: key_type_t type = KEY_ANY;
! 54: hash_algorithm_t digest = HASH_UNKNOWN;
! 55: signature_params_t *scheme = NULL;
! 56: certificate_t *cert = NULL;
! 57: private_key_t *private = NULL;
! 58: public_key_t *public = NULL;
! 59: char *file = NULL, *dn = NULL, *hex = NULL, *error = NULL, *keyid = NULL;
! 60: identification_t *id = NULL;
! 61: linked_list_t *san, *ocsp, *permitted, *excluded, *policies, *mappings;
! 62: linked_list_t *addrblocks;
! 63: int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
! 64: int inhibit_mapping = X509_NO_CONSTRAINT;
! 65: int require_explicit = X509_NO_CONSTRAINT;
! 66: chunk_t serial = chunk_empty;
! 67: chunk_t encoding = chunk_empty;
! 68: chunk_t critical_extension_oid = chunk_empty;
! 69: time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
! 70: char *datenb = NULL, *datena = NULL, *dateform = NULL;
! 71: x509_flag_t flags = 0;
! 72: x509_cert_policy_t *policy = NULL;
! 73: traffic_selector_t *ts;
! 74: char *arg;
! 75: bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
! 76: lib->ns);
! 77:
! 78: san = linked_list_create();
! 79: ocsp = linked_list_create();
! 80: permitted = linked_list_create();
! 81: excluded = linked_list_create();
! 82: policies = linked_list_create();
! 83: mappings = linked_list_create();
! 84: addrblocks = linked_list_create();
! 85:
! 86: while (TRUE)
! 87: {
! 88: switch (command_getopt(&arg))
! 89: {
! 90: case 'h':
! 91: goto usage;
! 92: case 't':
! 93: if (streq(arg, "rsa"))
! 94: {
! 95: type = KEY_RSA;
! 96: }
! 97: else if (streq(arg, "ecdsa"))
! 98: {
! 99: type = KEY_ECDSA;
! 100: }
! 101: else if (streq(arg, "ed25519"))
! 102: {
! 103: type = KEY_ED25519;
! 104: }
! 105: else if (streq(arg, "ed448"))
! 106: {
! 107: type = KEY_ED448;
! 108: }
! 109: else if (streq(arg, "bliss"))
! 110: {
! 111: type = KEY_BLISS;
! 112: }
! 113: else if (streq(arg, "priv"))
! 114: {
! 115: type = KEY_ANY;
! 116: }
! 117: else
! 118: {
! 119: error = "invalid input type";
! 120: goto usage;
! 121: }
! 122: continue;
! 123: case 'g':
! 124: if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
! 125: {
! 126: error = "invalid --digest type";
! 127: goto usage;
! 128: }
! 129: continue;
! 130: case 'R':
! 131: if (streq(arg, "pss"))
! 132: {
! 133: pss = TRUE;
! 134: }
! 135: else if (!streq(arg, "pkcs1"))
! 136: {
! 137: error = "invalid RSA padding";
! 138: goto usage;
! 139: }
! 140: continue;
! 141: case 'i':
! 142: file = arg;
! 143: continue;
! 144: case 'x':
! 145: keyid = arg;
! 146: continue;
! 147: case 'd':
! 148: dn = arg;
! 149: continue;
! 150: case 'a':
! 151: san->insert_last(san, identification_create_from_string(arg));
! 152: continue;
! 153: case 'l':
! 154: lifetime = atoi(arg) * 24 * 60 * 60;
! 155: if (!lifetime)
! 156: {
! 157: error = "invalid --lifetime value";
! 158: goto usage;
! 159: }
! 160: continue;
! 161: case 'D':
! 162: dateform = arg;
! 163: continue;
! 164: case 'F':
! 165: datenb = arg;
! 166: continue;
! 167: case 'T':
! 168: datena = arg;
! 169: continue;
! 170: case 's':
! 171: hex = arg;
! 172: continue;
! 173: case 'b':
! 174: flags |= X509_CA;
! 175: continue;
! 176: case 'p':
! 177: pathlen = atoi(arg);
! 178: continue;
! 179: case 'B':
! 180: ts = parse_ts(arg);
! 181: if (!ts)
! 182: {
! 183: error = "invalid addressBlock";
! 184: goto usage;
! 185: }
! 186: addrblocks->insert_last(addrblocks, ts);
! 187: continue;
! 188: case 'n':
! 189: permitted->insert_last(permitted,
! 190: identification_create_from_string(arg));
! 191: continue;
! 192: case 'N':
! 193: excluded->insert_last(excluded,
! 194: identification_create_from_string(arg));
! 195: continue;
! 196: case 'P':
! 197: {
! 198: chunk_t oid;
! 199:
! 200: oid = asn1_oid_from_string(arg);
! 201: if (!oid.len)
! 202: {
! 203: error = "--cert-policy OID invalid";
! 204: goto usage;
! 205: }
! 206: INIT(policy,
! 207: .oid = oid,
! 208: );
! 209: policies->insert_last(policies, policy);
! 210: continue;
! 211: }
! 212: case 'C':
! 213: if (!policy)
! 214: {
! 215: error = "--cps-uri must follow a --cert-policy";
! 216: goto usage;
! 217: }
! 218: policy->cps_uri = arg;
! 219: continue;
! 220: case 'U':
! 221: if (!policy)
! 222: {
! 223: error = "--user-notice must follow a --cert-policy";
! 224: goto usage;
! 225: }
! 226: policy->unotice_text = arg;
! 227: continue;
! 228: case 'M':
! 229: {
! 230: char *pos = strchr(arg, ':');
! 231: x509_policy_mapping_t *mapping;
! 232: chunk_t subject_oid, issuer_oid;
! 233:
! 234: if (pos)
! 235: {
! 236: *pos++ = '\0';
! 237: issuer_oid = asn1_oid_from_string(arg);
! 238: subject_oid = asn1_oid_from_string(pos);
! 239: }
! 240: if (!pos || !issuer_oid.len || !subject_oid.len)
! 241: {
! 242: error = "--policy-map OIDs invalid";
! 243: goto usage;
! 244: }
! 245: INIT(mapping,
! 246: .issuer = issuer_oid,
! 247: .subject = subject_oid,
! 248: );
! 249: mappings->insert_last(mappings, mapping);
! 250: continue;
! 251: }
! 252: case 'E':
! 253: require_explicit = atoi(arg);
! 254: continue;
! 255: case 'H':
! 256: inhibit_mapping = atoi(arg);
! 257: continue;
! 258: case 'A':
! 259: inhibit_any = atoi(arg);
! 260: continue;
! 261: case 'e':
! 262: if (streq(arg, "serverAuth"))
! 263: {
! 264: flags |= X509_SERVER_AUTH;
! 265: }
! 266: else if (streq(arg, "clientAuth"))
! 267: {
! 268: flags |= X509_CLIENT_AUTH;
! 269: }
! 270: else if (streq(arg, "ikeIntermediate"))
! 271: {
! 272: flags |= X509_IKE_INTERMEDIATE;
! 273: }
! 274: else if (streq(arg, "crlSign"))
! 275: {
! 276: flags |= X509_CRL_SIGN;
! 277: }
! 278: else if (streq(arg, "ocspSigning"))
! 279: {
! 280: flags |= X509_OCSP_SIGNER;
! 281: }
! 282: else if (streq(arg, "msSmartcardLogon"))
! 283: {
! 284: flags |= X509_MS_SMARTCARD_LOGON;
! 285: }
! 286: continue;
! 287: case 'f':
! 288: if (!get_form(arg, &form, CRED_CERTIFICATE))
! 289: {
! 290: error = "invalid output format";
! 291: goto usage;
! 292: }
! 293: continue;
! 294: case 'o':
! 295: ocsp->insert_last(ocsp, arg);
! 296: continue;
! 297: case 'X':
! 298: chunk_free(&critical_extension_oid);
! 299: critical_extension_oid = asn1_oid_from_string(arg);
! 300: continue;
! 301: case EOF:
! 302: break;
! 303: default:
! 304: error = "invalid --self option";
! 305: goto usage;
! 306: }
! 307: break;
! 308: }
! 309:
! 310: if (!dn)
! 311: {
! 312: error = "--dn is required";
! 313: goto usage;
! 314: }
! 315: if (!calculate_lifetime(dateform, datenb, datena, lifetime,
! 316: ¬_before, ¬_after))
! 317: {
! 318: error = "invalid --not-before/after datetime";
! 319: goto usage;
! 320: }
! 321: id = identification_create_from_string(dn);
! 322: if (id->get_type(id) != ID_DER_ASN1_DN)
! 323: {
! 324: error = "supplied --dn is not a distinguished name";
! 325: goto end;
! 326: }
! 327: if (file)
! 328: {
! 329: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
! 330: BUILD_FROM_FILE, file, BUILD_END);
! 331: }
! 332: else if (keyid)
! 333: {
! 334: chunk_t chunk;
! 335:
! 336: chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
! 337: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
! 338: BUILD_PKCS11_KEYID, chunk, BUILD_END);
! 339: free(chunk.ptr);
! 340: }
! 341: else
! 342: {
! 343: chunk_t chunk;
! 344:
! 345: set_file_mode(stdin, CERT_ASN1_DER);
! 346: if (!chunk_from_fd(0, &chunk))
! 347: {
! 348: fprintf(stderr, "%s: ", strerror(errno));
! 349: error = "reading private key failed";
! 350: goto end;
! 351: }
! 352: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
! 353: BUILD_BLOB, chunk, BUILD_END);
! 354: free(chunk.ptr);
! 355: }
! 356: if (!private)
! 357: {
! 358: error = "loading private key failed";
! 359: goto end;
! 360: }
! 361: public = private->get_public_key(private);
! 362: if (!public)
! 363: {
! 364: error = "extracting public key failed";
! 365: goto end;
! 366: }
! 367: if (hex)
! 368: {
! 369: serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
! 370: }
! 371: else
! 372: {
! 373: rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 374:
! 375: if (!rng)
! 376: {
! 377: error = "no random number generator found";
! 378: goto end;
! 379: }
! 380: if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE))
! 381: {
! 382: error = "failed to generate serial number";
! 383: rng->destroy(rng);
! 384: goto end;
! 385: }
! 386: serial.ptr[0] &= 0x7F;
! 387: rng->destroy(rng);
! 388: }
! 389: scheme = get_signature_scheme(private, digest, pss);
! 390: if (!scheme)
! 391: {
! 392: error = "no signature scheme found";
! 393: goto end;
! 394: }
! 395:
! 396: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 397: BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public,
! 398: BUILD_SUBJECT, id, BUILD_NOT_BEFORE_TIME, not_before,
! 399: BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
! 400: BUILD_SIGNATURE_SCHEME, scheme, BUILD_X509_FLAG, flags,
! 401: BUILD_PATHLEN, pathlen, BUILD_SUBJECT_ALTNAMES, san,
! 402: BUILD_ADDRBLOCKS, addrblocks,
! 403: BUILD_OCSP_ACCESS_LOCATIONS, ocsp,
! 404: BUILD_PERMITTED_NAME_CONSTRAINTS, permitted,
! 405: BUILD_EXCLUDED_NAME_CONSTRAINTS, excluded,
! 406: BUILD_CERTIFICATE_POLICIES, policies,
! 407: BUILD_POLICY_MAPPINGS, mappings,
! 408: BUILD_POLICY_REQUIRE_EXPLICIT, require_explicit,
! 409: BUILD_POLICY_INHIBIT_MAPPING, inhibit_mapping,
! 410: BUILD_POLICY_INHIBIT_ANY, inhibit_any,
! 411: BUILD_CRITICAL_EXTENSION, critical_extension_oid,
! 412: BUILD_END);
! 413: if (!cert)
! 414: {
! 415: error = "generating certificate failed";
! 416: goto end;
! 417: }
! 418: if (!cert->get_encoding(cert, form, &encoding))
! 419: {
! 420: error = "encoding certificate failed";
! 421: goto end;
! 422: }
! 423: set_file_mode(stdout, form);
! 424: if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
! 425: {
! 426: error = "writing certificate key failed";
! 427: goto end;
! 428: }
! 429:
! 430: end:
! 431: DESTROY_IF(id);
! 432: DESTROY_IF(cert);
! 433: DESTROY_IF(public);
! 434: DESTROY_IF(private);
! 435: san->destroy_offset(san, offsetof(identification_t, destroy));
! 436: permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
! 437: excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
! 438: addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
! 439: policies->destroy_function(policies, (void*)destroy_cert_policy);
! 440: mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
! 441: ocsp->destroy(ocsp);
! 442: signature_params_destroy(scheme);
! 443: free(critical_extension_oid.ptr);
! 444: free(encoding.ptr);
! 445: free(serial.ptr);
! 446:
! 447: if (error)
! 448: {
! 449: fprintf(stderr, "%s\n", error);
! 450: return 1;
! 451: }
! 452: return 0;
! 453:
! 454: usage:
! 455: san->destroy_offset(san, offsetof(identification_t, destroy));
! 456: permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
! 457: excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
! 458: addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
! 459: policies->destroy_function(policies, (void*)destroy_cert_policy);
! 460: mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
! 461: ocsp->destroy(ocsp);
! 462: free(critical_extension_oid.ptr);
! 463: return command_usage(error);
! 464: }
! 465:
! 466: /**
! 467: * Register the command.
! 468: */
! 469: static void __attribute__ ((constructor))reg()
! 470: {
! 471: command_register((command_t) {
! 472: self, 's', "self",
! 473: "create a self signed certificate",
! 474: {"[--in file|--keyid hex] [--type rsa|ecdsa|ed25519|ed448|bliss|priv]",
! 475: " --dn distinguished-name [--san subjectAltName]+",
! 476: "[--lifetime days] [--serial hex] [--ca] [--ocsp uri]+",
! 477: "[--flag serverAuth|clientAuth|crlSign|ocspSigning|msSmartcardLogon]+",
! 478: "[--nc-permitted name] [--nc-excluded name]",
! 479: "[--policy-map issuer-oid:subject-oid]",
! 480: "[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
! 481: "[--cert-policy oid [--cps-uri uri] [--user-notice text]]+",
! 482: "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
! 483: "[--rsa-padding pkcs1|pss] [--critical oid]",
! 484: "[--outform der|pem]"},
! 485: {
! 486: {"help", 'h', 0, "show usage information"},
! 487: {"in", 'i', 1, "private key input file, default: stdin"},
! 488: {"keyid", 'x', 1, "smartcard or TPM private key object handle"},
! 489: {"type", 't', 1, "type of input key, default: priv"},
! 490: {"dn", 'd', 1, "subject and issuer distinguished name"},
! 491: {"san", 'a', 1, "subjectAltName to include in certificate"},
! 492: {"lifetime", 'l', 1, "days the certificate is valid, default: 1095"},
! 493: {"not-before", 'F', 1, "date/time the validity of the cert starts"},
! 494: {"not-after", 'T', 1, "date/time the validity of the cert ends"},
! 495: {"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
! 496: {"serial", 's', 1, "serial number in hex, default: random"},
! 497: {"ca", 'b', 0, "include CA basicConstraint, default: no"},
! 498: {"pathlen", 'p', 1, "set path length constraint"},
! 499: {"addrblock", 'B', 1, "RFC 3779 addrBlock to include"},
! 500: {"nc-permitted", 'n', 1, "add permitted NameConstraint"},
! 501: {"nc-excluded", 'N', 1, "add excluded NameConstraint"},
! 502: {"cert-policy", 'P', 1, "certificatePolicy OID to include"},
! 503: {"cps-uri", 'C', 1, "Certification Practice statement URI for certificatePolicy"},
! 504: {"user-notice", 'U', 1, "user notice for certificatePolicy"},
! 505: {"policy-mapping", 'M', 1, "policyMapping from issuer to subject OID"},
! 506: {"policy-explicit", 'E', 1, "requireExplicitPolicy constraint"},
! 507: {"policy-inhibit", 'H', 1, "inhibitPolicyMapping constraint"},
! 508: {"policy-any", 'A', 1, "inhibitAnyPolicy constraint"},
! 509: {"flag", 'e', 1, "include extendedKeyUsage flag"},
! 510: {"ocsp", 'o', 1, "OCSP AuthorityInfoAccess URI to include"},
! 511: {"digest", 'g', 1, "digest for signature creation, default: key-specific"},
! 512: {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
! 513: {"critical", 'X', 1, "critical extension OID to include for test purposes"},
! 514: {"outform", 'f', 1, "encoding of generated cert, default: der"},
! 515: }
! 516: });
! 517: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>