1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include <stdio.h> 28 #include <strings.h> 29 #include <ctype.h> 30 #include <libgen.h> 31 #include <libintl.h> 32 #include <errno.h> 33 #include <kmfapiP.h> 34 #include <cryptoutil.h> 35 #include "util.h" 36 37 int 38 kc_create(int argc, char *argv[]) 39 { 40 KMF_RETURN ret; 41 int rv = KC_OK; 42 int opt; 43 extern int optind_av; 44 extern char *optarg_av; 45 char *filename = NULL; 46 int ocsp_set_attr = 0; 47 boolean_t crl_set_attr = 0; 48 KMF_POLICY_RECORD plc; 49 50 (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD)); 51 52 while ((opt = getopt_av(argc, argv, 53 "i:(dbfile)" 54 "p:(policy)" 55 "d:(ignore-date)" 56 "e:(ignore-unknown-eku)" 57 "a:(ignore-trust-anchor)" 58 "v:(validity-adjusttime)" 59 "t:(ta-name)" 60 "s:(ta-serial)" 61 "o:(ocsp-responder)" 62 "P:(ocsp-proxy)" 63 "r:(ocsp-use-cert-responder)" 64 "T:(ocsp-response-lifetime)" 65 "R:(ocsp-ignore-response-sign)" 66 "n:(ocsp-responder-cert-name)" 67 "A:(ocsp-responder-cert-serial)" 68 "c:(crl-basefilename)" 69 "I:(crl-directory)" 70 "g:(crl-get-crl-uri)" 71 "X:(crl-proxy)" 72 "S:(crl-ignore-crl-sign)" 73 "D:(crl-ignore-crl-date)" 74 "u:(keyusage)" 75 "E:(ekunames)" 76 "O:(ekuoids)")) != EOF) { 77 switch (opt) { 78 case 'i': 79 filename = get_string(optarg_av, &rv); 80 if (filename == NULL) { 81 (void) fprintf(stderr, 82 gettext("Error dbfile input.\n")); 83 } 84 break; 85 case 'p': 86 plc.name = get_string(optarg_av, &rv); 87 if (plc.name == NULL) { 88 (void) fprintf(stderr, 89 gettext("Error policy name.\n")); 90 } 91 break; 92 case 'd': 93 plc.ignore_date = get_boolean(optarg_av); 94 if (plc.ignore_date == -1) { 95 (void) fprintf(stderr, 96 gettext("Error boolean input.\n")); 97 rv = KC_ERR_USAGE; 98 } 99 break; 100 case 'e': 101 plc.ignore_unknown_ekus = 102 get_boolean(optarg_av); 103 if (plc.ignore_unknown_ekus == -1) { 104 (void) fprintf(stderr, 105 gettext("Error boolean input.\n")); 106 rv = KC_ERR_USAGE; 107 } 108 break; 109 case 'a': 110 plc.ignore_trust_anchor = 111 get_boolean(optarg_av); 112 if (plc.ignore_trust_anchor == -1) { 113 (void) fprintf(stderr, 114 gettext("Error boolean input.\n")); 115 rv = KC_ERR_USAGE; 116 } 117 break; 118 case 'v': 119 plc.validity_adjusttime = 120 get_string(optarg_av, &rv); 121 if (plc.validity_adjusttime == NULL) { 122 (void) fprintf(stderr, 123 gettext("Error time input.\n")); 124 } else { 125 uint32_t adj; 126 /* for syntax checking */ 127 if (str2lifetime( 128 plc.validity_adjusttime, 129 &adj) < 0) { 130 (void) fprintf(stderr, 131 gettext("Error time " 132 "input.\n")); 133 rv = KC_ERR_USAGE; 134 } 135 } 136 break; 137 case 't': 138 plc.ta_name = get_string(optarg_av, &rv); 139 if (plc.ta_name == NULL) { 140 (void) fprintf(stderr, 141 gettext("Error name input.\n")); 142 } else { 143 KMF_X509_NAME taDN; 144 /* for syntax checking */ 145 if (KMF_DNParser(plc.ta_name, 146 &taDN) != KMF_OK) { 147 (void) fprintf(stderr, 148 gettext("Error name " 149 "input.\n")); 150 rv = KC_ERR_USAGE; 151 } else { 152 KMF_FreeDN(&taDN); 153 } 154 } 155 break; 156 case 's': 157 plc.ta_serial = get_string(optarg_av, &rv); 158 if (plc.ta_serial == NULL) { 159 (void) fprintf(stderr, 160 gettext("Error serial input.\n")); 161 } else { 162 uchar_t *bytes = NULL; 163 size_t bytelen; 164 165 ret = KMF_HexString2Bytes( 166 (uchar_t *)plc.ta_serial, 167 &bytes, &bytelen); 168 if (ret != KMF_OK || bytes == NULL) { 169 (void) fprintf(stderr, 170 gettext("serial number " 171 "must be specified as a " 172 "hex number " 173 "(ex: 0x0102030405" 174 "ffeeddee)\n")); 175 rv = KC_ERR_USAGE; 176 } 177 if (bytes != NULL) 178 free(bytes); 179 } 180 break; 181 case 'o': 182 plc.VAL_OCSP_RESPONDER_URI = 183 get_string(optarg_av, &rv); 184 if (plc.VAL_OCSP_RESPONDER_URI == NULL) { 185 (void) fprintf(stderr, gettext( 186 "Error responder input.\n")); 187 } else { 188 ocsp_set_attr++; 189 } 190 break; 191 case 'P': 192 plc.VAL_OCSP_PROXY = 193 get_string(optarg_av, &rv); 194 if (plc.VAL_OCSP_PROXY == NULL) { 195 (void) fprintf(stderr, 196 gettext("Error proxy input.\n")); 197 } else { 198 ocsp_set_attr++; 199 } 200 break; 201 case 'r': 202 plc.VAL_OCSP_URI_FROM_CERT = 203 get_boolean(optarg_av); 204 if (plc.VAL_OCSP_URI_FROM_CERT == -1) { 205 (void) fprintf(stderr, 206 gettext("Error boolean input.\n")); 207 rv = KC_ERR_USAGE; 208 } else { 209 ocsp_set_attr++; 210 } 211 break; 212 case 'T': 213 plc.VAL_OCSP_RESP_LIFETIME = 214 get_string(optarg_av, &rv); 215 if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { 216 (void) fprintf(stderr, 217 gettext("Error time input.\n")); 218 } else { 219 uint32_t adj; 220 /* for syntax checking */ 221 if (str2lifetime( 222 plc.VAL_OCSP_RESP_LIFETIME, 223 &adj) < 0) { 224 (void) fprintf(stderr, 225 gettext("Error time " 226 "input.\n")); 227 rv = KC_ERR_USAGE; 228 } else { 229 ocsp_set_attr++; 230 } 231 } 232 break; 233 case 'R': 234 plc.VAL_OCSP_IGNORE_RESP_SIGN = 235 get_boolean(optarg_av); 236 if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { 237 (void) fprintf(stderr, 238 gettext("Error boolean input.\n")); 239 rv = KC_ERR_USAGE; 240 } else { 241 ocsp_set_attr++; 242 } 243 break; 244 case 'n': 245 plc.VAL_OCSP_RESP_CERT_NAME = 246 get_string(optarg_av, &rv); 247 if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { 248 (void) fprintf(stderr, 249 gettext("Error name input.\n")); 250 } else { 251 KMF_X509_NAME respDN; 252 /* for syntax checking */ 253 if (KMF_DNParser( 254 plc.VAL_OCSP_RESP_CERT_NAME, 255 &respDN) != KMF_OK) { 256 (void) fprintf(stderr, 257 gettext("Error name " 258 "input.\n")); 259 rv = KC_ERR_USAGE; 260 } else { 261 KMF_FreeDN(&respDN); 262 ocsp_set_attr++; 263 } 264 } 265 break; 266 case 'A': 267 plc.VAL_OCSP_RESP_CERT_SERIAL = 268 get_string(optarg_av, &rv); 269 if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { 270 (void) fprintf(stderr, 271 gettext("Error serial input.\n")); 272 } else { 273 uchar_t *bytes = NULL; 274 size_t bytelen; 275 276 ret = KMF_HexString2Bytes((uchar_t *) 277 plc.VAL_OCSP_RESP_CERT_SERIAL, 278 &bytes, &bytelen); 279 if (ret != KMF_OK || bytes == NULL) { 280 (void) fprintf(stderr, 281 gettext("serial number " 282 "must be specified as a " 283 "hex number " 284 "(ex: 0x0102030405" 285 "ffeeddee)\n")); 286 rv = KC_ERR_USAGE; 287 break; 288 } 289 if (bytes != NULL) 290 free(bytes); 291 ocsp_set_attr++; 292 } 293 break; 294 case 'c': 295 plc.VAL_CRL_BASEFILENAME = 296 get_string(optarg_av, &rv); 297 if (plc.VAL_CRL_BASEFILENAME == NULL) { 298 (void) fprintf(stderr, 299 gettext("Error boolean input.\n")); 300 } else { 301 crl_set_attr++; 302 } 303 break; 304 case 'I': 305 plc.VAL_CRL_DIRECTORY = 306 get_string(optarg_av, &rv); 307 if (plc.VAL_CRL_DIRECTORY == NULL) { 308 (void) fprintf(stderr, 309 gettext("Error boolean input.\n")); 310 } else { 311 crl_set_attr++; 312 } 313 break; 314 case 'g': 315 plc.VAL_CRL_GET_URI = get_boolean(optarg_av); 316 if (plc.VAL_CRL_GET_URI == -1) { 317 (void) fprintf(stderr, 318 gettext("Error boolean input.\n")); 319 rv = KC_ERR_USAGE; 320 } else { 321 crl_set_attr++; 322 } 323 break; 324 case 'X': 325 plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); 326 if (plc.VAL_CRL_PROXY == NULL) { 327 (void) fprintf(stderr, 328 gettext("Error proxy input.\n")); 329 } else { 330 crl_set_attr++; 331 } 332 break; 333 case 'S': 334 plc.VAL_CRL_IGNORE_SIGN = 335 get_boolean(optarg_av); 336 if (plc.VAL_CRL_IGNORE_SIGN == -1) { 337 (void) fprintf(stderr, 338 gettext("Error boolean input.\n")); 339 rv = KC_ERR_USAGE; 340 } else { 341 crl_set_attr++; 342 } 343 break; 344 case 'D': 345 plc.VAL_CRL_IGNORE_DATE = 346 get_boolean(optarg_av); 347 if (plc.VAL_CRL_IGNORE_DATE == -1) { 348 (void) fprintf(stderr, 349 gettext("Error boolean input.\n")); 350 rv = KC_ERR_USAGE; 351 } else { 352 crl_set_attr++; 353 } 354 break; 355 case 'u': 356 plc.ku_bits = parseKUlist(optarg_av); 357 if (plc.ku_bits == 0) { 358 (void) fprintf(stderr, gettext( 359 "Error keyusage input.\n")); 360 rv = KC_ERR_USAGE; 361 } 362 break; 363 case 'E': 364 if (parseEKUNames(optarg_av, &plc) != 0) { 365 (void) fprintf(stderr, 366 gettext("Error EKU input.\n")); 367 rv = KC_ERR_USAGE; 368 } 369 break; 370 case 'O': 371 if (parseEKUOIDs(optarg_av, &plc) != 0) { 372 (void) fprintf(stderr, 373 gettext("Error EKU OID input.\n")); 374 rv = KC_ERR_USAGE; 375 } 376 break; 377 default: 378 (void) fprintf(stderr, 379 gettext("Error input option.\n")); 380 rv = KC_ERR_USAGE; 381 break; 382 } 383 384 if (rv != KC_OK) 385 goto out; 386 } 387 388 /* No additional args allowed. */ 389 argc -= optind_av; 390 if (argc) { 391 (void) fprintf(stderr, 392 gettext("Error input option\n")); 393 rv = KC_ERR_USAGE; 394 goto out; 395 } 396 397 if (filename == NULL) { 398 filename = strdup(KMF_DEFAULT_POLICY_FILE); 399 if (filename == NULL) { 400 rv = KC_ERR_MEMORY; 401 goto out; 402 } 403 } 404 405 /* 406 * Must have a policy name. The policy name can not be default 407 * if using the default policy file. 408 */ 409 if (plc.name == NULL) { 410 (void) fprintf(stderr, 411 gettext("You must specify a policy name\n")); 412 rv = KC_ERR_USAGE; 413 goto out; 414 } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && 415 strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { 416 (void) fprintf(stderr, 417 gettext("Can not create a default policy in the default " 418 "policy file\n")); 419 rv = KC_ERR_USAGE; 420 goto out; 421 } 422 423 /* 424 * If the policy file exists and the policy is in the policy file 425 * already, we will not create it again. 426 */ 427 if (access(filename, R_OK) == 0) { 428 POLICY_LIST *plclist = NULL, *pnode; 429 int found = 0; 430 431 rv = load_policies(filename, &plclist); 432 if (rv != KMF_OK) 433 goto out; 434 435 pnode = plclist; 436 while (pnode != NULL && !found) { 437 if (strcmp(plc.name, pnode->plc.name) == 0) 438 found++; 439 pnode = pnode->next; 440 } 441 free_policy_list(plclist); 442 443 if (found) { 444 (void) fprintf(stderr, 445 gettext("Could not create policy \"%s\" - exists " 446 "already\n"), plc.name); 447 rv = KC_ERR_USAGE; 448 goto out; 449 } 450 } 451 452 /* 453 * If any OCSP attribute is set, turn on the OCSP checking flag. 454 * Also set "has_resp_cert" to be true, if the responder cert 455 * is provided. 456 */ 457 if (ocsp_set_attr > 0) 458 plc.revocation |= KMF_REVOCATION_METHOD_OCSP; 459 460 if (plc.VAL_OCSP_RESP_CERT.name != NULL && 461 plc.VAL_OCSP_RESP_CERT.serial != NULL) { 462 plc.VAL_OCSP.has_resp_cert = B_TRUE; 463 } 464 465 /* 466 * If any CRL attribute is set, turn on the CRL checking flag. 467 */ 468 if (crl_set_attr > 0) 469 plc.revocation |= KMF_REVOCATION_METHOD_CRL; 470 471 /* 472 * Does a sanity check on the new policy. 473 */ 474 ret = KMF_VerifyPolicy(&plc); 475 if (ret != KMF_OK) { 476 print_sanity_error(ret); 477 rv = KC_ERR_ADD_POLICY; 478 goto out; 479 } 480 481 /* 482 * Add to the DB. 483 */ 484 ret = KMF_AddPolicyToDB(&plc, filename, B_FALSE); 485 if (ret != KMF_OK) { 486 (void) fprintf(stderr, 487 gettext("Error adding policy to database: 0x%04x\n"), ret); 488 rv = KC_ERR_ADD_POLICY; 489 } 490 491 out: 492 if (filename != NULL) 493 free(filename); 494 495 KMF_FreePolicyRecord(&plc); 496 497 return (rv); 498 } 499