1d00756ccSwyllys /* 2d00756ccSwyllys * CDDL HEADER START 3d00756ccSwyllys * 4d00756ccSwyllys * The contents of this file are subject to the terms of the 5d00756ccSwyllys * Common Development and Distribution License (the "License"). 6d00756ccSwyllys * You may not use this file except in compliance with the License. 7d00756ccSwyllys * 8d00756ccSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d00756ccSwyllys * or http://www.opensolaris.org/os/licensing. 10d00756ccSwyllys * See the License for the specific language governing permissions 11d00756ccSwyllys * and limitations under the License. 12d00756ccSwyllys * 13d00756ccSwyllys * When distributing Covered Code, include this CDDL HEADER in each 14d00756ccSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d00756ccSwyllys * If applicable, add the following below this CDDL HEADER, with the 16d00756ccSwyllys * fields enclosed by brackets "[]" replaced with your own identifying 17d00756ccSwyllys * information: Portions Copyright [yyyy] [name of copyright owner] 18d00756ccSwyllys * 19d00756ccSwyllys * CDDL HEADER END 2072ca8cc9SWyllys Ingersoll * 2172ca8cc9SWyllys Ingersoll * 22*e65e5c2dSWyllys Ingersoll * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23d00756ccSwyllys * Use is subject to license terms. 24d00756ccSwyllys */ 25d00756ccSwyllys 26d00756ccSwyllys /* 27d00756ccSwyllys * This file implements the sign CSR operation for this tool. 28d00756ccSwyllys */ 29d00756ccSwyllys 30d00756ccSwyllys #include <stdio.h> 31d00756ccSwyllys #include <errno.h> 32d00756ccSwyllys #include <string.h> 33d00756ccSwyllys #include <cryptoutil.h> 34d00756ccSwyllys #include <security/cryptoki.h> 35d00756ccSwyllys #include "common.h" 36d00756ccSwyllys 37d00756ccSwyllys #include <kmfapi.h> 38448b8615Swyllys #include <kmfapiP.h> 39448b8615Swyllys 40d00756ccSwyllys #define SET_VALUE(f, s) \ 41d00756ccSwyllys rv = f; \ 42d00756ccSwyllys if (rv != KMF_OK) { \ 43d00756ccSwyllys cryptoerror(LOG_STDERR, \ 44d00756ccSwyllys gettext("Failed to set %s: 0x%02x\n"), s, rv); \ 45d00756ccSwyllys goto cleanup; \ 46d00756ccSwyllys } 47d00756ccSwyllys 48d00756ccSwyllys 49d00756ccSwyllys static int 50d00756ccSwyllys read_csrdata(KMF_HANDLE_T handle, char *csrfile, KMF_CSR_DATA *csrdata) 51d00756ccSwyllys { 52d00756ccSwyllys KMF_RETURN rv = KMF_OK; 53d00756ccSwyllys KMF_ENCODE_FORMAT csrfmt; 54d00756ccSwyllys KMF_DATA csrfiledata = {NULL, 0}; 55d00756ccSwyllys KMF_DATA rawcsr = {NULL, 0}; 56d00756ccSwyllys 57d00756ccSwyllys rv = kmf_get_file_format(csrfile, &csrfmt); 58d00756ccSwyllys if (rv != KMF_OK) 59d00756ccSwyllys return (rv); 60d00756ccSwyllys 61d00756ccSwyllys rv = kmf_read_input_file(handle, csrfile, &csrfiledata); 62d00756ccSwyllys if (rv != KMF_OK) 63d00756ccSwyllys return (rv); 64d00756ccSwyllys 65d00756ccSwyllys if (csrfmt == KMF_FORMAT_PEM) { 66d00756ccSwyllys rv = kmf_pem_to_der(csrfiledata.Data, csrfiledata.Length, 67d00756ccSwyllys &rawcsr.Data, (int *)&rawcsr.Length); 68d00756ccSwyllys if (rv != KMF_OK) 69d00756ccSwyllys return (rv); 70d00756ccSwyllys 71d00756ccSwyllys kmf_free_data(&csrfiledata); 72d00756ccSwyllys } else { 73d00756ccSwyllys rawcsr.Data = csrfiledata.Data; 74d00756ccSwyllys rawcsr.Length = csrfiledata.Length; 75d00756ccSwyllys } 76d00756ccSwyllys 77d00756ccSwyllys rv = kmf_decode_csr(handle, &rawcsr, csrdata); 78d00756ccSwyllys kmf_free_data(&rawcsr); 79d00756ccSwyllys 80d00756ccSwyllys return (rv); 81d00756ccSwyllys } 82d00756ccSwyllys 83448b8615Swyllys static KMF_RETURN 84448b8615Swyllys find_csr_extn(KMF_X509_EXTENSIONS *extnlist, KMF_OID *extoid, 85448b8615Swyllys KMF_X509_EXTENSION *outextn) 86448b8615Swyllys { 87448b8615Swyllys int i, found = 0; 88448b8615Swyllys KMF_X509_EXTENSION *eptr; 89448b8615Swyllys KMF_RETURN rv = KMF_OK; 90448b8615Swyllys 91448b8615Swyllys (void) memset(outextn, 0, sizeof (KMF_X509_EXTENSION)); 92448b8615Swyllys for (i = 0; !found && i < extnlist->numberOfExtensions; i++) { 93448b8615Swyllys eptr = &extnlist->extensions[i]; 94448b8615Swyllys if (IsEqualOid(extoid, &eptr->extnId)) { 95448b8615Swyllys rv = copy_extension_data(outextn, eptr); 96448b8615Swyllys found++; 97448b8615Swyllys } 98448b8615Swyllys } 99448b8615Swyllys if (found == 0 || rv != KMF_OK) 100448b8615Swyllys return (1); 101448b8615Swyllys else 102448b8615Swyllys return (rv); 103448b8615Swyllys } 104448b8615Swyllys 105d00756ccSwyllys static int 106d00756ccSwyllys build_cert_from_csr(KMF_CSR_DATA *csrdata, 107d00756ccSwyllys KMF_X509_CERTIFICATE *signedCert, 108d00756ccSwyllys KMF_BIGINT *serial, 109d00756ccSwyllys uint32_t ltime, 110d00756ccSwyllys char *issuer, char *subject, 111d00756ccSwyllys char *altname, 112d00756ccSwyllys KMF_GENERALNAMECHOICES alttype, 113d00756ccSwyllys int altcrit, 114d00756ccSwyllys uint16_t kubits, 115d00756ccSwyllys int kucrit, 116d00756ccSwyllys EKU_LIST *ekulist) 117d00756ccSwyllys { 118d00756ccSwyllys KMF_RETURN rv = KMF_OK; 119d00756ccSwyllys KMF_X509_NAME issuerDN, subjectDN; 120d00756ccSwyllys 121d00756ccSwyllys /* 122d00756ccSwyllys * If the CSR is ok, now we can generate the final certificate. 123d00756ccSwyllys */ 124d00756ccSwyllys (void) memset(signedCert, 0, sizeof (KMF_X509_CERTIFICATE)); 125d00756ccSwyllys (void) memset(&issuerDN, 0, sizeof (issuerDN)); 126d00756ccSwyllys (void) memset(&subjectDN, 0, sizeof (subjectDN)); 127d00756ccSwyllys 128d00756ccSwyllys SET_VALUE(kmf_set_cert_version(signedCert, 2), "version number"); 129d00756ccSwyllys 130d00756ccSwyllys SET_VALUE(kmf_set_cert_serial(signedCert, serial), "serial number"); 131d00756ccSwyllys 132d00756ccSwyllys SET_VALUE(kmf_set_cert_validity(signedCert, NULL, ltime), 133d00756ccSwyllys "validity time"); 134d00756ccSwyllys 135d00756ccSwyllys if (issuer) { 136d00756ccSwyllys if (kmf_dn_parser(issuer, &issuerDN) != KMF_OK) { 137d00756ccSwyllys cryptoerror(LOG_STDERR, 138d00756ccSwyllys gettext("Issuer name cannot be parsed\n")); 139d00756ccSwyllys return (PK_ERR_USAGE); 140d00756ccSwyllys } 141d00756ccSwyllys SET_VALUE(kmf_set_cert_issuer(signedCert, &issuerDN), 142d00756ccSwyllys "Issuer Name"); 143d00756ccSwyllys } 144d00756ccSwyllys if (subject) { 145d00756ccSwyllys if (kmf_dn_parser(subject, &subjectDN) != KMF_OK) { 146d00756ccSwyllys cryptoerror(LOG_STDERR, 147d00756ccSwyllys gettext("Subject name cannot be parsed\n")); 148d00756ccSwyllys return (PK_ERR_USAGE); 149d00756ccSwyllys } 150d00756ccSwyllys SET_VALUE(kmf_set_cert_subject(signedCert, &subjectDN), 151d00756ccSwyllys "Subject Name"); 152d00756ccSwyllys } else { 153d00756ccSwyllys signedCert->certificate.subject = csrdata->csr.subject; 154d00756ccSwyllys } 155d00756ccSwyllys 156d00756ccSwyllys signedCert->certificate.subjectPublicKeyInfo = 157d00756ccSwyllys csrdata->csr.subjectPublicKeyInfo; 158d00756ccSwyllys 159d00756ccSwyllys signedCert->certificate.extensions = csrdata->csr.extensions; 160d00756ccSwyllys 161d00756ccSwyllys signedCert->certificate.signature = 162d00756ccSwyllys csrdata->signature.algorithmIdentifier; 163d00756ccSwyllys 164d00756ccSwyllys if (kubits != 0) { 165448b8615Swyllys KMF_X509_EXTENSION extn; 166448b8615Swyllys uint16_t oldbits; 167448b8615Swyllys /* 168448b8615Swyllys * If the CSR already has KU, merge them. 169448b8615Swyllys */ 170448b8615Swyllys rv = find_csr_extn(&csrdata->csr.extensions, 171448b8615Swyllys (KMF_OID *)&KMFOID_KeyUsage, &extn); 172448b8615Swyllys if (rv == KMF_OK) { 173448b8615Swyllys extn.critical |= kucrit; 174448b8615Swyllys if (extn.value.tagAndValue->value.Length > 1) { 175448b8615Swyllys oldbits = 176448b8615Swyllys extn.value.tagAndValue->value.Data[1] << 8; 177448b8615Swyllys } else { 178448b8615Swyllys oldbits = 179448b8615Swyllys extn.value.tagAndValue->value.Data[0]; 180448b8615Swyllys } 181448b8615Swyllys oldbits |= kubits; 182448b8615Swyllys } else { 183d00756ccSwyllys SET_VALUE(kmf_set_cert_ku(signedCert, kucrit, kubits), 184d00756ccSwyllys "KeyUsage"); 185d00756ccSwyllys } 186448b8615Swyllys } 187d00756ccSwyllys if (altname != NULL) { 188d00756ccSwyllys SET_VALUE(kmf_set_cert_subject_altname(signedCert, 189d00756ccSwyllys altcrit, alttype, altname), "subjectAltName"); 190d00756ccSwyllys } 191d00756ccSwyllys if (ekulist != NULL) { 192d00756ccSwyllys int i; 193d00756ccSwyllys for (i = 0; rv == KMF_OK && i < ekulist->eku_count; i++) { 194d00756ccSwyllys SET_VALUE(kmf_add_cert_eku(signedCert, 195d00756ccSwyllys &ekulist->ekulist[i], 196d00756ccSwyllys ekulist->critlist[i]), "Extended Key Usage"); 197d00756ccSwyllys } 198d00756ccSwyllys } 199d00756ccSwyllys cleanup: 200d00756ccSwyllys if (issuer != NULL) 201d00756ccSwyllys kmf_free_dn(&issuerDN); 202d00756ccSwyllys if (subject != NULL) 203d00756ccSwyllys kmf_free_dn(&subjectDN); 204d00756ccSwyllys 205d00756ccSwyllys return (rv); 206d00756ccSwyllys } 207d00756ccSwyllys 208d00756ccSwyllys static int 209d00756ccSwyllys pk_sign_cert(KMF_HANDLE_T handle, KMF_X509_CERTIFICATE *cert, 210d00756ccSwyllys KMF_KEY_HANDLE *key, KMF_DATA *outdata) 211d00756ccSwyllys { 212d00756ccSwyllys KMF_RETURN rv; 213d00756ccSwyllys int numattr; 214d00756ccSwyllys KMF_ATTRIBUTE attrlist[4]; 215d00756ccSwyllys 216d00756ccSwyllys numattr = 0; 217d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 218d00756ccSwyllys &key->kstype, sizeof (KMF_KEYSTORE_TYPE)); 219d00756ccSwyllys numattr++; 220d00756ccSwyllys 221d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, 222d00756ccSwyllys key, sizeof (KMF_KEY_HANDLE_ATTR)); 223d00756ccSwyllys numattr++; 224d00756ccSwyllys 225d00756ccSwyllys /* cert data that is to be signed */ 226d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_X509_CERTIFICATE_ATTR, 227d00756ccSwyllys cert, sizeof (KMF_X509_CERTIFICATE)); 228d00756ccSwyllys numattr++; 229d00756ccSwyllys 230d00756ccSwyllys /* output buffer for the signed cert */ 231d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, 232d00756ccSwyllys outdata, sizeof (KMF_DATA)); 233d00756ccSwyllys numattr++; 234d00756ccSwyllys 235d00756ccSwyllys if ((rv = kmf_sign_cert(handle, numattr, attrlist)) != KMF_OK) { 236d00756ccSwyllys cryptoerror(LOG_STDERR, 237d00756ccSwyllys gettext("Failed to sign certificate.\n")); 238d00756ccSwyllys return (rv); 239d00756ccSwyllys } 240d00756ccSwyllys 241d00756ccSwyllys return (rv); 242d00756ccSwyllys } 243d00756ccSwyllys 244d00756ccSwyllys static int 245d00756ccSwyllys pk_signcsr_files(KMF_HANDLE_T handle, 246d00756ccSwyllys char *signkey, 247d00756ccSwyllys char *csrfile, 248d00756ccSwyllys KMF_BIGINT *serial, 249d00756ccSwyllys char *certfile, 250d00756ccSwyllys char *issuer, 251d00756ccSwyllys char *subject, 252d00756ccSwyllys char *altname, 253d00756ccSwyllys KMF_GENERALNAMECHOICES alttype, 254d00756ccSwyllys int altcrit, 255d00756ccSwyllys uint16_t kubits, 256d00756ccSwyllys int kucrit, 257d00756ccSwyllys EKU_LIST *ekulist, 258d00756ccSwyllys uint32_t ltime, 259d00756ccSwyllys KMF_ENCODE_FORMAT fmt) 260d00756ccSwyllys { 261d00756ccSwyllys KMF_RETURN rv = KMF_OK; 262d00756ccSwyllys KMF_CSR_DATA csrdata; 263d00756ccSwyllys KMF_ATTRIBUTE attrlist[16]; 264d00756ccSwyllys KMF_X509_CERTIFICATE signedCert; 265d00756ccSwyllys KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL; 266d00756ccSwyllys KMF_KEY_CLASS keyclass = KMF_ASYM_PRI; 267d00756ccSwyllys KMF_KEY_HANDLE cakey; 268d00756ccSwyllys KMF_DATA certdata = {NULL, 0}; 269d00756ccSwyllys int numattr, count; 270d00756ccSwyllys 271*e65e5c2dSWyllys Ingersoll (void) memset(&cakey, 0, sizeof (cakey)); 272*e65e5c2dSWyllys Ingersoll (void) memset(&signedCert, 0, sizeof (signedCert)); 273*e65e5c2dSWyllys Ingersoll 274d00756ccSwyllys rv = read_csrdata(handle, csrfile, &csrdata); 275d00756ccSwyllys if (rv != KMF_OK) { 276d00756ccSwyllys cryptoerror(LOG_STDERR, 277d00756ccSwyllys gettext("Error reading CSR data\n")); 278d00756ccSwyllys return (rv); 279d00756ccSwyllys } 280d00756ccSwyllys 281d00756ccSwyllys /* verify the signature first */ 282d00756ccSwyllys numattr = 0; 283d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR, 284d00756ccSwyllys &csrdata, sizeof (csrdata)); 285d00756ccSwyllys numattr++; 286d00756ccSwyllys 287d00756ccSwyllys rv = kmf_verify_csr(handle, numattr, attrlist); 288d00756ccSwyllys if (rv != KMF_OK) { 289d00756ccSwyllys cryptoerror(LOG_STDERR, gettext("CSR signature " 290d00756ccSwyllys "verification failed.\n")); 291d00756ccSwyllys goto cleanup; 292d00756ccSwyllys } 293d00756ccSwyllys 294d00756ccSwyllys rv = build_cert_from_csr(&csrdata, &signedCert, serial, ltime, 295d00756ccSwyllys issuer, subject, altname, alttype, altcrit, kubits, 296d00756ccSwyllys kucrit, ekulist); 297d00756ccSwyllys 298d00756ccSwyllys if (rv != KMF_OK) 299d00756ccSwyllys goto cleanup; 300d00756ccSwyllys 301d00756ccSwyllys /* 302d00756ccSwyllys * Find the signing key. 303d00756ccSwyllys */ 304d00756ccSwyllys (void) memset(&cakey, 0, sizeof (cakey)); 305d00756ccSwyllys 306d00756ccSwyllys numattr = 0; 307d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 308d00756ccSwyllys &kstype, sizeof (kstype)); 309d00756ccSwyllys numattr++; 310d00756ccSwyllys 311d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR, 312d00756ccSwyllys signkey, strlen(signkey)); 313d00756ccSwyllys numattr++; 314d00756ccSwyllys 315d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, 316d00756ccSwyllys &keyclass, sizeof (keyclass)); 317d00756ccSwyllys numattr++; 318d00756ccSwyllys 319d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, 320d00756ccSwyllys &cakey, sizeof (cakey)); 321d00756ccSwyllys numattr++; 322d00756ccSwyllys 323d00756ccSwyllys count = 1; 324d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, 325d00756ccSwyllys &count, sizeof (count)); 326d00756ccSwyllys numattr++; 327d00756ccSwyllys 328d00756ccSwyllys rv = kmf_find_key(handle, numattr, attrlist); 329d00756ccSwyllys if (rv != KMF_OK) { 330d00756ccSwyllys cryptoerror(LOG_STDERR, gettext( 331d00756ccSwyllys "Error finding CA signing key\n")); 332d00756ccSwyllys goto cleanup; 333d00756ccSwyllys } 334d00756ccSwyllys 335d00756ccSwyllys rv = pk_sign_cert(handle, &signedCert, &cakey, &certdata); 336d00756ccSwyllys if (rv != KMF_OK) { 337d00756ccSwyllys cryptoerror(LOG_STDERR, gettext( 338d00756ccSwyllys "Error signing certificate.\n")); 339d00756ccSwyllys goto cleanup; 340d00756ccSwyllys } 341d00756ccSwyllys 342d00756ccSwyllys rv = kmf_create_cert_file(&certdata, fmt, certfile); 343d00756ccSwyllys 344d00756ccSwyllys cleanup: 345d00756ccSwyllys kmf_free_signed_csr(&csrdata); 346d00756ccSwyllys kmf_free_data(&certdata); 347d00756ccSwyllys kmf_free_kmf_key(handle, &cakey); 348d00756ccSwyllys return (rv); 349d00756ccSwyllys } 350d00756ccSwyllys 351d00756ccSwyllys static int 352d00756ccSwyllys pk_signcsr_pk11_nss(KMF_HANDLE_T handle, 353d00756ccSwyllys KMF_KEYSTORE_TYPE kstype, 354d00756ccSwyllys char *dir, char *prefix, 355d00756ccSwyllys char *token, KMF_CREDENTIAL *cred, 356d00756ccSwyllys char *signkey, char *csrfile, 357d00756ccSwyllys KMF_BIGINT *serial, char *certfile, char *issuer, char *subject, 358d00756ccSwyllys char *altname, KMF_GENERALNAMECHOICES alttype, int altcrit, 359d00756ccSwyllys uint16_t kubits, int kucrit, 360d00756ccSwyllys EKU_LIST *ekulist, uint32_t ltime, 361d00756ccSwyllys KMF_ENCODE_FORMAT fmt, int store, char *outlabel) 362d00756ccSwyllys { 363d00756ccSwyllys KMF_RETURN rv = KMF_OK; 364d00756ccSwyllys KMF_DATA outcert = {NULL, 0}; 365d00756ccSwyllys KMF_CSR_DATA csrdata; 366d00756ccSwyllys KMF_KEY_HANDLE casignkey; 367d00756ccSwyllys KMF_KEY_CLASS keyclass = KMF_ASYM_PRI; 368d00756ccSwyllys int numattr = 0; 369d00756ccSwyllys int keys = 1; 370d00756ccSwyllys KMF_ATTRIBUTE attrlist[16]; 371d00756ccSwyllys KMF_X509_CERTIFICATE signedCert; 372d00756ccSwyllys boolean_t token_bool = B_TRUE; 373d00756ccSwyllys boolean_t private_bool = B_TRUE; 374d00756ccSwyllys 37572ca8cc9SWyllys Ingersoll (void) memset(&casignkey, 0, sizeof (KMF_KEY_HANDLE)); 376*e65e5c2dSWyllys Ingersoll (void) memset(&signedCert, 0, sizeof (signedCert)); 37772ca8cc9SWyllys Ingersoll 378d00756ccSwyllys rv = read_csrdata(handle, csrfile, &csrdata); 379d00756ccSwyllys if (rv != KMF_OK) { 380d00756ccSwyllys cryptoerror(LOG_STDERR, 381d00756ccSwyllys gettext("Error reading CSR data\n")); 382d00756ccSwyllys return (rv); 383d00756ccSwyllys } 384d00756ccSwyllys 385d00756ccSwyllys if (kstype == KMF_KEYSTORE_PK11TOKEN) { 386d00756ccSwyllys rv = select_token(handle, token, FALSE); 387d00756ccSwyllys } else if (kstype == KMF_KEYSTORE_NSS) { 388d00756ccSwyllys rv = configure_nss(handle, dir, prefix); 389d00756ccSwyllys } 390d00756ccSwyllys 391d00756ccSwyllys /* verify the signature first */ 392d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CSR_DATA_ATTR, 393d00756ccSwyllys &csrdata, sizeof (csrdata)); 394d00756ccSwyllys numattr++; 395d00756ccSwyllys 396d00756ccSwyllys rv = kmf_verify_csr(handle, numattr, attrlist); 397d00756ccSwyllys if (rv != KMF_OK) { 398d00756ccSwyllys cryptoerror(LOG_STDERR, gettext("CSR signature " 399d00756ccSwyllys "verification failed.\n")); 400d00756ccSwyllys goto cleanup; 401d00756ccSwyllys } 402d00756ccSwyllys 403d00756ccSwyllys rv = build_cert_from_csr(&csrdata, 404d00756ccSwyllys &signedCert, serial, ltime, 405d00756ccSwyllys issuer, subject, altname, 406d00756ccSwyllys alttype, altcrit, kubits, 407d00756ccSwyllys kucrit, ekulist); 408d00756ccSwyllys 409d00756ccSwyllys if (rv != KMF_OK) 410d00756ccSwyllys goto cleanup; 411d00756ccSwyllys 412d00756ccSwyllys /* 413d00756ccSwyllys * Find the signing key. 414d00756ccSwyllys */ 415d00756ccSwyllys numattr = 0; 416d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 417d00756ccSwyllys &kstype, sizeof (kstype)); 418d00756ccSwyllys numattr++; 419d00756ccSwyllys if (kstype == KMF_KEYSTORE_NSS) { 420d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR, 421d00756ccSwyllys token, strlen(token)); 422d00756ccSwyllys numattr++; 423d00756ccSwyllys } 424d00756ccSwyllys 425d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, signkey, 426d00756ccSwyllys strlen(signkey)); 427d00756ccSwyllys numattr++; 428d00756ccSwyllys 429d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR, 430d00756ccSwyllys &private_bool, sizeof (private_bool)); 431d00756ccSwyllys numattr++; 432d00756ccSwyllys 433d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR, 434d00756ccSwyllys &token_bool, sizeof (token_bool)); 435d00756ccSwyllys numattr++; 436d00756ccSwyllys 437d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR, 438d00756ccSwyllys &keyclass, sizeof (keyclass)); 439d00756ccSwyllys numattr++; 440d00756ccSwyllys 441d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR, 442d00756ccSwyllys cred, sizeof (KMF_CREDENTIAL_ATTR)); 443d00756ccSwyllys numattr++; 444d00756ccSwyllys 445d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR, 446d00756ccSwyllys &keys, sizeof (keys)); 447d00756ccSwyllys numattr++; 448d00756ccSwyllys 449d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR, 450d00756ccSwyllys &casignkey, sizeof (casignkey)); 451d00756ccSwyllys numattr++; 452d00756ccSwyllys 453d00756ccSwyllys rv = kmf_find_key(handle, numattr, attrlist); 454d00756ccSwyllys if (rv != KMF_OK) { 455d00756ccSwyllys cryptoerror(LOG_STDERR, 456d00756ccSwyllys gettext("Failed to find signing key\n")); 457d00756ccSwyllys goto cleanup; 458d00756ccSwyllys } 459d00756ccSwyllys 460d00756ccSwyllys /* 461d00756ccSwyllys * If we found the key, now we can sign the cert. 462d00756ccSwyllys */ 463d00756ccSwyllys rv = pk_sign_cert(handle, &signedCert, &casignkey, &outcert); 464d00756ccSwyllys if (rv != KMF_OK) { 465d00756ccSwyllys cryptoerror(LOG_STDERR, gettext( 466d00756ccSwyllys "Error signing certificate.\n")); 467d00756ccSwyllys goto cleanup; 468d00756ccSwyllys } 469d00756ccSwyllys 470d00756ccSwyllys /* 471d00756ccSwyllys * Store it on the token if the user asked for it. 472d00756ccSwyllys */ 473d00756ccSwyllys if (store) { 474d00756ccSwyllys numattr = 0; 475d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR, 476d00756ccSwyllys &kstype, sizeof (kstype)); 477d00756ccSwyllys numattr++; 478d00756ccSwyllys 479d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_DATA_ATTR, 480d00756ccSwyllys &outcert, sizeof (KMF_DATA)); 481d00756ccSwyllys numattr++; 482d00756ccSwyllys 483d00756ccSwyllys if (outlabel != NULL) { 484d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, 485d00756ccSwyllys KMF_CERT_LABEL_ATTR, 486d00756ccSwyllys outlabel, strlen(outlabel)); 487d00756ccSwyllys numattr++; 488d00756ccSwyllys } 489d00756ccSwyllys 490d00756ccSwyllys if (kstype == KMF_KEYSTORE_NSS) { 491d00756ccSwyllys if (token != NULL) 492d00756ccSwyllys kmf_set_attr_at_index(attrlist, numattr, 493d00756ccSwyllys KMF_TOKEN_LABEL_ATTR, 494d00756ccSwyllys token, strlen(token)); 495d00756ccSwyllys numattr++; 496d00756ccSwyllys } 497d00756ccSwyllys 498d00756ccSwyllys rv = kmf_store_cert(handle, numattr, attrlist); 499d00756ccSwyllys if (rv != KMF_OK) { 500d00756ccSwyllys display_error(handle, rv, 501d00756ccSwyllys gettext("Failed to store cert " 502d00756ccSwyllys "on PKCS#11 token.\n")); 503d00756ccSwyllys rv = KMF_OK; 504d00756ccSwyllys /* Not fatal, we can still write it to a file. */ 505d00756ccSwyllys } 506d00756ccSwyllys } 507d00756ccSwyllys rv = kmf_create_cert_file(&outcert, fmt, certfile); 508d00756ccSwyllys 509d00756ccSwyllys cleanup: 510d00756ccSwyllys kmf_free_signed_csr(&csrdata); 511d00756ccSwyllys kmf_free_data(&outcert); 512d00756ccSwyllys kmf_free_kmf_key(handle, &casignkey); 513d00756ccSwyllys 514d00756ccSwyllys return (rv); 515d00756ccSwyllys } 516d00756ccSwyllys 517d00756ccSwyllys /* 518d00756ccSwyllys * sign a CSR and generate an x509v3 certificate file. 519d00756ccSwyllys */ 520d00756ccSwyllys int 521d00756ccSwyllys pk_signcsr(int argc, char *argv[]) 522d00756ccSwyllys { 523d00756ccSwyllys int opt; 524d00756ccSwyllys extern int optind_av; 525d00756ccSwyllys extern char *optarg_av; 526d00756ccSwyllys char *token_spec = NULL; 527d00756ccSwyllys char *subject = NULL; 528d00756ccSwyllys char *issuer = NULL; 529d00756ccSwyllys char *dir = NULL; 530d00756ccSwyllys char *prefix = NULL; 531d00756ccSwyllys char *csrfile = NULL; 532d00756ccSwyllys char *serstr = NULL; 533d00756ccSwyllys char *ekustr = NULL; 534d00756ccSwyllys char *kustr = NULL; 535d00756ccSwyllys char *format = NULL; 536d00756ccSwyllys char *storestr = NULL; 537d00756ccSwyllys char *altname = NULL; 538d00756ccSwyllys char *certfile = NULL; 539d00756ccSwyllys char *lifetime = NULL; 540d00756ccSwyllys char *signkey = NULL; 541d00756ccSwyllys char *outlabel = NULL; 542d00756ccSwyllys uint32_t ltime = 365 * 24 * 60 * 60; /* 1 Year */ 543d00756ccSwyllys int store = 0; 544d00756ccSwyllys uint16_t kubits = 0; 545d00756ccSwyllys int altcrit = 0, kucrit = 0; 546d00756ccSwyllys KMF_BIGINT serial = { NULL, 0 }; 547d00756ccSwyllys EKU_LIST *ekulist = NULL; 548d00756ccSwyllys KMF_KEYSTORE_TYPE kstype = 0; 549d00756ccSwyllys KMF_RETURN rv = KMF_OK; 550d00756ccSwyllys KMF_HANDLE_T kmfhandle = NULL; 551d00756ccSwyllys KMF_CREDENTIAL tokencred = {NULL, 0}; 552d00756ccSwyllys KMF_GENERALNAMECHOICES alttype = 0; 553d00756ccSwyllys KMF_ENCODE_FORMAT fmt = KMF_FORMAT_PEM; 554d00756ccSwyllys 555d00756ccSwyllys /* Parse command line options. Do NOT i18n/l10n. */ 556d00756ccSwyllys while ((opt = getopt_av(argc, argv, 557d00756ccSwyllys "k:(keystore)c:(csr)T:(token)d:(dir)" 558d00756ccSwyllys "p:(prefix)S:(serial)s:(subject)a:(altname)" 559d00756ccSwyllys "t:(store)F:(format)K:(keyusage)l:(signkey)" 560d00756ccSwyllys "L:(lifetime)e:(eku)i:(issuer)" 561d00756ccSwyllys "n:(outlabel)o:(outcert)")) != EOF) { 562d00756ccSwyllys if (EMPTYSTRING(optarg_av)) 563d00756ccSwyllys return (PK_ERR_USAGE); 564d00756ccSwyllys switch (opt) { 565d00756ccSwyllys case 'k': 566d00756ccSwyllys if (kstype != 0) 567d00756ccSwyllys return (PK_ERR_USAGE); 568d00756ccSwyllys kstype = KS2Int(optarg_av); 569d00756ccSwyllys if (kstype == 0) 570d00756ccSwyllys return (PK_ERR_USAGE); 571d00756ccSwyllys break; 572d00756ccSwyllys case 't': 573d00756ccSwyllys if (storestr != NULL) 574d00756ccSwyllys return (PK_ERR_USAGE); 575d00756ccSwyllys storestr = optarg_av; 576d00756ccSwyllys store = yn_to_int(optarg_av); 577d00756ccSwyllys if (store == -1) 578d00756ccSwyllys return (PK_ERR_USAGE); 579d00756ccSwyllys break; 580d00756ccSwyllys case 'a': 581d00756ccSwyllys if (altname) 582d00756ccSwyllys return (PK_ERR_USAGE); 583d00756ccSwyllys altname = optarg_av; 584d00756ccSwyllys break; 585d00756ccSwyllys case 's': 586d00756ccSwyllys if (subject) 587d00756ccSwyllys return (PK_ERR_USAGE); 588d00756ccSwyllys subject = optarg_av; 589d00756ccSwyllys break; 590d00756ccSwyllys case 'i': 591d00756ccSwyllys if (issuer) 592d00756ccSwyllys return (PK_ERR_USAGE); 593d00756ccSwyllys issuer = optarg_av; 594d00756ccSwyllys break; 595d00756ccSwyllys case 'd': 596d00756ccSwyllys if (dir) 597d00756ccSwyllys return (PK_ERR_USAGE); 598d00756ccSwyllys dir = optarg_av; 599d00756ccSwyllys break; 600d00756ccSwyllys case 'p': 601d00756ccSwyllys if (prefix) 602d00756ccSwyllys return (PK_ERR_USAGE); 603d00756ccSwyllys prefix = optarg_av; 604d00756ccSwyllys break; 605d00756ccSwyllys case 'S': 606d00756ccSwyllys if (serstr != NULL) 607d00756ccSwyllys return (PK_ERR_USAGE); 608d00756ccSwyllys serstr = optarg_av; 609d00756ccSwyllys break; 610d00756ccSwyllys case 'c': 611d00756ccSwyllys if (csrfile) 612d00756ccSwyllys return (PK_ERR_USAGE); 613d00756ccSwyllys csrfile = optarg_av; 614d00756ccSwyllys break; 615d00756ccSwyllys case 'T': /* token specifier */ 616d00756ccSwyllys if (token_spec) 617d00756ccSwyllys return (PK_ERR_USAGE); 618d00756ccSwyllys token_spec = optarg_av; 619d00756ccSwyllys break; 620d00756ccSwyllys case 'l': /* object with specific label */ 621d00756ccSwyllys if (signkey) 622d00756ccSwyllys return (PK_ERR_USAGE); 623d00756ccSwyllys signkey = optarg_av; 624d00756ccSwyllys break; 625d00756ccSwyllys case 'e': 626d00756ccSwyllys if (ekustr != NULL) 627d00756ccSwyllys return (PK_ERR_USAGE); 628d00756ccSwyllys ekustr = optarg_av; 629d00756ccSwyllys break; 630d00756ccSwyllys case 'K': 631d00756ccSwyllys if (kustr != NULL) 632d00756ccSwyllys return (PK_ERR_USAGE); 633d00756ccSwyllys kustr = optarg_av; 634d00756ccSwyllys break; 635d00756ccSwyllys case 'F': 636d00756ccSwyllys if (format != NULL) 637d00756ccSwyllys return (PK_ERR_USAGE); 638d00756ccSwyllys format = optarg_av; 639d00756ccSwyllys break; 640d00756ccSwyllys case 'o': 641d00756ccSwyllys if (certfile != NULL) 642d00756ccSwyllys return (PK_ERR_USAGE); 643d00756ccSwyllys certfile = optarg_av; 644d00756ccSwyllys break; 645d00756ccSwyllys case 'L': 646d00756ccSwyllys if (lifetime != NULL) 647d00756ccSwyllys return (PK_ERR_USAGE); 648d00756ccSwyllys lifetime = optarg_av; 649d00756ccSwyllys break; 650d00756ccSwyllys case 'n': 651d00756ccSwyllys if (outlabel != NULL) 652d00756ccSwyllys return (PK_ERR_USAGE); 653d00756ccSwyllys outlabel = optarg_av; 654d00756ccSwyllys break; 655d00756ccSwyllys default: 656d00756ccSwyllys return (PK_ERR_USAGE); 657d00756ccSwyllys } 658d00756ccSwyllys } 659d00756ccSwyllys /* No additional args allowed. */ 660d00756ccSwyllys argc -= optind_av; 661d00756ccSwyllys argv += optind_av; 662d00756ccSwyllys if (argc) 663d00756ccSwyllys return (PK_ERR_USAGE); 664d00756ccSwyllys 665d00756ccSwyllys 666d00756ccSwyllys /* Assume keystore = PKCS#11 if not specified. */ 667d00756ccSwyllys if (kstype == 0) 668d00756ccSwyllys kstype = KMF_KEYSTORE_PK11TOKEN; 669d00756ccSwyllys 670577f4726Swyllys DIR_OPTION_CHECK(kstype, dir); 671577f4726Swyllys 672d00756ccSwyllys if (signkey == NULL) { 673d00756ccSwyllys (void) fprintf(stderr, gettext("The signing key label " 674d00756ccSwyllys "or filename was not specified\n")); 675d00756ccSwyllys return (PK_ERR_USAGE); 676d00756ccSwyllys } 677d00756ccSwyllys if (csrfile == NULL) { 678d00756ccSwyllys (void) fprintf(stderr, gettext("The CSR filename was not" 679d00756ccSwyllys " specified\n")); 680d00756ccSwyllys return (PK_ERR_USAGE); 681d00756ccSwyllys } 682d00756ccSwyllys if (certfile == NULL) { 683d00756ccSwyllys (void) fprintf(stderr, gettext("The output certificate file " 684d00756ccSwyllys "was not specified\n")); 685d00756ccSwyllys return (PK_ERR_USAGE); 686d00756ccSwyllys } 687d00756ccSwyllys if (issuer == NULL) { 688d00756ccSwyllys (void) fprintf(stderr, gettext("The issuer DN " 689d00756ccSwyllys "was not specified\n")); 690d00756ccSwyllys return (PK_ERR_USAGE); 691d00756ccSwyllys } 692d00756ccSwyllys if (lifetime != NULL) { 693d00756ccSwyllys if (Str2Lifetime(lifetime, <ime) != 0) { 694d00756ccSwyllys cryptoerror(LOG_STDERR, 695d00756ccSwyllys gettext("Error parsing lifetime string\n")); 696d00756ccSwyllys return (PK_ERR_USAGE); 697d00756ccSwyllys } 698d00756ccSwyllys } 699d00756ccSwyllys if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { 700d00756ccSwyllys token_spec = PK_DEFAULT_PK11TOKEN; 701d00756ccSwyllys } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { 702d00756ccSwyllys token_spec = DEFAULT_NSS_TOKEN; 703d00756ccSwyllys } 704d00756ccSwyllys 705d00756ccSwyllys if (serstr != NULL) { 706d00756ccSwyllys uchar_t *bytes = NULL; 707d00756ccSwyllys size_t bytelen; 708d00756ccSwyllys 709d00756ccSwyllys rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen); 710d00756ccSwyllys if (rv != KMF_OK || bytes == NULL) { 711d00756ccSwyllys (void) fprintf(stderr, gettext("Serial number " 712d00756ccSwyllys "must be specified as a hex number " 713d00756ccSwyllys "(ex: 0x0102030405ffeeddee)\n")); 714d00756ccSwyllys return (PK_ERR_USAGE); 715d00756ccSwyllys } 716d00756ccSwyllys serial.val = bytes; 717d00756ccSwyllys serial.len = bytelen; 718d00756ccSwyllys } else { 719d00756ccSwyllys (void) fprintf(stderr, gettext("The serial number was not" 720d00756ccSwyllys " specified\n")); 721d00756ccSwyllys return (PK_ERR_USAGE); 722d00756ccSwyllys } 723d00756ccSwyllys 724d00756ccSwyllys if ((kstype == KMF_KEYSTORE_PK11TOKEN || 725d00756ccSwyllys kstype == KMF_KEYSTORE_NSS)) { 726d00756ccSwyllys /* Need to get password for private key access */ 727d00756ccSwyllys (void) get_token_password(kstype, token_spec, 728d00756ccSwyllys &tokencred); 729d00756ccSwyllys } 730448b8615Swyllys if (kustr != NULL) { 731448b8615Swyllys rv = verify_keyusage(kustr, &kubits, &kucrit); 732448b8615Swyllys if (rv != KMF_OK) { 733448b8615Swyllys (void) fprintf(stderr, gettext("KeyUsage " 734448b8615Swyllys "must be specified as a comma-separated list. " 735448b8615Swyllys "See the man page for details.\n")); 736448b8615Swyllys rv = PK_ERR_USAGE; 737448b8615Swyllys goto end; 738448b8615Swyllys } 739448b8615Swyllys } 740d00756ccSwyllys if (ekustr != NULL) { 741d00756ccSwyllys rv = verify_ekunames(ekustr, &ekulist); 742d00756ccSwyllys if (rv != KMF_OK) { 743d00756ccSwyllys (void) fprintf(stderr, gettext("EKUs must " 744d00756ccSwyllys "be specified as a comma-separated list. " 745d00756ccSwyllys "See the man page for details.\n")); 746d00756ccSwyllys rv = PK_ERR_USAGE; 747d00756ccSwyllys goto end; 748d00756ccSwyllys } 749d00756ccSwyllys } 750d00756ccSwyllys if (altname != NULL) { 751d00756ccSwyllys char *p; 752d00756ccSwyllys rv = verify_altname(altname, &alttype, &altcrit); 753d00756ccSwyllys if (rv != KMF_OK) { 754d00756ccSwyllys (void) fprintf(stderr, gettext("Subject AltName " 755d00756ccSwyllys "must be specified as a name=value pair. " 756d00756ccSwyllys "See the man page for details.\n")); 757d00756ccSwyllys rv = PK_ERR_USAGE; 758d00756ccSwyllys goto end; 759d00756ccSwyllys } 760d00756ccSwyllys /* advance the altname past the '=' sign */ 761d00756ccSwyllys p = strchr(altname, '='); 762d00756ccSwyllys if (p != NULL) 763d00756ccSwyllys altname = p + 1; 764d00756ccSwyllys } 765d00756ccSwyllys if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { 766d00756ccSwyllys cryptoerror(LOG_STDERR, 767d00756ccSwyllys gettext("Error parsing format string (%s).\n"), 768d00756ccSwyllys format); 769d00756ccSwyllys return (PK_ERR_USAGE); 770d00756ccSwyllys } 771d00756ccSwyllys 772577f4726Swyllys if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 773577f4726Swyllys return (rv); 774577f4726Swyllys } 775577f4726Swyllys 776d00756ccSwyllys if (kstype == KMF_KEYSTORE_PK11TOKEN) { 777d00756ccSwyllys rv = pk_signcsr_pk11_nss(kmfhandle, 778d00756ccSwyllys kstype, dir, prefix, token_spec, &tokencred, 779d00756ccSwyllys signkey, csrfile, &serial, certfile, issuer, subject, 780d00756ccSwyllys altname, alttype, altcrit, kubits, kucrit, 781d00756ccSwyllys ekulist, ltime, fmt, store, outlabel); 782d00756ccSwyllys 783d00756ccSwyllys } else if (kstype == KMF_KEYSTORE_NSS) { 784d00756ccSwyllys if (dir == NULL) 785d00756ccSwyllys dir = PK_DEFAULT_DIRECTORY; 786d00756ccSwyllys 787d00756ccSwyllys rv = pk_signcsr_pk11_nss(kmfhandle, 788d00756ccSwyllys kstype, dir, prefix, token_spec, &tokencred, 789d00756ccSwyllys signkey, csrfile, &serial, certfile, issuer, subject, 790d00756ccSwyllys altname, alttype, altcrit, kubits, kucrit, 791d00756ccSwyllys ekulist, ltime, fmt, store, outlabel); 792d00756ccSwyllys 793d00756ccSwyllys } else if (kstype == KMF_KEYSTORE_OPENSSL) { 794d00756ccSwyllys rv = pk_signcsr_files(kmfhandle, 795d00756ccSwyllys signkey, csrfile, &serial, certfile, issuer, subject, 796d00756ccSwyllys altname, alttype, altcrit, kubits, kucrit, 797d00756ccSwyllys ekulist, ltime, fmt); 798d00756ccSwyllys } 799d00756ccSwyllys 800d00756ccSwyllys end: 801d00756ccSwyllys if (rv != KMF_OK) { 802d00756ccSwyllys display_error(kmfhandle, rv, 803d00756ccSwyllys gettext("Error listing objects")); 804d00756ccSwyllys } 805d00756ccSwyllys 806d00756ccSwyllys if (serial.val != NULL) 807d00756ccSwyllys free(serial.val); 808d00756ccSwyllys 809d00756ccSwyllys if (tokencred.cred != NULL) 810d00756ccSwyllys free(tokencred.cred); 811d00756ccSwyllys 812d00756ccSwyllys free_eku_list(ekulist); 813d00756ccSwyllys 814d00756ccSwyllys (void) kmf_finalize(kmfhandle); 815d00756ccSwyllys return (rv); 816d00756ccSwyllys } 817