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 { 144 KMF_X509_NAME taDN; 145 /* for syntax checking */ 146 if (kmf_dn_parser(plc.ta_name, 147 &taDN) != KMF_OK) { 148 (void) fprintf(stderr, 149 gettext("Error name " 150 "input.\n")); 151 rv = KC_ERR_USAGE; 152 } else { 153 kmf_free_dn(&taDN); 154 } 155 } 156 break; 157 case 's': 158 plc.ta_serial = get_string(optarg_av, &rv); 159 if (plc.ta_serial == NULL) { 160 (void) fprintf(stderr, 161 gettext("Error serial input.\n")); 162 } else { 163 uchar_t *bytes = NULL; 164 size_t bytelen; 165 166 ret = kmf_hexstr_to_bytes( 167 (uchar_t *)plc.ta_serial, 168 &bytes, &bytelen); 169 if (ret != KMF_OK || bytes == NULL) { 170 (void) fprintf(stderr, 171 gettext("serial number " 172 "must be specified as a " 173 "hex number " 174 "(ex: 0x0102030405" 175 "ffeeddee)\n")); 176 rv = KC_ERR_USAGE; 177 } 178 if (bytes != NULL) 179 free(bytes); 180 } 181 break; 182 case 'o': 183 plc.VAL_OCSP_RESPONDER_URI = 184 get_string(optarg_av, &rv); 185 if (plc.VAL_OCSP_RESPONDER_URI == NULL) { 186 (void) fprintf(stderr, gettext( 187 "Error responder input.\n")); 188 } else { 189 ocsp_set_attr++; 190 } 191 break; 192 case 'P': 193 plc.VAL_OCSP_PROXY = 194 get_string(optarg_av, &rv); 195 if (plc.VAL_OCSP_PROXY == NULL) { 196 (void) fprintf(stderr, 197 gettext("Error proxy input.\n")); 198 } else { 199 ocsp_set_attr++; 200 } 201 break; 202 case 'r': 203 plc.VAL_OCSP_URI_FROM_CERT = 204 get_boolean(optarg_av); 205 if (plc.VAL_OCSP_URI_FROM_CERT == -1) { 206 (void) fprintf(stderr, 207 gettext("Error boolean input.\n")); 208 rv = KC_ERR_USAGE; 209 } else { 210 ocsp_set_attr++; 211 } 212 break; 213 case 'T': 214 plc.VAL_OCSP_RESP_LIFETIME = 215 get_string(optarg_av, &rv); 216 if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { 217 (void) fprintf(stderr, 218 gettext("Error time input.\n")); 219 } else { 220 uint32_t adj; 221 /* for syntax checking */ 222 if (str2lifetime( 223 plc.VAL_OCSP_RESP_LIFETIME, 224 &adj) < 0) { 225 (void) fprintf(stderr, 226 gettext("Error time " 227 "input.\n")); 228 rv = KC_ERR_USAGE; 229 } else { 230 ocsp_set_attr++; 231 } 232 } 233 break; 234 case 'R': 235 plc.VAL_OCSP_IGNORE_RESP_SIGN = 236 get_boolean(optarg_av); 237 if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { 238 (void) fprintf(stderr, 239 gettext("Error boolean input.\n")); 240 rv = KC_ERR_USAGE; 241 } else { 242 ocsp_set_attr++; 243 } 244 break; 245 case 'n': 246 plc.VAL_OCSP_RESP_CERT_NAME = 247 get_string(optarg_av, &rv); 248 if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { 249 (void) fprintf(stderr, 250 gettext("Error name input.\n")); 251 } else { 252 KMF_X509_NAME respDN; 253 /* for syntax checking */ 254 if (kmf_dn_parser( 255 plc.VAL_OCSP_RESP_CERT_NAME, 256 &respDN) != KMF_OK) { 257 (void) fprintf(stderr, 258 gettext("Error name " 259 "input.\n")); 260 rv = KC_ERR_USAGE; 261 } else { 262 kmf_free_dn(&respDN); 263 ocsp_set_attr++; 264 } 265 } 266 break; 267 case 'A': 268 plc.VAL_OCSP_RESP_CERT_SERIAL = 269 get_string(optarg_av, &rv); 270 if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { 271 (void) fprintf(stderr, 272 gettext("Error serial input.\n")); 273 } else { 274 uchar_t *bytes = NULL; 275 size_t bytelen; 276 277 ret = kmf_hexstr_to_bytes((uchar_t *) 278 plc.VAL_OCSP_RESP_CERT_SERIAL, 279 &bytes, &bytelen); 280 if (ret != KMF_OK || bytes == NULL) { 281 (void) fprintf(stderr, 282 gettext("serial number " 283 "must be specified as a " 284 "hex number " 285 "(ex: 0x0102030405" 286 "ffeeddee)\n")); 287 rv = KC_ERR_USAGE; 288 break; 289 } 290 if (bytes != NULL) 291 free(bytes); 292 ocsp_set_attr++; 293 } 294 break; 295 case 'c': 296 plc.VAL_CRL_BASEFILENAME = 297 get_string(optarg_av, &rv); 298 if (plc.VAL_CRL_BASEFILENAME == NULL) { 299 (void) fprintf(stderr, 300 gettext("Error boolean input.\n")); 301 } else { 302 crl_set_attr++; 303 } 304 break; 305 case 'I': 306 plc.VAL_CRL_DIRECTORY = 307 get_string(optarg_av, &rv); 308 if (plc.VAL_CRL_DIRECTORY == NULL) { 309 (void) fprintf(stderr, 310 gettext("Error boolean input.\n")); 311 } else { 312 crl_set_attr++; 313 } 314 break; 315 case 'g': 316 plc.VAL_CRL_GET_URI = get_boolean(optarg_av); 317 if (plc.VAL_CRL_GET_URI == -1) { 318 (void) fprintf(stderr, 319 gettext("Error boolean input.\n")); 320 rv = KC_ERR_USAGE; 321 } else { 322 crl_set_attr++; 323 } 324 break; 325 case 'X': 326 plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); 327 if (plc.VAL_CRL_PROXY == NULL) { 328 (void) fprintf(stderr, 329 gettext("Error proxy input.\n")); 330 } else { 331 crl_set_attr++; 332 } 333 break; 334 case 'S': 335 plc.VAL_CRL_IGNORE_SIGN = 336 get_boolean(optarg_av); 337 if (plc.VAL_CRL_IGNORE_SIGN == -1) { 338 (void) fprintf(stderr, 339 gettext("Error boolean input.\n")); 340 rv = KC_ERR_USAGE; 341 } else { 342 crl_set_attr++; 343 } 344 break; 345 case 'D': 346 plc.VAL_CRL_IGNORE_DATE = 347 get_boolean(optarg_av); 348 if (plc.VAL_CRL_IGNORE_DATE == -1) { 349 (void) fprintf(stderr, 350 gettext("Error boolean input.\n")); 351 rv = KC_ERR_USAGE; 352 } else { 353 crl_set_attr++; 354 } 355 break; 356 case 'u': 357 plc.ku_bits = parseKUlist(optarg_av); 358 if (plc.ku_bits == 0) { 359 (void) fprintf(stderr, gettext( 360 "Error keyusage input.\n")); 361 rv = KC_ERR_USAGE; 362 } 363 break; 364 case 'E': 365 if (parseEKUNames(optarg_av, &plc) != 0) { 366 (void) fprintf(stderr, 367 gettext("Error EKU input.\n")); 368 rv = KC_ERR_USAGE; 369 } 370 break; 371 case 'O': 372 if (parseEKUOIDs(optarg_av, &plc) != 0) { 373 (void) fprintf(stderr, 374 gettext("Error EKU OID input.\n")); 375 rv = KC_ERR_USAGE; 376 } 377 break; 378 case 'm': 379 plc.mapper.mapname = get_string(optarg_av, &rv); 380 if (plc.mapper.mapname == NULL) { 381 (void) fprintf(stderr, 382 gettext("Error mapper-name " 383 "input.\n")); 384 } 385 break; 386 case 'M': 387 plc.mapper.dir = get_string(optarg_av, &rv); 388 if (plc.mapper.dir == NULL) { 389 (void) fprintf(stderr, 390 gettext("Error mapper-dir " 391 "input.\n")); 392 } 393 break; 394 case 'Q': 395 plc.mapper.pathname = get_string(optarg_av, 396 &rv); 397 if (plc.mapper.pathname == NULL) { 398 (void) fprintf(stderr, 399 gettext("Error mapper-pathname " 400 "input.\n")); 401 } 402 break; 403 case 'q': 404 plc.mapper.options = get_string(optarg_av, &rv); 405 if (plc.mapper.options == NULL) { 406 (void) fprintf(stderr, 407 gettext("Error mapper-options " 408 "input.\n")); 409 } 410 break; 411 default: 412 (void) fprintf(stderr, 413 gettext("Error input option.\n")); 414 rv = KC_ERR_USAGE; 415 break; 416 } 417 418 if (rv != KC_OK) 419 goto out; 420 } 421 422 /* No additional args allowed. */ 423 argc -= optind_av; 424 if (argc) { 425 (void) fprintf(stderr, 426 gettext("Error input option\n")); 427 rv = KC_ERR_USAGE; 428 goto out; 429 } 430 431 if (filename == NULL) { 432 filename = strdup(KMF_DEFAULT_POLICY_FILE); 433 if (filename == NULL) { 434 rv = KC_ERR_MEMORY; 435 goto out; 436 } 437 } 438 439 /* 440 * Must have a policy name. The policy name can not be default 441 * if using the default policy file. 442 */ 443 if (plc.name == NULL) { 444 (void) fprintf(stderr, 445 gettext("You must specify a policy name\n")); 446 rv = KC_ERR_USAGE; 447 goto out; 448 } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && 449 strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { 450 (void) fprintf(stderr, 451 gettext("Can not create a default policy in the default " 452 "policy file\n")); 453 rv = KC_ERR_USAGE; 454 goto out; 455 } 456 457 /* 458 * If the policy file exists and the policy is in the policy file 459 * already, we will not create it again. 460 */ 461 if (access(filename, R_OK) == 0) { 462 POLICY_LIST *plclist = NULL, *pnode; 463 int found = 0; 464 465 rv = load_policies(filename, &plclist); 466 if (rv != KMF_OK) 467 goto out; 468 469 pnode = plclist; 470 while (pnode != NULL && !found) { 471 if (strcmp(plc.name, pnode->plc.name) == 0) 472 found++; 473 pnode = pnode->next; 474 } 475 free_policy_list(plclist); 476 477 if (found) { 478 (void) fprintf(stderr, 479 gettext("Could not create policy \"%s\" - exists " 480 "already\n"), plc.name); 481 rv = KC_ERR_USAGE; 482 goto out; 483 } 484 } 485 486 /* 487 * If any OCSP attribute is set, turn on the OCSP checking flag. 488 * Also set "has_resp_cert" to be true, if the responder cert 489 * is provided. 490 */ 491 if (ocsp_set_attr > 0) 492 plc.revocation |= KMF_REVOCATION_METHOD_OCSP; 493 494 if (plc.VAL_OCSP_RESP_CERT.name != NULL && 495 plc.VAL_OCSP_RESP_CERT.serial != NULL) { 496 plc.VAL_OCSP.has_resp_cert = B_TRUE; 497 } 498 499 /* 500 * Setting mapper-name (with optional mapper-dir) and mapper-pathname is 501 * mutually exclusive. Also, you cannot set options only, you need the 502 * name or pathname, and you can set the directory only with the name, 503 * not the pathname. 504 */ 505 if ((plc.mapper.mapname != NULL && plc.mapper.pathname != NULL) || 506 (plc.mapper.dir != NULL && plc.mapper.pathname != NULL) || 507 (plc.mapper.dir != NULL && plc.mapper.mapname == NULL) || 508 (plc.mapper.options != NULL && plc.mapper.mapname == NULL && 509 plc.mapper.pathname == NULL)) { 510 (void) fprintf(stderr, 511 gettext("Error in mapper input options\n")); 512 rv = KC_ERR_USAGE; 513 goto out; 514 } 515 516 /* 517 * If any CRL attribute is set, turn on the CRL checking flag. 518 */ 519 if (crl_set_attr > 0) 520 plc.revocation |= KMF_REVOCATION_METHOD_CRL; 521 522 /* 523 * Does a sanity check on the new policy. 524 */ 525 ret = kmf_verify_policy(&plc); 526 if (ret != KMF_OK) { 527 print_sanity_error(ret); 528 rv = KC_ERR_ADD_POLICY; 529 goto out; 530 } 531 532 /* 533 * Add to the DB. 534 */ 535 ret = kmf_add_policy_to_db(&plc, filename, B_FALSE); 536 if (ret != KMF_OK) { 537 (void) fprintf(stderr, 538 gettext("Error adding policy to database: 0x%04x\n"), ret); 539 rv = KC_ERR_ADD_POLICY; 540 } 541 542 out: 543 if (filename != NULL) 544 free(filename); 545 546 kmf_free_policy_record(&plc); 547 548 return (rv); 549 } 550