diff options
Diffstat (limited to 'src/pki/commands/issue.c')
-rw-r--r-- | src/pki/commands/issue.c | 223 |
1 files changed, 189 insertions, 34 deletions
diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 8ea852e31..6a5686d92 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -18,12 +18,41 @@ #include "pki.h" #include <debug.h> +#include <asn1/asn1.h> #include <utils/linked_list.h> #include <credentials/certificates/certificate.h> #include <credentials/certificates/x509.h> #include <credentials/certificates/pkcs10.h> /** + * Free cert policy with OID + */ +static void destroy_cert_policy(x509_cert_policy_t *policy) +{ + free(policy->oid.ptr); + free(policy); +} + +/** + * Free policy mapping + */ +static void destroy_policy_mapping(x509_policy_mapping_t *mapping) +{ + free(mapping->issuer.ptr); + free(mapping->subject.ptr); + free(mapping); +} + +/** + * Free a CRL DistributionPoint + */ +static void destroy_cdp(x509_cdp_t *this) +{ + DESTROY_IF(this->issuer); + free(this); +} + +/** * Issue a certificate using a CA certificate and key */ static int issue() @@ -37,19 +66,26 @@ static int issue() char *file = NULL, *dn = NULL, *hex = NULL, *cacert = NULL, *cakey = NULL; char *error = NULL, *keyid = NULL; identification_t *id = NULL; - linked_list_t *san, *cdps, *ocsp; + linked_list_t *san, *cdps, *ocsp, *permitted, *excluded, *policies, *mappings; int lifetime = 1095; - int pathlen = X509_NO_PATH_LEN_CONSTRAINT; + int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT; + int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT; chunk_t serial = chunk_empty; chunk_t encoding = chunk_empty; time_t not_before, not_after; x509_flag_t flags = 0; x509_t *x509; + x509_cdp_t *cdp = NULL; + x509_cert_policy_t *policy = NULL; char *arg; san = linked_list_create(); cdps = linked_list_create(); ocsp = linked_list_create(); + permitted = linked_list_create(); + excluded = linked_list_create(); + policies = linked_list_create(); + mappings = linked_list_create(); while (TRUE) { @@ -111,6 +147,79 @@ static int issue() case 'p': pathlen = atoi(arg); continue; + case 'n': + permitted->insert_last(permitted, + identification_create_from_string(arg)); + continue; + case 'N': + excluded->insert_last(excluded, + identification_create_from_string(arg)); + continue; + case 'P': + { + chunk_t oid; + + oid = asn1_oid_from_string(arg); + if (!oid.len) + { + error = "--cert-policy OID invalid"; + goto usage; + } + INIT(policy, + .oid = oid, + ); + policies->insert_last(policies, policy); + continue; + } + case 'C': + if (!policy) + { + error = "--cps-uri must follow a --cert-policy"; + goto usage; + } + policy->cps_uri = arg; + continue; + case 'U': + if (!policy) + { + error = "--user-notice must follow a --cert-policy"; + goto usage; + } + policy->unotice_text = arg; + continue; + case 'M': + { + char *pos = strchr(arg, ':'); + x509_policy_mapping_t *mapping; + chunk_t subject_oid, issuer_oid; + + if (pos) + { + *pos++ = '\0'; + issuer_oid = asn1_oid_from_string(arg); + subject_oid = asn1_oid_from_string(pos); + } + if (!pos || !issuer_oid.len || !subject_oid.len) + { + error = "--policy-map OIDs invalid"; + goto usage; + } + INIT(mapping, + .issuer = issuer_oid, + .subject = subject_oid, + ); + mappings->insert_last(mappings, mapping); + continue; + } + case 'E': + require_explicit = atoi(arg); + continue; + case 'H': + inhibit_mapping = atoi(arg); + continue; + case 'A': + inhibit_any = atoi(arg); + continue; case 'e': if (streq(arg, "serverAuth")) { @@ -120,6 +229,10 @@ static int issue() { flags |= X509_CLIENT_AUTH; } + else if (streq(arg, "crlSign")) + { + flags |= X509_CRL_SIGN; + } else if (streq(arg, "ocspSigning")) { flags |= X509_OCSP_SIGNER; @@ -128,11 +241,23 @@ static int issue() case 'f': if (!get_form(arg, &form, CRED_CERTIFICATE)) { - return command_usage("invalid output format"); + error = "invalid output format"; + goto usage; } continue; case 'u': - cdps->insert_last(cdps, arg); + INIT(cdp, + .uri = arg, + ); + cdps->insert_last(cdps, cdp); + continue; + case 'I': + if (!cdp || cdp->issuer) + { + error = "--crlissuer must follow a --crl"; + goto usage; + } + cdp->issuer = identification_create_from_string(arg); continue; case 'o': ocsp->insert_last(ocsp, arg); @@ -145,12 +270,6 @@ static int issue() } break; } - - if (!pkcs10 && !dn) - { - error = "--dn is required"; - goto usage; - } if (!cacert) { error = "--cacert is required"; @@ -161,7 +280,7 @@ static int issue() error = "--cakey or --keyid is required"; goto usage; } - if (dn) + if (dn && *dn) { id = identification_create_from_string(dn); if (id->get_type(id) != ID_DER_ASN1_DN) @@ -306,6 +425,12 @@ static int issue() goto end; } + if (!id) + { + id = identification_create_from_encoding(ID_DER_ASN1_DN, + chunk_from_chars(ASN1_SEQUENCE, 0)); + } + not_before = time(NULL); not_after = not_before + lifetime * 24 * 60 * 60; @@ -317,7 +442,15 @@ static int issue() BUILD_SUBJECT_ALTNAMES, san, BUILD_X509_FLAG, flags, BUILD_PATHLEN, pathlen, BUILD_CRL_DISTRIBUTION_POINTS, cdps, - BUILD_OCSP_ACCESS_LOCATIONS, ocsp, BUILD_END); + BUILD_OCSP_ACCESS_LOCATIONS, ocsp, + BUILD_PERMITTED_NAME_CONSTRAINTS, permitted, + BUILD_EXCLUDED_NAME_CONSTRAINTS, excluded, + BUILD_CERTIFICATE_POLICIES, policies, + BUILD_POLICY_MAPPINGS, mappings, + BUILD_POLICY_REQUIRE_EXPLICIT, require_explicit, + BUILD_POLICY_INHIBIT_MAPPING, inhibit_mapping, + BUILD_POLICY_INHIBIT_ANY, inhibit_any, + BUILD_END); if (!cert) { error = "generating certificate failed"; @@ -342,7 +475,11 @@ end: DESTROY_IF(public); DESTROY_IF(private); san->destroy_offset(san, offsetof(identification_t, destroy)); - cdps->destroy(cdps); + permitted->destroy_offset(permitted, offsetof(identification_t, destroy)); + excluded->destroy_offset(excluded, offsetof(identification_t, destroy)); + policies->destroy_function(policies, (void*)destroy_cert_policy); + mappings->destroy_function(mappings, (void*)destroy_policy_mapping); + cdps->destroy_function(cdps, (void*)destroy_cdp); ocsp->destroy(ocsp); free(encoding.ptr); free(serial.ptr); @@ -356,7 +493,11 @@ end: usage: san->destroy_offset(san, offsetof(identification_t, destroy)); - cdps->destroy(cdps); + permitted->destroy_offset(permitted, offsetof(identification_t, destroy)); + excluded->destroy_offset(excluded, offsetof(identification_t, destroy)); + policies->destroy_function(policies, (void*)destroy_cert_policy); + mappings->destroy_function(mappings, (void*)destroy_policy_mapping); + cdps->destroy_function(cdps, (void*)destroy_cdp); ocsp->destroy(ocsp); return command_usage(error); } @@ -370,28 +511,42 @@ static void __attribute__ ((constructor))reg() issue, 'i', "issue", "issue a certificate using a CA certificate and key", {"[--in file] [--type pub|pkcs10] --cakey file | --cakeyid hex", - " --cacert file --dn subject-dn [--san subjectAltName]+", - "[--lifetime days] [--serial hex] [--crl uri]+ [--ocsp uri]+", - "[--ca] [--pathlen len] [--flag serverAuth|clientAuth|ocspSigning]+", + " --cacert file [--dn subject-dn] [--san subjectAltName]+", + "[--lifetime days] [--serial hex] [--crl uri [--crlissuer i] ]+ [--ocsp uri]+", + "[--ca] [--pathlen len] [--flag serverAuth|clientAuth|crlSign|ocspSigning]+", + "[--nc-permitted name] [--nc-excluded name]", + "[--cert-policy oid [--cps-uri uri] [--user-notice text] ]+", + "[--policy-map issuer-oid:subject-oid]", + "[--policy-explicit len] [--policy-inhibit len] [--policy-any len]", "[--digest md5|sha1|sha224|sha256|sha384|sha512] [--outform der|pem]"}, { - {"help", 'h', 0, "show usage information"}, - {"in", 'i', 1, "public key/request file to issue, default: stdin"}, - {"type", 't', 1, "type of input, default: pub"}, - {"cacert", 'c', 1, "CA certificate file"}, - {"cakey", 'k', 1, "CA private key file"}, - {"cakeyid", 'x', 1, "keyid on smartcard of CA private key"}, - {"dn", 'd', 1, "distinguished name to include as subject"}, - {"san", 'a', 1, "subjectAltName to include in certificate"}, - {"lifetime",'l', 1, "days the certificate is valid, default: 1095"}, - {"serial", 's', 1, "serial number in hex, default: random"}, - {"ca", 'b', 0, "include CA basicConstraint, default: no"}, - {"pathlen", 'p', 1, "set path length constraint"}, - {"flag", 'e', 1, "include extendedKeyUsage flag"}, - {"crl", 'u', 1, "CRL distribution point URI to include"}, - {"ocsp", 'o', 1, "OCSP AuthorityInfoAccess URI to include"}, - {"digest", 'g', 1, "digest for signature creation, default: sha1"}, - {"outform", 'f', 1, "encoding of generated cert, default: der"}, + {"help", 'h', 0, "show usage information"}, + {"in", 'i', 1, "public key/request file to issue, default: stdin"}, + {"type", 't', 1, "type of input, default: pub"}, + {"cacert", 'c', 1, "CA certificate file"}, + {"cakey", 'k', 1, "CA private key file"}, + {"cakeyid", 'x', 1, "keyid on smartcard of CA private key"}, + {"dn", 'd', 1, "distinguished name to include as subject"}, + {"san", 'a', 1, "subjectAltName to include in certificate"}, + {"lifetime", 'l', 1, "days the certificate is valid, default: 1095"}, + {"serial", 's', 1, "serial number in hex, default: random"}, + {"ca", 'b', 0, "include CA basicConstraint, default: no"}, + {"pathlen", 'p', 1, "set path length constraint"}, + {"nc-permitted", 'n', 1, "add permitted NameConstraint"}, + {"nc-excluded", 'N', 1, "add excluded NameConstraint"}, + {"cert-policy", 'P', 1, "certificatePolicy OID to include"}, + {"cps-uri", 'C', 1, "Certification Practice statement URI for certificatePolicy"}, + {"user-notice", 'U', 1, "user notice for certificatePolicy"}, + {"policy-mapping", 'M', 1, "policyMapping from issuer to subject OID"}, + {"policy-explicit", 'E', 1, "requireExplicitPolicy constraint"}, + {"policy-inhibit", 'H', 1, "inhibitPolicyMapping constraint"}, + {"policy-any", 'A', 1, "inhibitAnyPolicy constraint"}, + {"flag", 'e', 1, "include extendedKeyUsage flag"}, + {"crl", 'u', 1, "CRL distribution point URI to include"}, + {"crlissuer", 'I', 1, "CRL Issuer for CRL at distribution point"}, + {"ocsp", 'o', 1, "OCSP AuthorityInfoAccess URI to include"}, + {"digest", 'g', 1, "digest for signature creation, default: sha1"}, + {"outform", 'f', 1, "encoding of generated cert, default: der"}, } }); } |