13089Swyllys /* 23089Swyllys * CDDL HEADER START 33089Swyllys * 43089Swyllys * The contents of this file are subject to the terms of the 53089Swyllys * Common Development and Distribution License (the "License"). 63089Swyllys * You may not use this file except in compliance with the License. 73089Swyllys * 83089Swyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93089Swyllys * or http://www.opensolaris.org/os/licensing. 103089Swyllys * See the License for the specific language governing permissions 113089Swyllys * and limitations under the License. 123089Swyllys * 133089Swyllys * When distributing Covered Code, include this CDDL HEADER in each 143089Swyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153089Swyllys * If applicable, add the following below this CDDL HEADER, with the 163089Swyllys * fields enclosed by brackets "[]" replaced with your own identifying 173089Swyllys * information: Portions Copyright [yyyy] [name of copyright owner] 183089Swyllys * 193089Swyllys * CDDL HEADER END 203089Swyllys * 21*5051Swyllys * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 223089Swyllys * Use is subject to license terms. 233089Swyllys */ 243089Swyllys 253089Swyllys #pragma ident "%Z%%M% %I% %E% SMI" 263089Swyllys 273089Swyllys #include <stdio.h> 283089Swyllys #include <strings.h> 293089Swyllys #include <ctype.h> 303089Swyllys #include <libgen.h> 313089Swyllys #include <libintl.h> 323089Swyllys #include <errno.h> 333089Swyllys #include <kmfapiP.h> 343089Swyllys #include <cryptoutil.h> 353089Swyllys #include "util.h" 363089Swyllys 373089Swyllys int 383089Swyllys kc_create(int argc, char *argv[]) 393089Swyllys { 403089Swyllys KMF_RETURN ret; 413089Swyllys int rv = KC_OK; 423089Swyllys int opt; 433089Swyllys extern int optind_av; 443089Swyllys extern char *optarg_av; 453089Swyllys char *filename = NULL; 463089Swyllys int ocsp_set_attr = 0; 473089Swyllys boolean_t crl_set_attr = 0; 483089Swyllys KMF_POLICY_RECORD plc; 493089Swyllys 503089Swyllys (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD)); 513089Swyllys 523089Swyllys while ((opt = getopt_av(argc, argv, 53*5051Swyllys "i:(dbfile)" 54*5051Swyllys "p:(policy)" 55*5051Swyllys "d:(ignore-date)" 56*5051Swyllys "e:(ignore-unknown-eku)" 57*5051Swyllys "a:(ignore-trust-anchor)" 58*5051Swyllys "v:(validity-adjusttime)" 59*5051Swyllys "t:(ta-name)" 60*5051Swyllys "s:(ta-serial)" 61*5051Swyllys "o:(ocsp-responder)" 62*5051Swyllys "P:(ocsp-proxy)" 63*5051Swyllys "r:(ocsp-use-cert-responder)" 64*5051Swyllys "T:(ocsp-response-lifetime)" 65*5051Swyllys "R:(ocsp-ignore-response-sign)" 66*5051Swyllys "n:(ocsp-responder-cert-name)" 67*5051Swyllys "A:(ocsp-responder-cert-serial)" 68*5051Swyllys "c:(crl-basefilename)" 69*5051Swyllys "I:(crl-directory)" 70*5051Swyllys "g:(crl-get-crl-uri)" 71*5051Swyllys "X:(crl-proxy)" 72*5051Swyllys "S:(crl-ignore-crl-sign)" 73*5051Swyllys "D:(crl-ignore-crl-date)" 74*5051Swyllys "u:(keyusage)" 75*5051Swyllys "E:(ekunames)" 76*5051Swyllys "O:(ekuoids)")) != EOF) { 773089Swyllys switch (opt) { 783089Swyllys case 'i': 793089Swyllys filename = get_string(optarg_av, &rv); 803089Swyllys if (filename == NULL) { 813089Swyllys (void) fprintf(stderr, 823089Swyllys gettext("Error dbfile input.\n")); 833089Swyllys } 843089Swyllys break; 853089Swyllys case 'p': 863089Swyllys plc.name = get_string(optarg_av, &rv); 873089Swyllys if (plc.name == NULL) { 883089Swyllys (void) fprintf(stderr, 893089Swyllys gettext("Error policy name.\n")); 903089Swyllys } 913089Swyllys break; 923089Swyllys case 'd': 933089Swyllys plc.ignore_date = get_boolean(optarg_av); 943089Swyllys if (plc.ignore_date == -1) { 953089Swyllys (void) fprintf(stderr, 963089Swyllys gettext("Error boolean input.\n")); 973089Swyllys rv = KC_ERR_USAGE; 983089Swyllys } 993089Swyllys break; 1003089Swyllys case 'e': 1013089Swyllys plc.ignore_unknown_ekus = 1023089Swyllys get_boolean(optarg_av); 1033089Swyllys if (plc.ignore_unknown_ekus == -1) { 1043089Swyllys (void) fprintf(stderr, 1053089Swyllys gettext("Error boolean input.\n")); 1063089Swyllys rv = KC_ERR_USAGE; 1073089Swyllys } 1083089Swyllys break; 1093089Swyllys case 'a': 1103089Swyllys plc.ignore_trust_anchor = 1113089Swyllys get_boolean(optarg_av); 1123089Swyllys if (plc.ignore_trust_anchor == -1) { 1133089Swyllys (void) fprintf(stderr, 1143089Swyllys gettext("Error boolean input.\n")); 1153089Swyllys rv = KC_ERR_USAGE; 1163089Swyllys } 1173089Swyllys break; 1183089Swyllys case 'v': 1193089Swyllys plc.validity_adjusttime = 1203089Swyllys get_string(optarg_av, &rv); 1213089Swyllys if (plc.validity_adjusttime == NULL) { 1223089Swyllys (void) fprintf(stderr, 1233089Swyllys gettext("Error time input.\n")); 1243089Swyllys } else { 1253089Swyllys uint32_t adj; 1263089Swyllys /* for syntax checking */ 1273089Swyllys if (str2lifetime( 1283089Swyllys plc.validity_adjusttime, 1293089Swyllys &adj) < 0) { 1303089Swyllys (void) fprintf(stderr, 1313089Swyllys gettext("Error time " 1323089Swyllys "input.\n")); 1333089Swyllys rv = KC_ERR_USAGE; 1343089Swyllys } 1353089Swyllys } 1363089Swyllys break; 1373089Swyllys case 't': 1383089Swyllys plc.ta_name = get_string(optarg_av, &rv); 1393089Swyllys if (plc.ta_name == NULL) { 1403089Swyllys (void) fprintf(stderr, 1413089Swyllys gettext("Error name input.\n")); 1423089Swyllys } else { 1433089Swyllys KMF_X509_NAME taDN; 1443089Swyllys /* for syntax checking */ 145*5051Swyllys if (kmf_dn_parser(plc.ta_name, 1463089Swyllys &taDN) != KMF_OK) { 1473089Swyllys (void) fprintf(stderr, 1483089Swyllys gettext("Error name " 1493089Swyllys "input.\n")); 1503089Swyllys rv = KC_ERR_USAGE; 1513089Swyllys } else { 152*5051Swyllys kmf_free_dn(&taDN); 1533089Swyllys } 1543089Swyllys } 1553089Swyllys break; 1563089Swyllys case 's': 1573089Swyllys plc.ta_serial = get_string(optarg_av, &rv); 1583089Swyllys if (plc.ta_serial == NULL) { 1593089Swyllys (void) fprintf(stderr, 1603089Swyllys gettext("Error serial input.\n")); 1613089Swyllys } else { 1623089Swyllys uchar_t *bytes = NULL; 1633089Swyllys size_t bytelen; 1643089Swyllys 165*5051Swyllys ret = kmf_hexstr_to_bytes( 1663089Swyllys (uchar_t *)plc.ta_serial, 1673089Swyllys &bytes, &bytelen); 1683089Swyllys if (ret != KMF_OK || bytes == NULL) { 1693089Swyllys (void) fprintf(stderr, 1703089Swyllys gettext("serial number " 1713089Swyllys "must be specified as a " 1723089Swyllys "hex number " 1733089Swyllys "(ex: 0x0102030405" 1743089Swyllys "ffeeddee)\n")); 1753089Swyllys rv = KC_ERR_USAGE; 1763089Swyllys } 1773089Swyllys if (bytes != NULL) 1783089Swyllys free(bytes); 1793089Swyllys } 1803089Swyllys break; 1813089Swyllys case 'o': 1823089Swyllys plc.VAL_OCSP_RESPONDER_URI = 1833089Swyllys get_string(optarg_av, &rv); 1843089Swyllys if (plc.VAL_OCSP_RESPONDER_URI == NULL) { 1853089Swyllys (void) fprintf(stderr, gettext( 1863089Swyllys "Error responder input.\n")); 1873089Swyllys } else { 1883089Swyllys ocsp_set_attr++; 1893089Swyllys } 1903089Swyllys break; 1913089Swyllys case 'P': 1923089Swyllys plc.VAL_OCSP_PROXY = 1933089Swyllys get_string(optarg_av, &rv); 1943089Swyllys if (plc.VAL_OCSP_PROXY == NULL) { 1953089Swyllys (void) fprintf(stderr, 1963089Swyllys gettext("Error proxy input.\n")); 1973089Swyllys } else { 1983089Swyllys ocsp_set_attr++; 1993089Swyllys } 2003089Swyllys break; 2013089Swyllys case 'r': 2023089Swyllys plc.VAL_OCSP_URI_FROM_CERT = 2033089Swyllys get_boolean(optarg_av); 2043089Swyllys if (plc.VAL_OCSP_URI_FROM_CERT == -1) { 2053089Swyllys (void) fprintf(stderr, 2063089Swyllys gettext("Error boolean input.\n")); 2073089Swyllys rv = KC_ERR_USAGE; 2083089Swyllys } else { 2093089Swyllys ocsp_set_attr++; 2103089Swyllys } 2113089Swyllys break; 2123089Swyllys case 'T': 2133089Swyllys plc.VAL_OCSP_RESP_LIFETIME = 2143089Swyllys get_string(optarg_av, &rv); 2153089Swyllys if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { 2163089Swyllys (void) fprintf(stderr, 2173089Swyllys gettext("Error time input.\n")); 2183089Swyllys } else { 2193089Swyllys uint32_t adj; 2203089Swyllys /* for syntax checking */ 2213089Swyllys if (str2lifetime( 2223089Swyllys plc.VAL_OCSP_RESP_LIFETIME, 2233089Swyllys &adj) < 0) { 2243089Swyllys (void) fprintf(stderr, 2253089Swyllys gettext("Error time " 2263089Swyllys "input.\n")); 2273089Swyllys rv = KC_ERR_USAGE; 2283089Swyllys } else { 2293089Swyllys ocsp_set_attr++; 2303089Swyllys } 2313089Swyllys } 2323089Swyllys break; 2333089Swyllys case 'R': 2343089Swyllys plc.VAL_OCSP_IGNORE_RESP_SIGN = 2353089Swyllys get_boolean(optarg_av); 2363089Swyllys if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { 2373089Swyllys (void) fprintf(stderr, 2383089Swyllys gettext("Error boolean input.\n")); 2393089Swyllys rv = KC_ERR_USAGE; 2403089Swyllys } else { 2413089Swyllys ocsp_set_attr++; 2423089Swyllys } 2433089Swyllys break; 2443089Swyllys case 'n': 2453089Swyllys plc.VAL_OCSP_RESP_CERT_NAME = 2463089Swyllys get_string(optarg_av, &rv); 2473089Swyllys if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { 2483089Swyllys (void) fprintf(stderr, 2493089Swyllys gettext("Error name input.\n")); 2503089Swyllys } else { 2513089Swyllys KMF_X509_NAME respDN; 2523089Swyllys /* for syntax checking */ 253*5051Swyllys if (kmf_dn_parser( 2543089Swyllys plc.VAL_OCSP_RESP_CERT_NAME, 2553089Swyllys &respDN) != KMF_OK) { 2563089Swyllys (void) fprintf(stderr, 2573089Swyllys gettext("Error name " 2583089Swyllys "input.\n")); 2593089Swyllys rv = KC_ERR_USAGE; 2603089Swyllys } else { 261*5051Swyllys kmf_free_dn(&respDN); 2623089Swyllys ocsp_set_attr++; 2633089Swyllys } 2643089Swyllys } 2653089Swyllys break; 2663089Swyllys case 'A': 2673089Swyllys plc.VAL_OCSP_RESP_CERT_SERIAL = 2683089Swyllys get_string(optarg_av, &rv); 2693089Swyllys if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { 2703089Swyllys (void) fprintf(stderr, 2713089Swyllys gettext("Error serial input.\n")); 2723089Swyllys } else { 2733089Swyllys uchar_t *bytes = NULL; 2743089Swyllys size_t bytelen; 2753089Swyllys 276*5051Swyllys ret = kmf_hexstr_to_bytes((uchar_t *) 2773089Swyllys plc.VAL_OCSP_RESP_CERT_SERIAL, 2783089Swyllys &bytes, &bytelen); 2793089Swyllys if (ret != KMF_OK || bytes == NULL) { 2803089Swyllys (void) fprintf(stderr, 2813089Swyllys gettext("serial number " 2823089Swyllys "must be specified as a " 2833089Swyllys "hex number " 2843089Swyllys "(ex: 0x0102030405" 2853089Swyllys "ffeeddee)\n")); 2863089Swyllys rv = KC_ERR_USAGE; 2873089Swyllys break; 2883089Swyllys } 2893089Swyllys if (bytes != NULL) 2903089Swyllys free(bytes); 2913089Swyllys ocsp_set_attr++; 2923089Swyllys } 2933089Swyllys break; 2943089Swyllys case 'c': 2953089Swyllys plc.VAL_CRL_BASEFILENAME = 2963089Swyllys get_string(optarg_av, &rv); 2973089Swyllys if (plc.VAL_CRL_BASEFILENAME == NULL) { 2983089Swyllys (void) fprintf(stderr, 2993089Swyllys gettext("Error boolean input.\n")); 3003089Swyllys } else { 3013089Swyllys crl_set_attr++; 3023089Swyllys } 3033089Swyllys break; 3043089Swyllys case 'I': 3053089Swyllys plc.VAL_CRL_DIRECTORY = 3063089Swyllys get_string(optarg_av, &rv); 3073089Swyllys if (plc.VAL_CRL_DIRECTORY == NULL) { 3083089Swyllys (void) fprintf(stderr, 3093089Swyllys gettext("Error boolean input.\n")); 3103089Swyllys } else { 3113089Swyllys crl_set_attr++; 3123089Swyllys } 3133089Swyllys break; 3143089Swyllys case 'g': 3153089Swyllys plc.VAL_CRL_GET_URI = get_boolean(optarg_av); 3163089Swyllys if (plc.VAL_CRL_GET_URI == -1) { 3173089Swyllys (void) fprintf(stderr, 3183089Swyllys gettext("Error boolean input.\n")); 3193089Swyllys rv = KC_ERR_USAGE; 3203089Swyllys } else { 3213089Swyllys crl_set_attr++; 3223089Swyllys } 3233089Swyllys break; 3243089Swyllys case 'X': 3253089Swyllys plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); 3263089Swyllys if (plc.VAL_CRL_PROXY == NULL) { 3273089Swyllys (void) fprintf(stderr, 3283089Swyllys gettext("Error proxy input.\n")); 3293089Swyllys } else { 3303089Swyllys crl_set_attr++; 3313089Swyllys } 3323089Swyllys break; 3333089Swyllys case 'S': 3343089Swyllys plc.VAL_CRL_IGNORE_SIGN = 3353089Swyllys get_boolean(optarg_av); 3363089Swyllys if (plc.VAL_CRL_IGNORE_SIGN == -1) { 3373089Swyllys (void) fprintf(stderr, 3383089Swyllys gettext("Error boolean input.\n")); 3393089Swyllys rv = KC_ERR_USAGE; 3403089Swyllys } else { 3413089Swyllys crl_set_attr++; 3423089Swyllys } 3433089Swyllys break; 3443089Swyllys case 'D': 3453089Swyllys plc.VAL_CRL_IGNORE_DATE = 346*5051Swyllys get_boolean(optarg_av); 3473089Swyllys if (plc.VAL_CRL_IGNORE_DATE == -1) { 3483089Swyllys (void) fprintf(stderr, 3493089Swyllys gettext("Error boolean input.\n")); 3503089Swyllys rv = KC_ERR_USAGE; 3513089Swyllys } else { 3523089Swyllys crl_set_attr++; 3533089Swyllys } 3543089Swyllys break; 3553089Swyllys case 'u': 3563089Swyllys plc.ku_bits = parseKUlist(optarg_av); 3573089Swyllys if (plc.ku_bits == 0) { 3583089Swyllys (void) fprintf(stderr, gettext( 3593089Swyllys "Error keyusage input.\n")); 3603089Swyllys rv = KC_ERR_USAGE; 3613089Swyllys } 3623089Swyllys break; 3633089Swyllys case 'E': 3643089Swyllys if (parseEKUNames(optarg_av, &plc) != 0) { 3653089Swyllys (void) fprintf(stderr, 3663089Swyllys gettext("Error EKU input.\n")); 3673089Swyllys rv = KC_ERR_USAGE; 3683089Swyllys } 3693089Swyllys break; 3703089Swyllys case 'O': 3713089Swyllys if (parseEKUOIDs(optarg_av, &plc) != 0) { 3723089Swyllys (void) fprintf(stderr, 3733089Swyllys gettext("Error EKU OID input.\n")); 3743089Swyllys rv = KC_ERR_USAGE; 3753089Swyllys } 3763089Swyllys break; 3773089Swyllys default: 3783089Swyllys (void) fprintf(stderr, 3793089Swyllys gettext("Error input option.\n")); 3803089Swyllys rv = KC_ERR_USAGE; 3813089Swyllys break; 3823089Swyllys } 3833089Swyllys 3843089Swyllys if (rv != KC_OK) 3853089Swyllys goto out; 3863089Swyllys } 3873089Swyllys 3883089Swyllys /* No additional args allowed. */ 3893089Swyllys argc -= optind_av; 3903089Swyllys if (argc) { 3913089Swyllys (void) fprintf(stderr, 3923089Swyllys gettext("Error input option\n")); 3933089Swyllys rv = KC_ERR_USAGE; 3943089Swyllys goto out; 3953089Swyllys } 3963089Swyllys 3973089Swyllys if (filename == NULL) { 3983089Swyllys filename = strdup(KMF_DEFAULT_POLICY_FILE); 3993089Swyllys if (filename == NULL) { 4003089Swyllys rv = KC_ERR_MEMORY; 4013089Swyllys goto out; 4023089Swyllys } 4033089Swyllys } 4043089Swyllys 4053089Swyllys /* 4063089Swyllys * Must have a policy name. The policy name can not be default 4073089Swyllys * if using the default policy file. 4083089Swyllys */ 4093089Swyllys if (plc.name == NULL) { 4103089Swyllys (void) fprintf(stderr, 4113089Swyllys gettext("You must specify a policy name\n")); 4123089Swyllys rv = KC_ERR_USAGE; 4133089Swyllys goto out; 4143089Swyllys } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && 4153089Swyllys strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { 4163089Swyllys (void) fprintf(stderr, 4173089Swyllys gettext("Can not create a default policy in the default " 4183089Swyllys "policy file\n")); 4193089Swyllys rv = KC_ERR_USAGE; 4203089Swyllys goto out; 4213089Swyllys } 4223089Swyllys 4233089Swyllys /* 4243089Swyllys * If the policy file exists and the policy is in the policy file 4253089Swyllys * already, we will not create it again. 4263089Swyllys */ 4273089Swyllys if (access(filename, R_OK) == 0) { 4283089Swyllys POLICY_LIST *plclist = NULL, *pnode; 4293089Swyllys int found = 0; 4303089Swyllys 4313089Swyllys rv = load_policies(filename, &plclist); 4323089Swyllys if (rv != KMF_OK) 4333089Swyllys goto out; 4343089Swyllys 4353089Swyllys pnode = plclist; 4363089Swyllys while (pnode != NULL && !found) { 4373089Swyllys if (strcmp(plc.name, pnode->plc.name) == 0) 4383089Swyllys found++; 4393089Swyllys pnode = pnode->next; 4403089Swyllys } 4413089Swyllys free_policy_list(plclist); 4423089Swyllys 4433089Swyllys if (found) { 4443089Swyllys (void) fprintf(stderr, 4453089Swyllys gettext("Could not create policy \"%s\" - exists " 4463089Swyllys "already\n"), plc.name); 4473089Swyllys rv = KC_ERR_USAGE; 4483089Swyllys goto out; 4493089Swyllys } 4503089Swyllys } 4513089Swyllys 4523089Swyllys /* 4533089Swyllys * If any OCSP attribute is set, turn on the OCSP checking flag. 4543089Swyllys * Also set "has_resp_cert" to be true, if the responder cert 4553089Swyllys * is provided. 4563089Swyllys */ 4573089Swyllys if (ocsp_set_attr > 0) 4583089Swyllys plc.revocation |= KMF_REVOCATION_METHOD_OCSP; 4593089Swyllys 4603089Swyllys if (plc.VAL_OCSP_RESP_CERT.name != NULL && 4613089Swyllys plc.VAL_OCSP_RESP_CERT.serial != NULL) { 4623089Swyllys plc.VAL_OCSP.has_resp_cert = B_TRUE; 4633089Swyllys } 4643089Swyllys 4653089Swyllys /* 4663089Swyllys * If any CRL attribute is set, turn on the CRL checking flag. 4673089Swyllys */ 4683089Swyllys if (crl_set_attr > 0) 4693089Swyllys plc.revocation |= KMF_REVOCATION_METHOD_CRL; 4703089Swyllys 4713089Swyllys /* 4723089Swyllys * Does a sanity check on the new policy. 4733089Swyllys */ 474*5051Swyllys ret = kmf_verify_policy(&plc); 4753089Swyllys if (ret != KMF_OK) { 4763089Swyllys print_sanity_error(ret); 4773089Swyllys rv = KC_ERR_ADD_POLICY; 4783089Swyllys goto out; 4793089Swyllys } 4803089Swyllys 4813089Swyllys /* 4823089Swyllys * Add to the DB. 4833089Swyllys */ 484*5051Swyllys ret = kmf_add_policy_to_db(&plc, filename, B_FALSE); 4853089Swyllys if (ret != KMF_OK) { 4863089Swyllys (void) fprintf(stderr, 4873089Swyllys gettext("Error adding policy to database: 0x%04x\n"), ret); 4883089Swyllys rv = KC_ERR_ADD_POLICY; 4893089Swyllys } 4903089Swyllys 4913089Swyllys out: 4923089Swyllys if (filename != NULL) 4933089Swyllys free(filename); 4943089Swyllys 495*5051Swyllys kmf_free_policy_record(&plc); 4963089Swyllys 4973089Swyllys return (rv); 4983089Swyllys } 499