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