diff options
author | wyllys <none@none> | 2006-11-10 15:34:56 -0800 |
---|---|---|
committer | wyllys <none@none> | 2006-11-10 15:34:56 -0800 |
commit | 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8 (patch) | |
tree | a972f78468519a4e00234388688f45a506e934ba /usr/src | |
parent | 177fd15c9f814babb60e824f89984cdd8acf7c85 (diff) | |
download | illumos-joyent-99ebb4ca412cb0a19d77a3899a87c055b9c30fa8.tar.gz |
PSARC 2005/074 Solaris Key Management Framework
6224192 Solaris needs unified key management interfaces
--HG--
rename : usr/src/cmd/cmd-crypto/pktool/biginteger.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/biginteger.h
rename : usr/src/cmd/cmd-crypto/pktool/derparse.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.c
rename : usr/src/cmd/cmd-crypto/pktool/derparse.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/derparse.h
rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.c
rename : usr/src/cmd/cmd-crypto/pktool/osslcommon.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/osslcommon.h
rename : usr/src/cmd/cmd-crypto/pktool/p12common.c => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.c
rename : usr/src/cmd/cmd-crypto/pktool/p12common.h => deleted_files/usr/src/cmd/cmd-crypto/pktool/p12common.h
Diffstat (limited to 'usr/src')
120 files changed, 40999 insertions, 5252 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 95d7251dd1..cd4f2cdcb6 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -332,6 +332,7 @@ COMMON_SUBDIRS = \ lib/libipmp \ lib/libipp \ lib/libipsecutil \ + lib/libkmf \ lib/libkstat \ lib/liblaadm \ lib/liblgrp \ diff --git a/usr/src/cmd/cmd-crypto/Makefile b/usr/src/cmd/cmd-crypto/Makefile index f02549ce64..a046256e8a 100644 --- a/usr/src/cmd/cmd-crypto/Makefile +++ b/usr/src/cmd/cmd-crypto/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -32,7 +31,8 @@ SUBDIRS1 = \ cryptoadm \ decrypt \ digest \ - pktool + pktool \ + kmfcfg $(CLOSED_BUILD)SUBDIRS1 += \ $(CLOSED)/cmd/cmd-crypto/elfsign \ diff --git a/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c b/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c index 999ab4cb17..aad2a69f84 100644 --- a/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c +++ b/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -52,8 +51,6 @@ static int err; /* To store errno which may be overwritten by gettext() */ static boolean_t is_in_policylist(midstr_t, umechlist_t *); -static umechlist_t *dup_umechlist(umechlist_t *); -static uentry_t *dup_uentry(uentry_t *); static char *uent2str(uentry_t *); static boolean_t check_random(CK_SLOT_ID, CK_FUNCTION_LIST_PTR); @@ -1114,117 +1111,6 @@ uninstall_uef_lib(char *libname) } - -/* - * Duplicate an UEF mechanism list. A NULL pointer is returned if out of - * memory or the input argument is NULL. - */ -static umechlist_t * -dup_umechlist(umechlist_t *plist) -{ - umechlist_t *pres = NULL; - umechlist_t *pcur; - umechlist_t *ptmp; - int rc = SUCCESS; - - while (plist != NULL) { - if (!(ptmp = create_umech(plist->name))) { - rc = FAILURE; - break; - } - - if (pres == NULL) { - pres = pcur = ptmp; - } else { - pcur->next = ptmp; - pcur = pcur->next; - } - plist = plist->next; - } - - if (rc != SUCCESS) { - free_umechlist(pres); - return (NULL); - } - - return (pres); -} - - - -/* - * Duplicate an uentry. A NULL pointer is returned if out of memory - * or the input argument is NULL. - */ -static uentry_t * -dup_uentry(uentry_t *puent1) -{ - uentry_t *puent2 = NULL; - - if (puent1 == NULL) { - return (NULL); - } - - if ((puent2 = malloc(sizeof (uentry_t))) == NULL) { - cryptoerror(LOG_STDERR, gettext("out of memory.")); - return (NULL); - } else { - (void) strlcpy(puent2->name, puent1->name, - sizeof (puent2->name)); - puent2->flag_norandom = puent1->flag_norandom; - puent2->flag_enabledlist = puent1->flag_enabledlist; - puent2->count = puent1->count; - puent2->policylist = dup_umechlist(puent1->policylist); - puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled; - puent2->flag_metaslot_auto_key_migrate - = puent1->flag_metaslot_auto_key_migrate; - (void) memcpy(puent2->metaslot_ks_slot, - puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); - (void) memcpy(puent2->metaslot_ks_token, - puent1->metaslot_ks_token, TOKEN_LABEL_SIZE); - return (puent2); - } -} - - -/* - * Find the entry in the "pkcs11.conf" file with "libname" as the provider - * name. Return the entry if found, otherwise return NULL. - */ -uentry_t * -getent_uef(char *libname) -{ - uentrylist_t *pliblist = NULL; - uentrylist_t *plib = NULL; - uentry_t *puent = NULL; - boolean_t found = B_FALSE; - - if (libname == NULL) { - return (NULL); - } - - if ((get_pkcs11conf_info(&pliblist)) == FAILURE) { - return (NULL); - } - - plib = pliblist; - while (plib) { - if (strcmp(plib->puent->name, libname) == 0) { - found = B_TRUE; - break; - } else { - plib = plib->next; - } - } - - if (found) { - puent = dup_uentry(plib->puent); - } - - free_uentrylist(pliblist); - return (puent); -} - int display_policy(uentry_t *puent) { diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/Makefile b/usr/src/cmd/cmd-crypto/kmfcfg/Makefile new file mode 100644 index 0000000000..86fd4eb30e --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/Makefile @@ -0,0 +1,91 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for policy testing code +# + +PROG = kmfcfg + +OBJS = kmfcfg.o \ + list.o \ + delete.o \ + util.o \ + create.o \ + modify.o \ + export.o \ + import.o + +include ../../Makefile.cmd + +KMFDIR = $(SRC)/lib/libkmf +SRCS = $(OBJS:%.o=%.c) + +POFILES = $(OBJS:%.o=%.po) +POFILE = $(PROG)_msg.po +MSGFILES = $(SRCS:%.c=%.i) + +CPPFLAGS += -I/usr/include/libxml2 -I$(KMFDIR)/include -I. +LDLIBS += -L$(ROOT)/usr/lib -lkmf -lcryptoutil +XMLLIB = -lxml2 + +.KEEP_STATE: + +XMLDIR= $(ROOT)/etc/security +DTDDIR= $(ROOT)/usr/share/lib/xml/dtd +ROOTDTDS= $(DTDDIR)/kmfpolicy.dtd +ROOTXML= $(XMLDIR)/kmfpolicy.xml + +$(ROOTDTDS) := FILEMODE = 444 +$(ROOTDTDS) := OWNER = root +$(ROOTDTDS) := GROUP = bin + +$(ROOTXML) := FILEMODE = 644 +$(ROOTXML) := OWNER = root +$(ROOTXML) := GROUP = bin + +all: $(PROG) $(ROOTDTDS) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(XMLLIB) + $(POST_PROCESS) + +$(POFILE): $(POFILES) + $(BUILDPO.pofiles) + +install: all $(ROOTDTDS) $(ROOTXML) $(ROOTPROG) + +$(XMLDIR)/%: % + $(INS.file) + +$(DTDDIR)/%: % + $(INS.file) + +clean: + $(RM) $(OBJS) + +lint : lint_SRCS + +include ../../Makefile.targ diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/create.c b/usr/src/cmd/cmd-crypto/kmfcfg/create.c new file mode 100644 index 0000000000..ceacf5f5d5 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/create.c @@ -0,0 +1,498 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <errno.h> +#include <kmfapiP.h> +#include <cryptoutil.h> +#include "util.h" + +int +kc_create(int argc, char *argv[]) +{ + KMF_RETURN ret; + int rv = KC_OK; + int opt; + extern int optind_av; + extern char *optarg_av; + char *filename = NULL; + int ocsp_set_attr = 0; + boolean_t crl_set_attr = 0; + KMF_POLICY_RECORD plc; + + (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD)); + + while ((opt = getopt_av(argc, argv, + "i:(dbfile)" + "p:(policy)" + "d:(ignore-date)" + "e:(ignore-unknown-eku)" + "a:(ignore-trust-anchor)" + "v:(validity-adjusttime)" + "t:(ta-name)" + "s:(ta-serial)" + "o:(ocsp-responder)" + "P:(ocsp-proxy)" + "r:(ocsp-use-cert-responder)" + "T:(ocsp-response-lifetime)" + "R:(ocsp-ignore-response-sign)" + "n:(ocsp-responder-cert-name)" + "A:(ocsp-responder-cert-serial)" + "c:(crl-basefilename)" + "I:(crl-directory)" + "g:(crl-get-crl-uri)" + "X:(crl-proxy)" + "S:(crl-ignore-crl-sign)" + "D:(crl-ignore-crl-date)" + "u:(keyusage)" + "E:(ekunames)" + "O:(ekuoids)")) != EOF) { + switch (opt) { + case 'i': + filename = get_string(optarg_av, &rv); + if (filename == NULL) { + (void) fprintf(stderr, + gettext("Error dbfile input.\n")); + } + break; + case 'p': + plc.name = get_string(optarg_av, &rv); + if (plc.name == NULL) { + (void) fprintf(stderr, + gettext("Error policy name.\n")); + } + break; + case 'd': + plc.ignore_date = get_boolean(optarg_av); + if (plc.ignore_date == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } + break; + case 'e': + plc.ignore_unknown_ekus = + get_boolean(optarg_av); + if (plc.ignore_unknown_ekus == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } + break; + case 'a': + plc.ignore_trust_anchor = + get_boolean(optarg_av); + if (plc.ignore_trust_anchor == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } + break; + case 'v': + plc.validity_adjusttime = + get_string(optarg_av, &rv); + if (plc.validity_adjusttime == NULL) { + (void) fprintf(stderr, + gettext("Error time input.\n")); + } else { + uint32_t adj; + /* for syntax checking */ + if (str2lifetime( + plc.validity_adjusttime, + &adj) < 0) { + (void) fprintf(stderr, + gettext("Error time " + "input.\n")); + rv = KC_ERR_USAGE; + } + } + break; + case 't': + plc.ta_name = get_string(optarg_av, &rv); + if (plc.ta_name == NULL) { + (void) fprintf(stderr, + gettext("Error name input.\n")); + } else { + KMF_X509_NAME taDN; + /* for syntax checking */ + if (KMF_DNParser(plc.ta_name, + &taDN) != KMF_OK) { + (void) fprintf(stderr, + gettext("Error name " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + KMF_FreeDN(&taDN); + } + } + break; + case 's': + plc.ta_serial = get_string(optarg_av, &rv); + if (plc.ta_serial == NULL) { + (void) fprintf(stderr, + gettext("Error serial input.\n")); + } else { + uchar_t *bytes = NULL; + size_t bytelen; + + ret = KMF_HexString2Bytes( + (uchar_t *)plc.ta_serial, + &bytes, &bytelen); + if (ret != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, + gettext("serial number " + "must be specified as a " + "hex number " + "(ex: 0x0102030405" + "ffeeddee)\n")); + rv = KC_ERR_USAGE; + } + if (bytes != NULL) + free(bytes); + } + break; + case 'o': + plc.VAL_OCSP_RESPONDER_URI = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESPONDER_URI == NULL) { + (void) fprintf(stderr, gettext( + "Error responder input.\n")); + } else { + ocsp_set_attr++; + } + break; + case 'P': + plc.VAL_OCSP_PROXY = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_PROXY == NULL) { + (void) fprintf(stderr, + gettext("Error proxy input.\n")); + } else { + ocsp_set_attr++; + } + break; + case 'r': + plc.VAL_OCSP_URI_FROM_CERT = + get_boolean(optarg_av); + if (plc.VAL_OCSP_URI_FROM_CERT == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + ocsp_set_attr++; + } + break; + case 'T': + plc.VAL_OCSP_RESP_LIFETIME = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { + (void) fprintf(stderr, + gettext("Error time input.\n")); + } else { + uint32_t adj; + /* for syntax checking */ + if (str2lifetime( + plc.VAL_OCSP_RESP_LIFETIME, + &adj) < 0) { + (void) fprintf(stderr, + gettext("Error time " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + ocsp_set_attr++; + } + } + break; + case 'R': + plc.VAL_OCSP_IGNORE_RESP_SIGN = + get_boolean(optarg_av); + if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + ocsp_set_attr++; + } + break; + case 'n': + plc.VAL_OCSP_RESP_CERT_NAME = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { + (void) fprintf(stderr, + gettext("Error name input.\n")); + } else { + KMF_X509_NAME respDN; + /* for syntax checking */ + if (KMF_DNParser( + plc.VAL_OCSP_RESP_CERT_NAME, + &respDN) != KMF_OK) { + (void) fprintf(stderr, + gettext("Error name " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + KMF_FreeDN(&respDN); + ocsp_set_attr++; + } + } + break; + case 'A': + plc.VAL_OCSP_RESP_CERT_SERIAL = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { + (void) fprintf(stderr, + gettext("Error serial input.\n")); + } else { + uchar_t *bytes = NULL; + size_t bytelen; + + ret = KMF_HexString2Bytes((uchar_t *) + plc.VAL_OCSP_RESP_CERT_SERIAL, + &bytes, &bytelen); + if (ret != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, + gettext("serial number " + "must be specified as a " + "hex number " + "(ex: 0x0102030405" + "ffeeddee)\n")); + rv = KC_ERR_USAGE; + break; + } + if (bytes != NULL) + free(bytes); + ocsp_set_attr++; + } + break; + case 'c': + plc.VAL_CRL_BASEFILENAME = + get_string(optarg_av, &rv); + if (plc.VAL_CRL_BASEFILENAME == NULL) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + } else { + crl_set_attr++; + } + break; + case 'I': + plc.VAL_CRL_DIRECTORY = + get_string(optarg_av, &rv); + if (plc.VAL_CRL_DIRECTORY == NULL) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + } else { + crl_set_attr++; + } + break; + case 'g': + plc.VAL_CRL_GET_URI = get_boolean(optarg_av); + if (plc.VAL_CRL_GET_URI == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + crl_set_attr++; + } + break; + case 'X': + plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); + if (plc.VAL_CRL_PROXY == NULL) { + (void) fprintf(stderr, + gettext("Error proxy input.\n")); + } else { + crl_set_attr++; + } + break; + case 'S': + plc.VAL_CRL_IGNORE_SIGN = + get_boolean(optarg_av); + if (plc.VAL_CRL_IGNORE_SIGN == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + crl_set_attr++; + } + break; + case 'D': + plc.VAL_CRL_IGNORE_DATE = + get_boolean(optarg_av); + if (plc.VAL_CRL_IGNORE_DATE == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + crl_set_attr++; + } + break; + case 'u': + plc.ku_bits = parseKUlist(optarg_av); + if (plc.ku_bits == 0) { + (void) fprintf(stderr, gettext( + "Error keyusage input.\n")); + rv = KC_ERR_USAGE; + } + break; + case 'E': + if (parseEKUNames(optarg_av, &plc) != 0) { + (void) fprintf(stderr, + gettext("Error EKU input.\n")); + rv = KC_ERR_USAGE; + } + break; + case 'O': + if (parseEKUOIDs(optarg_av, &plc) != 0) { + (void) fprintf(stderr, + gettext("Error EKU OID input.\n")); + rv = KC_ERR_USAGE; + } + break; + default: + (void) fprintf(stderr, + gettext("Error input option.\n")); + rv = KC_ERR_USAGE; + break; + } + + if (rv != KC_OK) + goto out; + } + + /* No additional args allowed. */ + argc -= optind_av; + if (argc) { + (void) fprintf(stderr, + gettext("Error input option\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (filename == NULL) { + filename = strdup(KMF_DEFAULT_POLICY_FILE); + if (filename == NULL) { + rv = KC_ERR_MEMORY; + goto out; + } + } + + /* + * Must have a policy name. The policy name can not be default + * if using the default policy file. + */ + if (plc.name == NULL) { + (void) fprintf(stderr, + gettext("You must specify a policy name\n")); + rv = KC_ERR_USAGE; + goto out; + } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && + strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { + (void) fprintf(stderr, + gettext("Can not create a default policy in the default " + "policy file\n")); + rv = KC_ERR_USAGE; + goto out; + } + + /* + * If the policy file exists and the policy is in the policy file + * already, we will not create it again. + */ + if (access(filename, R_OK) == 0) { + POLICY_LIST *plclist = NULL, *pnode; + int found = 0; + + rv = load_policies(filename, &plclist); + if (rv != KMF_OK) + goto out; + + pnode = plclist; + while (pnode != NULL && !found) { + if (strcmp(plc.name, pnode->plc.name) == 0) + found++; + pnode = pnode->next; + } + free_policy_list(plclist); + + if (found) { + (void) fprintf(stderr, + gettext("Could not create policy \"%s\" - exists " + "already\n"), plc.name); + rv = KC_ERR_USAGE; + goto out; + } + } + + /* + * If any OCSP attribute is set, turn on the OCSP checking flag. + * Also set "has_resp_cert" to be true, if the responder cert + * is provided. + */ + if (ocsp_set_attr > 0) + plc.revocation |= KMF_REVOCATION_METHOD_OCSP; + + if (plc.VAL_OCSP_RESP_CERT.name != NULL && + plc.VAL_OCSP_RESP_CERT.serial != NULL) { + plc.VAL_OCSP.has_resp_cert = B_TRUE; + } + + /* + * If any CRL attribute is set, turn on the CRL checking flag. + */ + if (crl_set_attr > 0) + plc.revocation |= KMF_REVOCATION_METHOD_CRL; + + /* + * Does a sanity check on the new policy. + */ + ret = KMF_VerifyPolicy(&plc); + if (ret != KMF_OK) { + print_sanity_error(ret); + rv = KC_ERR_ADD_POLICY; + goto out; + } + + /* + * Add to the DB. + */ + ret = KMF_AddPolicyToDB(&plc, filename, B_FALSE); + if (ret != KMF_OK) { + (void) fprintf(stderr, + gettext("Error adding policy to database: 0x%04x\n"), ret); + rv = KC_ERR_ADD_POLICY; + } + +out: + if (filename != NULL) + free(filename); + + KMF_FreePolicyRecord(&plc); + + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/delete.c b/usr/src/cmd/cmd-crypto/kmfcfg/delete.c new file mode 100644 index 0000000000..7e0a1c7d45 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/delete.c @@ -0,0 +1,132 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <errno.h> +#include <kmfapiP.h> +#include "util.h" + +int +kc_delete(int argc, char *argv[]) +{ + int rv = KC_OK; + KMF_RETURN kmfrv = KMF_OK; + int opt; + extern int optind_av; + extern char *optarg_av; + char *filename = NULL; + char *policyname = NULL; + + while ((opt = getopt_av(argc, argv, "i:(dbfile)p:(policy)")) != EOF) { + switch (opt) { + case 'i': + filename = get_string(optarg_av, &rv); + if (filename == NULL) { + (void) fprintf(stderr, + gettext("Error dbfile input.\n")); + } + break; + case 'p': + policyname = get_string(optarg_av, &rv); + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("Error policy name.\n")); + } + break; + default: + (void) fprintf(stderr, + gettext("Error input option.\n")); + rv = KC_ERR_USAGE; + break; + + } + + if (rv != KC_OK) + goto out; + } + + /* No additional args allowed. */ + argc -= optind_av; + if (argc) { + (void) fprintf(stderr, + gettext("Error input option\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (filename == NULL) { + filename = strdup(KMF_DEFAULT_POLICY_FILE); + if (filename == NULL) { + rv = KC_ERR_MEMORY; + goto out; + } + } + + /* + * Must have a policy name. The policy name can not be default + * if using the default policy file. + */ + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("You must specify a policy name\n")); + rv = KC_ERR_USAGE; + goto out; + } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && + strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) { + (void) fprintf(stderr, + gettext("Can not delete the default policy in the default " + "policy file\n")); + rv = KC_ERR_USAGE; + goto out; + } + + /* Check the access permission of the policy DB */ + if (access(filename, W_OK) < 0) { + int err = errno; + (void) fprintf(stderr, + gettext("Cannot access \"%s\" for delete - %s\n"), + filename, strerror(err)); + rv = KC_ERR_ACCESS; + goto out; + } + + kmfrv = KMF_DeletePolicyFromDB(policyname, filename); + if (kmfrv != KMF_OK) + rv = KC_ERR_DELETE_POLICY; + +out: + if (filename != NULL) + free(filename); + + if (policyname != NULL) + free(policyname); + + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/export.c b/usr/src/cmd/cmd-crypto/kmfcfg/export.c new file mode 100644 index 0000000000..c1ddab153c --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/export.c @@ -0,0 +1,167 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <locale.h> +#include <errno.h> +#include <kmfapiP.h> + +#include "util.h" + +int +kc_export(int argc, char *argv[]) +{ + int rv = KC_OK; + char *filename = NULL; + char *outfile = NULL; + char *policyname = NULL; + POLICY_LIST *plclist = NULL, *pnode; + int opt, found = 0; + extern int optind_av; + extern char *optarg_av; + + while ((opt = getopt_av(argc, argv, + "d:(dbfile)p:(policy)o:(outfile)")) != EOF) { + switch (opt) { + case 'd': + filename = get_string(optarg_av, &rv); + if (filename == NULL) { + (void) fprintf(stderr, + gettext("Error dbfile input.\n")); + } + break; + case 'p': + policyname = get_string(optarg_av, &rv); + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("Error policy name.\n")); + } + break; + case 'o': + outfile = get_string(optarg_av, &rv); + if (outfile == NULL) { + (void) fprintf(stderr, + gettext("Error outfile input.\n")); + } + break; + default: + (void) fprintf(stderr, + gettext("Error input option.\n")); + rv = KC_ERR_USAGE; + break; + } + + if (rv != KC_OK) + goto out; + } + + /* No additional args allowed. */ + argc -= optind_av; + if (argc) { + (void) fprintf(stderr, + gettext("Error input option\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (filename == NULL) { + filename = strdup(KMF_DEFAULT_POLICY_FILE); + if (filename == NULL) { + rv = KC_ERR_MEMORY; + goto out; + } + } + + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("You must specify a policy name\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (outfile == NULL) { + (void) fprintf(stderr, + gettext("You must specify a output DB file\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (strcmp(outfile, KMF_DEFAULT_POLICY_FILE) == 0 && + strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) { + (void) fprintf(stderr, + gettext("Can not export the default policy record to " + "the system default policy database\n")); + rv = KC_ERR_USAGE; + goto out; + } + + rv = load_policies(filename, &plclist); + if (rv != KMF_OK) + goto out; + + pnode = plclist; + while (pnode != NULL && !found) { + if (strcmp(policyname, pnode->plc.name) == 0) { + KMF_RETURN ret; + + found++; + ret = KMF_VerifyPolicy(&pnode->plc); + if (ret != KMF_OK) { + print_sanity_error(ret); + rv = KC_ERR_VERIFY_POLICY; + break; + } + rv = KMF_AddPolicyToDB(&pnode->plc, outfile, B_FALSE); + } + pnode = pnode->next; + } + + if (!found) { + (void) fprintf(stderr, + gettext("Could not find policy \"%s\" in %s\n"), + policyname, filename); + rv = KC_ERR_FIND_POLICY; + } + +out: + if (filename != NULL) + free(filename); + + if (policyname != NULL) + free(policyname); + + if (outfile != NULL) + free(outfile); + + free_policy_list(plclist); + + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/import.c b/usr/src/cmd/cmd-crypto/kmfcfg/import.c new file mode 100644 index 0000000000..b55caac068 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/import.c @@ -0,0 +1,169 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <locale.h> +#include <errno.h> + +#include <kmfapiP.h> + +#include "util.h" + +int +kc_import(int argc, char *argv[]) +{ + int rv = KC_OK; + char *filename = NULL; + char *infile = NULL; + char *policyname = NULL; + POLICY_LIST *plclist = NULL, *pnode; + int opt, found = 0; + extern int optind_av; + extern char *optarg_av; + + while ((opt = getopt_av(argc, argv, + "d:(dbfile)p:(policy)i:(infile)")) != EOF) { + switch (opt) { + case 'd': + filename = get_string(optarg_av, &rv); + if (filename == NULL) { + (void) fprintf(stderr, + gettext("Error dbfile input.\n")); + } + break; + case 'p': + policyname = get_string(optarg_av, &rv); + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("Error policy name.\n")); + } + break; + case 'i': + infile = get_string(optarg_av, &rv); + if (infile == NULL) { + (void) fprintf(stderr, + gettext("Error infile input.\n")); + } + break; + default: + (void) fprintf(stderr, + gettext("Error input option.\n")); + rv = KC_ERR_USAGE; + break; + } + + if (rv != KC_OK) + goto out; + + } + + /* No additional args allowed. */ + argc -= optind_av; + if (argc) { + (void) fprintf(stderr, + gettext("Error input option\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (filename == NULL) { + filename = strdup(KMF_DEFAULT_POLICY_FILE); + if (filename == NULL) { + rv = KC_ERR_MEMORY; + goto out; + } + } + + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("You must specify a policy name\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (infile == NULL) { + (void) fprintf(stderr, + gettext("You must specify a input DB file\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && + strcmp(policyname, KMF_DEFAULT_POLICY_NAME) == 0) { + (void) fprintf(stderr, + gettext("Can not import the default policy record to " + "the system default policy database\n")); + rv = KC_ERR_USAGE; + goto out; + } + + rv = load_policies(infile, &plclist); + if (rv != KMF_OK) + goto out; + + pnode = plclist; + while (pnode != NULL && !found) { + if (strcmp(policyname, pnode->plc.name) == 0) { + KMF_RETURN ret; + + found++; + ret = KMF_VerifyPolicy(&pnode->plc); + if (ret != KMF_OK) { + print_sanity_error(ret); + rv = KC_ERR_VERIFY_POLICY; + break; + } + rv = KMF_AddPolicyToDB(&pnode->plc, filename, B_FALSE); + } + pnode = pnode->next; + } + + if (!found) { + (void) fprintf(stderr, + gettext("Could not find policy \"%s\" in %s\n"), + policyname, infile); + rv = KC_ERR_FIND_POLICY; + } + +out: + if (filename != NULL) + free(filename); + + if (policyname != NULL) + free(policyname); + + if (infile != NULL) + free(infile); + + free_policy_list(plclist); + + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c new file mode 100644 index 0000000000..e58368284f --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c @@ -0,0 +1,245 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <locale.h> + +#include <kmfapiP.h> + +#include "util.h" + +/* + * The verbcmd construct allows genericizing information about a verb so + * that it is easier to manipulate. Makes parsing code easier to read, + * fix, and extend with new verbs. + */ +typedef struct verbcmd_s { + char *verb; + int (*action)(int, char *[]); + char *synopsis; +} verbcmd; + +int kc_list(int argc, char *argv[]); +int kc_delete(int argc, char *argv[]); +int kc_create(int argc, char *argv[]); +int kc_modify(int argc, char *argv[]); +int kc_export(int argc, char *argv[]); +int kc_import(int argc, char *argv[]); +static int kc_help(); + +static verbcmd cmds[] = { + { "list", kc_list, "list [dbfile=dbfile] " + "[policy=policyname]" }, + { "delete", kc_delete, "delete [dbfile=dbfile] " + "policy=policyname" }, + { "create", kc_create, + "create [dbfile=dbfile] policy=policyname\n" + "\t\t[ignore-date=true|false]\n" + "\t\t[ignore-unknown-eku=true|false]\n" + "\t\t[ignore-trust-anchor=true|false]\n" + "\t\t[validity-adjusttime=adjusttime]\n" + "\t\t[ta-name=trust anchor subject DN]\n" + "\t\t[ta-serial=trust anchor serial number]\n" + "\t\t[ocsp-responder=URL]\n" + "\t\t[ocsp-proxy=URL]\n" + "\t\t[ocsp-use-cert-responder=true|false]\n" + "\t\t[ocsp-response-lifetime=timelimit]\n" + "\t\t[ocsp-ignore-response-sign=true|false]\n" + "\t\t[ocsp-responder-cert-name=Issuer DN]\n" + "\t\t[ocsp-responder-cert-serial=serial number]\n" + "\t\t[crl-basefilename=basefilename]\n" + "\t\t[crl-directory=directory]\n" + "\t\t[crl-get-crl-uri=true|false]\n" + "\t\t[crl-proxy=URL]\n" + "\t\t[crl-ignore-crl-sign=true|false]\n" + "\t\t[crl-ignore-crl-date=true|false]\n" + "\t\t[keyusage=digitalSignature|nonRepudiation\n\t" + "\t\t|keyEncipherment | dataEncipherment |\n\t" + "\t\tkeyAgreement |keyCertSign |\n\t" + "\t\tcRLSign | encipherOnly | decipherOnly],[...]\n" + "\t\t[ekunames=serverAuth | clientAuth |\n\t" + "\t\tcodeSigning | emailProtection |\n\t" + "\t\tipsecEndSystem | ipsecTunnel |\n\t" + "\t\tipsecUser | timeStamping |\n\t" + "\t\tOCSPSigning],[...]\n" + "\t\t[ekuoids=OID,OID,OID...]\n" }, + { "modify", kc_modify, + "modify [dbfile=dbfile] policy=policyname\n" + "\t\t[ignore-date=true|false]\n" + "\t\t[ignore-unknown-eku=true|false]\n" + "\t\t[ignore-trust-anchor=true|false]\n" + "\t\t[validity-adjusttime=adjusttime]\n" + "\t\t[ta-name=trust anchor subject DN]\n" + "\t\t[ta-serial=trust anchor serial number]\n" + "\t\t[ocsp-responder=URL]\n" + "\t\t[ocsp-proxy=URL]\n" + "\t\t[ocsp-use-cert-responder=true|false]\n" + "\t\t[ocsp-response-lifetime=timelimit]\n" + "\t\t[ocsp-ignore-response-sign=true|false]\n" + "\t\t[ocsp-responder-cert-name=Issuer DN]\n" + "\t\t[ocsp-responder-cert-serial=serial number]\n" + "\t\t[ocsp-none=true|false]\n" + "\t\t[crl-basefilename=basefilename]\n" + "\t\t[crl-directory=directory]\n" + "\t\t[crl-get-crl-uri=true|false]\n" + "\t\t[crl-proxy=URL]\n" + "\t\t[crl-ignore-crl-sign=true|false]\n" + "\t\t[crl-ignore-crl-date=true|false]\n" + "\t\t[crl-none=true|false]\n" + "\t\t[keyusage=digitalSignature|nonRepudiation\n\t" + "\t\t|keyEncipherment | dataEncipherment |\n\t" + "\t\tkeyAgreement |keyCertSign |\n\t" + "\t\tcRLSign | encipherOnly | decipherOnly],[...]\n" + "\t\t[keyusage-none=true|false]\n" + "\t\t[ekunames=serverAuth | clientAuth |\n\t" + "\t\tcodeSigning | emailProtection |\n\t" + "\t\tipsecEndSystem | ipsecTunnel |\n\t" + "\t\tipsecUser | timeStamping |\n\t" + "\t\tOCSPSigning],[...]\n" + "\t\t[ekuoids=OID,OID,OID...]\n" + "\t\t[eku-none=true|false]\n" }, + { "import", kc_import, "import [dbfile=dbfile] policy=policyname " + "infile=inputdbfile\n" }, + { "export", kc_export, "export [dbfile=dbfile] policy=policyname " + "outfile=newdbfile\n" }, + { "-?", kc_help, "help"}, + { "help", kc_help, ""} +}; + +static int num_cmds = sizeof (cmds) / sizeof (verbcmd); +static char *prog; + +static void +usage(void) +{ + int i; + + /* Display this block only in command-line mode. */ + (void) fprintf(stdout, gettext("Usage:\n")); + (void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog); + (void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog); + (void) fprintf(stdout, gettext("where subcommands may be:\n")); + + /* Display only those verbs that match the current tool mode. */ + for (i = 0; i < num_cmds; i++) { + /* Do NOT i18n/l10n. */ + (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis); + } +} + +static int +kc_help() +{ + usage(); + return (0); +} + +int +main(int argc, char *argv[]) +{ + KMF_RETURN ret; + int found; + int i; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D. */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ +#endif + (void) textdomain(TEXT_DOMAIN); + + prog = basename(argv[0]); + argv++; argc--; + + if (argc == 0) { + usage(); + exit(1); + } + + if (argc == 1 && argv[0][0] == '-') { + switch (argv[0][1]) { + case '?': + return (kc_help()); + default: + usage(); + exit(1); + } + } + + found = -1; + for (i = 0; i < num_cmds; i++) { + if (strcmp(cmds[i].verb, argv[0]) == 0) { + found = i; + break; + } + } + + if (found < 0) { + (void) fprintf(stderr, gettext("Invalid command: %s\n"), + argv[0]); + exit(1); + } + + ret = (*cmds[found].action)(argc, argv); + + switch (ret) { + case KC_OK: + break; + case KC_ERR_USAGE: + break; + case KC_ERR_LOADDB: + (void) fprintf(stderr, + gettext("Error loading database\n")); + break; + case KC_ERR_FIND_POLICY: + break; + case KC_ERR_DELETE_POLICY: + (void) fprintf(stderr, gettext("Error deleting policy " + "from database.\n")); + break; + case KC_ERR_ADD_POLICY: + break; + case KC_ERR_VERIFY_POLICY: + break; + case KC_ERR_INCOMPLETE_POLICY: + break; + case KC_ERR_MEMORY: + (void) fprintf(stderr, gettext("Out of memory.\n")); + break; + case KC_ERR_ACCESS: + break; + default: + (void) fprintf(stderr, gettext("%s operation failed. " + "error 0x%02x\n"), cmds[found].verb, ret); + break; + } + + return (ret); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd new file mode 100644 index 0000000000..32fa28e99a --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.dtd @@ -0,0 +1,84 @@ +<?xml version='1.0' encoding='UTF-8' ?> + +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" +--> + +<!--Element Definitions--> + +<!ELEMENT kmf-policy-db (kmf-policy*)> +<!ATTLIST kmf-policy-db allow-local-files (TRUE|FALSE) #IMPLIED> + +<!ELEMENT kmf-policy (validation-methods, key-usage-set?, ext-key-usage?)> +<!ATTLIST kmf-policy name CDATA #REQUIRED> +<!ATTLIST kmf-policy ignore-date (TRUE|FALSE) #IMPLIED> +<!ATTLIST kmf-policy ignore-unknown-eku (TRUE|FALSE) #IMPLIED> +<!ATTLIST kmf-policy ignore-trust-anchor (TRUE|FALSE) #IMPLIED> +<!ATTLIST kmf-policy validity-adjusttime CDATA #IMPLIED> +<!ATTLIST kmf-policy ta-name CDATA #IMPLIED> +<!ATTLIST kmf-policy ta-serial CDATA #IMPLIED> + +<!ELEMENT validation-methods (ocsp?, crl?)> +<!ELEMENT ocsp (ocsp-basic, responder-cert?)> + +<!ELEMENT ocsp-basic EMPTY> +<!ATTLIST ocsp-basic + responder CDATA #IMPLIED + proxy CDATA #IMPLIED + uri-from-cert (TRUE|FALSE) #IMPLIED + response-lifetime CDATA #IMPLIED + ignore-response-sign (TRUE|FALSE) #IMPLIED +> + +<!ELEMENT responder-cert EMPTY> +<!ATTLIST responder-cert + name CDATA #REQUIRED + serial CDATA #REQUIRED +> + +<!ELEMENT crl EMPTY> +<!ATTLIST crl basefilename CDATA #IMPLIED> +<!ATTLIST crl directory CDATA #IMPLIED> +<!ATTLIST crl get-crl-uri (TRUE|FALSE) #IMPLIED> +<!ATTLIST crl proxy CDATA #IMPLIED> +<!ATTLIST crl ignore-crl-sign (TRUE|FALSE) #IMPLIED> +<!ATTLIST crl ignore-crl-date (TRUE|FALSE) #IMPLIED> + +<!ELEMENT key-usage-set (key-usage+)> + +<!ELEMENT key-usage EMPTY> +<!ATTLIST key-usage use (digitalSignature | nonRepudiation | + keyEncipherment | dataEncipherment | keyAgreement | + keyCertSign | cRLSign | encipherOnly | decipherOnly) #IMPLIED> + +<!ELEMENT ext-key-usage (eku-name*, eku-oid*)> + +<!ELEMENT eku-name EMPTY> +<!ATTLIST eku-name name (serverAuth | clientAuth | + codeSigning | emailProtection | + ipsecEndSystem | ipsecTunnel | ipsecUser | + timeStamping | OCSPSigning) #IMPLIED > +<!ELEMENT eku-oid EMPTY> +<!ATTLIST eku-oid oid CDATA #IMPLIED> diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml new file mode 100644 index 0000000000..2c2ed35e2c --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + Sample KMF Policy Database file. + + ident "%Z%%M% %I% %E% SMI" +--> +<!DOCTYPE kmf-policy-db SYSTEM "/usr/share/lib/xml/dtd/kmfpolicy.dtd"> +<kmf-policy-db> + +<kmf-policy name="default" ignore-date="TRUE" ignore-trust-anchor="TRUE"> + <validation-methods> + <ocsp> + <ocsp-basic uri-from-cert="TRUE" + ignore-response-sign="TRUE"/> + </ocsp> + </validation-methods> +</kmf-policy> +</kmf-policy-db> diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/list.c b/usr/src/cmd/cmd-crypto/kmfcfg/list.c new file mode 100644 index 0000000000..e68e2b8643 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/list.c @@ -0,0 +1,277 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <errno.h> +#include <kmfapiP.h> + +#include "util.h" + +static void +show_policy(KMF_POLICY_RECORD *plc) +{ + int i; + if (plc == NULL) + return; + + (void) printf("Name: %s\n", plc->name); + + (void) printf(gettext("Ignore Date: %s\n"), + plc->ignore_date ? gettext("true") : gettext("false")); + + (void) printf(gettext("Ignore Unknown EKUs: %s\n"), + plc->ignore_unknown_ekus ? gettext("true") : gettext("false")); + + (void) printf(gettext("Ignore TA: %s\n"), + plc->ignore_trust_anchor ? gettext("true") : gettext("false")); + + (void) printf(gettext("Validity Adjusted Time: %s\n"), + plc->validity_adjusttime ? + plc->validity_adjusttime : "<null>"); + + if (plc->ta_name == NULL && plc->ta_serial == NULL) { + (void) printf(gettext("Trust Anchor Certificate: <null>\n")); + } else { + (void) printf(gettext("Trust Anchor Certificate:\n")); + (void) printf(gettext("\tName: %s\n"), + plc->ta_name ? plc->ta_name : "<null>"); + (void) printf(gettext("\tSerial Number: %s\n"), + plc->ta_serial ? plc->ta_serial : "<null>"); + } + + if (plc->ku_bits != 0) { + (void) printf(gettext("Key Usage Bits: ")); + for (i = KULOWBIT; i <= KUHIGHBIT; i++) { + char *s = ku2str((plc->ku_bits & (1<<i))); + if (s != NULL) { + (void) printf("%s ", s); + } + } + (void) printf("\n"); + } else { + (void) printf(gettext("Key Usage Bits: 0\n")); + } + + if (plc->eku_set.eku_count > 0) { + (void) printf(gettext("Extended Key Usage Values:\n")); + for (i = 0; i < plc->eku_set.eku_count; i++) { + char *s = KMF_OID2EKUString(&plc->eku_set.ekulist[i]); + (void) printf("\t%s\t(%s)\n", + KMF_OID2String(&plc->eku_set.ekulist[i]), + s ? s : "unknown"); + } + } else { + (void) printf(gettext("Extended Key Usage Values: <null>\n")); + } + + (void) printf(gettext("Validation Policy Information:\n")); + + if (plc->revocation & KMF_REVOCATION_METHOD_OCSP) { + (void) printf(gettext(" OCSP:\n")); + + (void) printf(gettext("\tResponder URI: %s\n"), + plc->VAL_OCSP_BASIC.responderURI ? + plc->VAL_OCSP_BASIC.responderURI : "<null>"); + + (void) printf(gettext("\tProxy: %s\n"), + plc->VAL_OCSP_BASIC.proxy ? + plc->VAL_OCSP_BASIC.proxy : "<null>"); + + (void) printf(gettext("\tUse ResponderURI from Certificate: " + "%s\n"), plc->VAL_OCSP_BASIC.uri_from_cert ? + gettext("true") : gettext("false")); + + (void) printf(gettext("\tResponse lifetime: %s\n"), + plc->VAL_OCSP_BASIC.response_lifetime ? + plc->VAL_OCSP_BASIC.response_lifetime : "<null>"); + + (void) printf(gettext("\tIgnore Response signature: %s\n"), + plc->VAL_OCSP_BASIC.ignore_response_sign ? + gettext("true") : gettext("false")); + + if (!plc->VAL_OCSP.has_resp_cert) { + (void) printf(gettext("\tResponder Certificate:" + " <null>\n")); + } else { + (void) printf(gettext("\tResponder Certificate:\n")); + (void) printf(gettext("\t\tName: %s\n"), + plc->VAL_OCSP_RESP_CERT.name ? + plc->VAL_OCSP_RESP_CERT.name : "<null>"); + (void) printf(gettext("\t\tSerial: %s\n"), + plc->VAL_OCSP_RESP_CERT.serial ? + plc->VAL_OCSP_RESP_CERT.serial : "<null>"); + } + } + + if (plc->revocation & KMF_REVOCATION_METHOD_CRL) { + (void) printf(gettext(" CRL:\n")); + + (void) printf(gettext("\tBase filename: %s\n"), + plc->validation_info.crl_info.basefilename ? + plc->validation_info.crl_info.basefilename : "<null>"); + + (void) printf(gettext("\tDirectory: %s\n"), + plc->validation_info.crl_info.directory ? + plc->validation_info.crl_info.directory : "<null>"); + + (void) printf(gettext("\tDownload and cache CRL: %s\n"), + plc->validation_info.crl_info.get_crl_uri ? + gettext("true") : gettext("false")); + + (void) printf(gettext("\tProxy: %s\n"), + plc->validation_info.crl_info.proxy ? + plc->validation_info.crl_info.proxy : "<null>"); + + (void) printf(gettext("\tIgnore CRL signature: %s\n"), + plc->validation_info.crl_info.ignore_crl_sign ? + gettext("true") : gettext("false")); + + (void) printf(gettext("\tIgnore CRL validity date: %s\n"), + plc->validation_info.crl_info.ignore_crl_date ? + gettext("true") : gettext("false")); + } + + (void) printf("\n"); +} + +int +kc_list(int argc, char *argv[]) +{ + int rv = KC_OK; + int opt, found = 0; + extern int optind_av; + extern char *optarg_av; + char *filename = NULL; + char *policyname = NULL; + POLICY_LIST *plclist = NULL, *pnode; + int sanity_err = 0; + + while ((opt = getopt_av(argc, argv, "i:(dbfile)p:(policy)")) != EOF) { + switch (opt) { + case 'i': + filename = get_string(optarg_av, &rv); + if (filename == NULL) { + (void) fprintf(stderr, + gettext("Error dbfile input.\n")); + } + break; + case 'p': + policyname = get_string(optarg_av, &rv); + if (policyname == NULL) { + (void) fprintf(stderr, + gettext("Error policy name.\n")); + } + break; + default: + (void) fprintf(stderr, + gettext("Error input option.\n")); + rv = KC_ERR_USAGE; + break; + } + if (rv != KC_OK) + goto out; + } + + /* No additional args allowed. */ + argc -= optind_av; + if (argc) { + (void) fprintf(stderr, + gettext("Error input option\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (filename == NULL) { + filename = strdup(KMF_DEFAULT_POLICY_FILE); + if (filename == NULL) { + rv = KC_ERR_MEMORY; + goto out; + } + } + + /* Check the access permission of the policy DB */ + if (access(filename, R_OK) < 0) { + int err = errno; + (void) fprintf(stderr, + gettext("Cannot access \"%s\" for list - %s\n"), filename, + strerror(err)); + rv = KC_ERR_ACCESS; + goto out; + } + + rv = load_policies(filename, &plclist); + if (rv != KMF_OK) { + goto out; + } + + pnode = plclist; + while (pnode != NULL) { + if (policyname == NULL || + strcmp(policyname, pnode->plc.name) == 0) { + KMF_POLICY_RECORD *plc = &pnode->plc; + + found++; + rv = KMF_VerifyPolicy(plc); + if (rv != KMF_OK) { + (void) fprintf(stderr, gettext( + "Policy Name: '%s' is invalid\n"), + plc->name); + sanity_err++; + } else { + show_policy(&pnode->plc); + } + } + pnode = pnode->next; + } + + free_policy_list(plclist); + + if (!found) { + if (policyname) + (void) fprintf(stderr, gettext( + "Cannot find policy '%s'\n"), policyname); + else + (void) fprintf(stderr, gettext("Cannot find " + "any policies to display\n")); + rv = KC_ERR_FIND_POLICY; + } else if (sanity_err) { + rv = KC_ERR_VERIFY_POLICY; + } + +out: + + if (filename != NULL) + free(filename); + + if (policyname != NULL) + free(policyname); + + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/modify.c b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c new file mode 100644 index 0000000000..413bda3be7 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c @@ -0,0 +1,845 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> +#include <errno.h> +#include <kmfapiP.h> +#include <cryptoutil.h> +#include "util.h" + +#define KC_IGNORE_DATE 0x0000001 +#define KC_IGNORE_UNKNOWN_EKUS 0x0000002 +#define KC_IGNORE_TRUST_ANCHOR 0x0000004 +#define KC_VALIDITY_ADJUSTTIME 0x0000008 +#define KC_TA_NAME 0x0000010 +#define KC_TA_SERIAL 0x0000020 +#define KC_OCSP_RESPONDER_URI 0x0000040 +#define KC_OCSP_PROXY 0x0000080 +#define KC_OCSP_URI_FROM_CERT 0x0000100 +#define KC_OCSP_RESP_LIFETIME 0x0000200 +#define KC_OCSP_IGNORE_RESP_SIGN 0x0000400 +#define KC_OCSP_RESP_CERT_NAME 0x0000800 +#define KC_OCSP_RESP_CERT_SERIAL 0x0001000 +#define KC_OCSP_NONE 0x0002000 +#define KC_CRL_BASEFILENAME 0x0004000 +#define KC_CRL_DIRECTORY 0x0008000 +#define KC_CRL_GET_URI 0x0010000 +#define KC_CRL_PROXY 0x0020000 +#define KC_CRL_IGNORE_SIGN 0x0040000 +#define KC_CRL_IGNORE_DATE 0x0080000 +#define KC_CRL_NONE 0x0100000 +#define KC_KEYUSAGE 0x0200000 +#define KC_KEYUSAGE_NONE 0x0400000 +#define KC_EKUS 0x0800000 +#define KC_EKUS_NONE 0x1000000 + +int +kc_modify(int argc, char *argv[]) +{ + KMF_RETURN ret; + int rv = KC_OK; + int opt; + extern int optind_av; + extern char *optarg_av; + char *filename = NULL; + uint32_t flags = 0; + boolean_t ocsp_none_opt = B_FALSE; + boolean_t crl_none_opt = B_FALSE; + boolean_t ku_none_opt = B_FALSE; + boolean_t eku_none_opt = B_FALSE; + int ocsp_set_attr = 0; + int crl_set_attr = 0; + KMF_POLICY_RECORD oplc, plc; + + (void) memset(&plc, 0, sizeof (KMF_POLICY_RECORD)); + (void) memset(&oplc, 0, sizeof (KMF_POLICY_RECORD)); + + while ((opt = getopt_av(argc, argv, + "i:(dbfile)" + "p:(policy)" + "d:(ignore-date)" + "e:(ignore-unknown-eku)" + "a:(ignore-trust-anchor)" + "v:(validity-adjusttime)" + "t:(ta-name)" + "s:(ta-serial)" + "o:(ocsp-responder)" + "P:(ocsp-proxy)" + "r:(ocsp-use-cert-responder)" + "T:(ocsp-response-lifetime)" + "R:(ocsp-ignore-response-sign)" + "n:(ocsp-responder-cert-name)" + "A:(ocsp-responder-cert-serial)" + "y:(ocsp-none)" + "c:(crl-basefilename)" + "I:(crl-directory)" + "g:(crl-get-crl-uri)" + "X:(crl-proxy)" + "S:(crl-ignore-crl-sign)" + "D:(crl-ignore-crl-date)" + "z:(crl-none)" + "u:(keyusage)" + "Y:(keyusage-none)" + "E:(ekunames)" + "O:(ekuoids)" + "Z:(eku-none)")) != EOF) { + switch (opt) { + case 'i': + filename = get_string(optarg_av, &rv); + if (filename == NULL) { + (void) fprintf(stderr, + gettext("Error dbfile input.\n")); + } + break; + case 'p': + plc.name = get_string(optarg_av, &rv); + if (plc.name == NULL) { + (void) fprintf(stderr, + gettext("Error policy name.\n")); + } + break; + case 'd': + plc.ignore_date = get_boolean(optarg_av); + if (plc.ignore_date == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_IGNORE_DATE; + } + break; + case 'e': + plc.ignore_unknown_ekus = + get_boolean(optarg_av); + if (plc.ignore_unknown_ekus == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_IGNORE_UNKNOWN_EKUS; + } + break; + case 'a': + plc.ignore_trust_anchor = + get_boolean(optarg_av); + if (plc.ignore_trust_anchor == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_IGNORE_TRUST_ANCHOR; + } + break; + case 'v': + plc.validity_adjusttime = + get_string(optarg_av, &rv); + if (plc.validity_adjusttime == NULL) { + (void) fprintf(stderr, + gettext("Error time input.\n")); + } else { + uint32_t adj; + /* for syntax checking */ + if (str2lifetime( + plc.validity_adjusttime, + &adj) < 0) { + (void) fprintf(stderr, + gettext("Error time " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_VALIDITY_ADJUSTTIME; + } + } + break; + case 't': + plc.ta_name = get_string(optarg_av, &rv); + if (plc.ta_name == NULL) { + (void) fprintf(stderr, + gettext("Error name input.\n")); + } else { + KMF_X509_NAME taDN; + /* for syntax checking */ + if (KMF_DNParser(plc.ta_name, + &taDN) != KMF_OK) { + (void) fprintf(stderr, + gettext("Error name " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + KMF_FreeDN(&taDN); + flags |= KC_TA_NAME; + } + } + break; + case 's': + plc.ta_serial = get_string(optarg_av, &rv); + if (plc.ta_serial == NULL) { + (void) fprintf(stderr, + gettext("Error serial input.\n")); + } else { + uchar_t *bytes = NULL; + size_t bytelen; + + ret = KMF_HexString2Bytes( + (uchar_t *)plc.ta_serial, + &bytes, &bytelen); + if (ret != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, + gettext("serial number " + "must be specified as a " + "hex number " + "(ex: 0x0102030405" + "ffeeddee)\n")); + rv = KC_ERR_USAGE; + break; + } + if (bytes != NULL) + free(bytes); + flags |= KC_TA_SERIAL; + } + break; + case 'o': + plc.VAL_OCSP_RESPONDER_URI = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESPONDER_URI == NULL) { + (void) fprintf(stderr, + gettext("Error responder " + "input.\n")); + } else { + flags |= KC_OCSP_RESPONDER_URI; + ocsp_set_attr++; + } + break; + case 'P': + plc.VAL_OCSP_PROXY = get_string(optarg_av, &rv); + if (plc.VAL_OCSP_PROXY == NULL) { + (void) fprintf(stderr, + gettext("Error proxy input.\n")); + } else { + flags |= KC_OCSP_PROXY; + ocsp_set_attr++; + } + break; + case 'r': + plc.VAL_OCSP_URI_FROM_CERT = + get_boolean(optarg_av); + if (plc.VAL_OCSP_URI_FROM_CERT == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_OCSP_URI_FROM_CERT; + ocsp_set_attr++; + } + break; + case 'T': + plc.VAL_OCSP_RESP_LIFETIME = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESP_LIFETIME == NULL) { + (void) fprintf(stderr, + gettext("Error time input.\n")); + } else { + uint32_t adj; + /* for syntax checking */ + if (str2lifetime( + plc.VAL_OCSP_RESP_LIFETIME, + &adj) < 0) { + (void) fprintf(stderr, + gettext("Error time " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_OCSP_RESP_LIFETIME; + ocsp_set_attr++; + } + } + break; + case 'R': + plc.VAL_OCSP_IGNORE_RESP_SIGN = + get_boolean(optarg_av); + if (plc.VAL_OCSP_IGNORE_RESP_SIGN == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_OCSP_IGNORE_RESP_SIGN; + ocsp_set_attr++; + } + break; + case 'n': + plc.VAL_OCSP_RESP_CERT_NAME = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESP_CERT_NAME == NULL) { + (void) fprintf(stderr, + gettext("Error name input.\n")); + } else { + KMF_X509_NAME respDN; + /* for syntax checking */ + if (KMF_DNParser( + plc.VAL_OCSP_RESP_CERT_NAME, + &respDN) != KMF_OK) { + (void) fprintf(stderr, + gettext("Error name " + "input.\n")); + rv = KC_ERR_USAGE; + } else { + KMF_FreeDN(&respDN); + flags |= KC_OCSP_RESP_CERT_NAME; + ocsp_set_attr++; + } + } + break; + case 'A': + plc.VAL_OCSP_RESP_CERT_SERIAL = + get_string(optarg_av, &rv); + if (plc.VAL_OCSP_RESP_CERT_SERIAL == NULL) { + (void) fprintf(stderr, + gettext("Error serial input.\n")); + } else { + uchar_t *bytes = NULL; + size_t bytelen; + + ret = KMF_HexString2Bytes((uchar_t *) + plc.VAL_OCSP_RESP_CERT_SERIAL, + &bytes, &bytelen); + if (ret != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, + gettext("serial number " + "must be specified as a " + "hex number " + "(ex: 0x0102030405" + "ffeeddee)\n")); + rv = KC_ERR_USAGE; + break; + } + if (bytes != NULL) + free(bytes); + flags |= KC_OCSP_RESP_CERT_SERIAL; + ocsp_set_attr++; + } + break; + case 'y': + ocsp_none_opt = get_boolean(optarg_av); + if (ocsp_none_opt == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_OCSP_NONE; + } + break; + case 'c': + plc.VAL_CRL_BASEFILENAME = + get_string(optarg_av, &rv); + if (plc.VAL_CRL_BASEFILENAME == NULL) { + (void) fprintf(stderr, gettext( + "Error basefilename input.\n")); + } else { + flags |= KC_CRL_BASEFILENAME; + crl_set_attr++; + } + break; + case 'I': + plc.VAL_CRL_DIRECTORY = + get_string(optarg_av, &rv); + if (plc.VAL_CRL_DIRECTORY == NULL) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + } else { + flags |= KC_CRL_DIRECTORY; + crl_set_attr++; + } + break; + case 'g': + plc.VAL_CRL_GET_URI = get_boolean(optarg_av); + if (plc.VAL_CRL_GET_URI == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_CRL_GET_URI; + crl_set_attr++; + } + break; + case 'X': + plc.VAL_CRL_PROXY = get_string(optarg_av, &rv); + if (plc.VAL_CRL_PROXY == NULL) { + (void) fprintf(stderr, + gettext("Error proxy input.\n")); + } else { + flags |= KC_CRL_PROXY; + crl_set_attr++; + } + break; + case 'S': + plc.VAL_CRL_IGNORE_SIGN = + get_boolean(optarg_av); + if (plc.VAL_CRL_IGNORE_SIGN == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_CRL_IGNORE_SIGN; + crl_set_attr++; + } + break; + case 'D': + plc.VAL_CRL_IGNORE_DATE = + get_boolean(optarg_av); + if (plc.VAL_CRL_IGNORE_DATE == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_CRL_IGNORE_DATE; + crl_set_attr++; + } + break; + case 'z': + crl_none_opt = get_boolean(optarg_av); + if (crl_none_opt == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_CRL_NONE; + } + break; + case 'u': + plc.ku_bits = parseKUlist(optarg_av); + if (plc.ku_bits == 0) { + (void) fprintf(stderr, gettext( + "Error keyusage input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_KEYUSAGE; + } + break; + case 'Y': + ku_none_opt = get_boolean(optarg_av); + if (ku_none_opt == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_KEYUSAGE_NONE; + } + break; + case 'E': + if (parseEKUNames(optarg_av, &plc) != 0) { + (void) fprintf(stderr, + gettext("Error EKU input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_EKUS; + } + break; + case 'O': + if (parseEKUOIDs(optarg_av, &plc) != 0) { + (void) fprintf(stderr, + gettext("Error EKU OID input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_EKUS; + } + break; + case 'Z': + eku_none_opt = get_boolean(optarg_av); + if (eku_none_opt == -1) { + (void) fprintf(stderr, + gettext("Error boolean input.\n")); + rv = KC_ERR_USAGE; + } else { + flags |= KC_EKUS_NONE; + } + break; + default: + (void) fprintf(stderr, + gettext("Error input option.\n")); + rv = KC_ERR_USAGE; + break; + } + if (rv != KC_OK) + goto out; + } + + /* No additional args allowed. */ + argc -= optind_av; + if (argc) { + (void) fprintf(stderr, + gettext("Error input option\n")); + rv = KC_ERR_USAGE; + goto out; + } + + if (filename == NULL) { + filename = strdup(KMF_DEFAULT_POLICY_FILE); + if (filename == NULL) { + rv = KC_ERR_MEMORY; + goto out; + } + } + + /* + * Must have a policy name. The policy name can not be default + * if using the default policy file. + */ + if (plc.name == NULL) { + (void) fprintf(stderr, + gettext("You must specify a policy name.\n")); + rv = KC_ERR_USAGE; + goto out; + } else if (strcmp(filename, KMF_DEFAULT_POLICY_FILE) == 0 && + strcmp(plc.name, KMF_DEFAULT_POLICY_NAME) == 0) { + (void) fprintf(stderr, + gettext("Can not modify the default policy in the default " + "policy file.\n")); + rv = KC_ERR_USAGE; + goto out; + } + + /* Check the access permission of the policy DB */ + if (access(filename, W_OK) < 0) { + int err = errno; + (void) fprintf(stderr, + gettext("Cannot access \"%s\" for modify - %s\n"), + filename, strerror(err)); + rv = KC_ERR_ACCESS; + goto out; + } + + /* Try to load the named policy from the DB */ + ret = KMF_GetPolicy(filename, plc.name, &oplc); + if (ret != KMF_OK) { + (void) fprintf(stderr, + gettext("Error loading policy \"%s\" from %s\n"), filename, + plc.name); + return (KC_ERR_FIND_POLICY); + } + + /* Update the general policy attributes. */ + if (flags & KC_IGNORE_DATE) + oplc.ignore_date = plc.ignore_date; + + if (flags & KC_IGNORE_UNKNOWN_EKUS) + oplc.ignore_unknown_ekus = plc.ignore_unknown_ekus; + + if (flags & KC_IGNORE_TRUST_ANCHOR) + oplc.ignore_trust_anchor = plc.ignore_trust_anchor; + + if (flags & KC_VALIDITY_ADJUSTTIME) { + if (oplc.validity_adjusttime) + free(oplc.validity_adjusttime); + oplc.validity_adjusttime = + plc.validity_adjusttime; + } + + if (flags & KC_TA_NAME) { + if (oplc.ta_name) + free(oplc.ta_name); + oplc.ta_name = plc.ta_name; + } + if (flags & KC_TA_SERIAL) { + if (oplc.ta_serial) + free(oplc.ta_serial); + oplc.ta_serial = plc.ta_serial; + } + + /* Update the OCSP policy */ + if (ocsp_none_opt == B_TRUE) { + if (ocsp_set_attr > 0) { + (void) fprintf(stderr, + gettext("Can not set ocsp-none=true and other " + "OCSP attributes at the same time.\n")); + rv = KC_ERR_USAGE; + goto out; + } + + /* + * If the original policy does not have OCSP checking, + * then we do not need to do anything. If the original + * policy has the OCSP checking, then we need to release the + * space of OCSP attributes and turn the OCSP checking off. + */ + if (oplc.revocation & KMF_REVOCATION_METHOD_OCSP) { + if (oplc.VAL_OCSP_BASIC.responderURI) { + free(oplc.VAL_OCSP_BASIC.responderURI); + oplc.VAL_OCSP_BASIC.responderURI = NULL; + } + + if (oplc.VAL_OCSP_BASIC.proxy) { + free(oplc.VAL_OCSP_BASIC.proxy); + oplc.VAL_OCSP_BASIC.proxy = NULL; + } + + if (oplc.VAL_OCSP_BASIC.response_lifetime) { + free(oplc.VAL_OCSP_BASIC.response_lifetime); + oplc.VAL_OCSP_BASIC.response_lifetime = NULL; + } + + if (flags & KC_OCSP_RESP_CERT_NAME) { + free(oplc.VAL_OCSP_RESP_CERT.name); + oplc.VAL_OCSP_RESP_CERT.name = NULL; + } + + if (flags & KC_OCSP_RESP_CERT_SERIAL) { + free(oplc.VAL_OCSP_RESP_CERT.serial); + oplc.VAL_OCSP_RESP_CERT.serial = NULL; + } + + /* Turn off the OCSP checking */ + oplc.revocation &= ~KMF_REVOCATION_METHOD_OCSP; + } + + } else { + /* + * If the "ocsp-none" option is not set or is set to false, + * then we only need to do the modification if there is at + * least one OCSP attribute is specified. + */ + if (ocsp_set_attr > 0) { + if (flags & KC_OCSP_RESPONDER_URI) { + if (oplc.VAL_OCSP_RESPONDER_URI) + free(oplc.VAL_OCSP_RESPONDER_URI); + oplc.VAL_OCSP_RESPONDER_URI = + plc.VAL_OCSP_RESPONDER_URI; + } + + if (flags & KC_OCSP_PROXY) { + if (oplc.VAL_OCSP_PROXY) + free(oplc.VAL_OCSP_PROXY); + oplc.VAL_OCSP_PROXY = plc.VAL_OCSP_PROXY; + } + + if (flags & KC_OCSP_URI_FROM_CERT) + oplc.VAL_OCSP_URI_FROM_CERT = + plc.VAL_OCSP_URI_FROM_CERT; + + if (flags & KC_OCSP_RESP_LIFETIME) { + if (oplc.VAL_OCSP_RESP_LIFETIME) + free(oplc.VAL_OCSP_RESP_LIFETIME); + oplc.VAL_OCSP_RESP_LIFETIME = + plc.VAL_OCSP_RESP_LIFETIME; + } + + if (flags & KC_OCSP_IGNORE_RESP_SIGN) + oplc.VAL_OCSP_IGNORE_RESP_SIGN = + plc.VAL_OCSP_IGNORE_RESP_SIGN; + + if (flags & KC_OCSP_RESP_CERT_NAME) { + if (oplc.VAL_OCSP_RESP_CERT_NAME) + free(oplc.VAL_OCSP_RESP_CERT_NAME); + oplc.VAL_OCSP_RESP_CERT_NAME = + plc.VAL_OCSP_RESP_CERT_NAME; + } + + if (flags & KC_OCSP_RESP_CERT_SERIAL) { + if (oplc.VAL_OCSP_RESP_CERT_SERIAL) + free(oplc.VAL_OCSP_RESP_CERT_SERIAL); + oplc.VAL_OCSP_RESP_CERT_SERIAL = + plc.VAL_OCSP_RESP_CERT_SERIAL; + } + + if (oplc.VAL_OCSP_RESP_CERT_NAME != NULL && + oplc.VAL_OCSP_RESP_CERT_SERIAL != NULL) + oplc.VAL_OCSP.has_resp_cert = B_TRUE; + else + oplc.VAL_OCSP.has_resp_cert = B_FALSE; + + /* Turn on the OCSP checking */ + oplc.revocation |= KMF_REVOCATION_METHOD_OCSP; + } + } + + /* Update the CRL policy */ + if (crl_none_opt == B_TRUE) { + if (crl_set_attr > 0) { + (void) fprintf(stderr, + gettext("Can not set crl-none=true and other CRL " + "attributes at the same time.\n")); + rv = KC_ERR_USAGE; + goto out; + } + + /* + * If the original policy does not have CRL checking, + * then we do not need to do anything. If the original + * policy has the CRL checking, then we need to release the + * space of CRL attributes and turn the CRL checking off. + */ + if (oplc.revocation & KMF_REVOCATION_METHOD_CRL) { + if (oplc.VAL_CRL_BASEFILENAME) { + free(oplc.VAL_CRL_BASEFILENAME); + oplc.VAL_CRL_BASEFILENAME = NULL; + } + + if (oplc.VAL_CRL_DIRECTORY) { + free(oplc.VAL_CRL_DIRECTORY); + oplc.VAL_CRL_DIRECTORY = NULL; + } + + if (oplc.VAL_CRL_PROXY) { + free(oplc.VAL_CRL_PROXY); + oplc.VAL_CRL_PROXY = NULL; + } + + /* Turn off the CRL checking */ + oplc.revocation &= ~KMF_REVOCATION_METHOD_CRL; + } + } else { + /* + * If the "ocsp-none" option is not set or is set to false, + * then we only need to do the modification if there is at + * least one CRL attribute is specified. + */ + if (crl_set_attr > 0) { + if (flags & KC_CRL_BASEFILENAME) { + if (oplc.VAL_CRL_BASEFILENAME) + free(oplc.VAL_CRL_BASEFILENAME); + oplc.VAL_CRL_BASEFILENAME = + plc.VAL_CRL_BASEFILENAME; + } + + if (flags & KC_CRL_DIRECTORY) { + if (oplc.VAL_CRL_DIRECTORY) + free(oplc.VAL_CRL_DIRECTORY); + oplc.VAL_CRL_DIRECTORY = plc.VAL_CRL_DIRECTORY; + } + + if (flags & KC_CRL_GET_URI) { + oplc.VAL_CRL_GET_URI = plc.VAL_CRL_GET_URI; + } + + if (flags & KC_CRL_PROXY) { + if (oplc.VAL_CRL_PROXY) + free(oplc.VAL_CRL_PROXY); + oplc.VAL_CRL_PROXY = plc.VAL_CRL_PROXY; + } + + if (flags & KC_CRL_IGNORE_SIGN) { + oplc.VAL_CRL_IGNORE_SIGN = + plc.VAL_CRL_IGNORE_SIGN; + } + + if (flags & KC_CRL_IGNORE_DATE) { + oplc.VAL_CRL_IGNORE_DATE = + plc.VAL_CRL_IGNORE_DATE; + } + + /* Turn on the CRL checking */ + oplc.revocation |= KMF_REVOCATION_METHOD_CRL; + } + } + + /* Update the Key Usage */ + if (ku_none_opt == B_TRUE) { + if (flags & KC_KEYUSAGE) { + (void) fprintf(stderr, + gettext("Can not set keyusage-none=true and " + "modify the keyusage value at the same time.\n")); + rv = KC_ERR_USAGE; + goto out; + } + + oplc.ku_bits = 0; + } else { + /* + * If the "keyusage-none" option is not set or is set to + * false, then we only need to do the modification if + * the keyusage value is specified. + */ + if (flags & KC_KEYUSAGE) + oplc.ku_bits = plc.ku_bits; + } + + + /* Update the Extended Key Usage */ + if (eku_none_opt == B_TRUE) { + if (flags & KC_EKUS) { + (void) fprintf(stderr, + gettext("Can not set eku-none=true and modify " + "EKU values at the same time.\n")); + rv = KC_ERR_USAGE; + goto out; + } + + /* Release current EKU list (if any) */ + if (oplc.eku_set.eku_count > 0) { + KMF_FreeEKUPolicy(&oplc.eku_set); + oplc.eku_set.eku_count = 0; + oplc.eku_set.ekulist = NULL; + } + } else { + /* + * If the "eku-none" option is not set or is set to false, + * then we only need to do the modification if either + * "ekuname" or "ekuoids" is specified. + */ + if (flags & KC_EKUS) { + /* Release current EKU list (if any) */ + KMF_FreeEKUPolicy(&oplc.eku_set); + oplc.eku_set = plc.eku_set; + } + } + + /* Do a sanity check on the modified policy */ + ret = KMF_VerifyPolicy(&oplc); + if (ret != KMF_OK) { + print_sanity_error(ret); + rv = KC_ERR_VERIFY_POLICY; + goto out; + } + + /* The modify operation is a delete followed by an add */ + ret = KMF_DeletePolicyFromDB(oplc.name, filename); + if (ret != KMF_OK) { + rv = KC_ERR_DELETE_POLICY; + goto out; + } + + /* + * Now add the modified policy back to the DB. + */ + ret = KMF_AddPolicyToDB(&oplc, filename, B_FALSE); + if (ret != KMF_OK) { + (void) fprintf(stderr, + gettext("Error adding policy to database: 0x%04x\n"), ret); + rv = KC_ERR_ADD_POLICY; + goto out; + } + +out: + if (filename != NULL) + free(filename); + + KMF_FreePolicyRecord(&oplc); + + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/util.c b/usr/src/cmd/cmd-crypto/kmfcfg/util.c new file mode 100644 index 0000000000..f3bdc633f2 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/util.c @@ -0,0 +1,497 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <libgen.h> +#include <libintl.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <kmfapiP.h> + +#include "util.h" + +/* Supporting structures and global variables for getopt_av(). */ +typedef struct av_opts_s { + int shortnm; /* short name character */ + char *longnm; /* long name string, NOT terminated */ + int longnm_len; /* length of long name string */ + boolean_t has_arg; /* takes optional argument */ +} av_opts; + +static av_opts *opts_av = NULL; +static const char *_save_optstr = NULL; +static int _save_numopts = 0; +int optind_av = 1; +char *optarg_av = NULL; + +void +free_policy_list(POLICY_LIST *plist) +{ + POLICY_LIST *n = plist, *old; + + if (plist == NULL) + return; + + while (n != NULL) { + old = n; + KMF_FreePolicyRecord(&n->plc); + n = n->next; + free(old); + } + plist = NULL; +} + +int +load_policies(char *file, POLICY_LIST **policy_list) +{ + int rv = KC_OK; + KMF_RETURN kmfrv = KMF_OK; + POLICY_LIST *newitem, *plist = NULL; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc = NULL; + xmlNodePtr cur, node; + + /* Create a parser context */ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return (KMF_ERR_POLICY_DB_FORMAT); + + /* Read the policy DB and verify it against the schema. */ + doc = xmlCtxtReadFile(ctxt, file, NULL, + XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (doc == NULL || ctxt->valid == 0) { + kmfrv = KMF_ERR_POLICY_DB_FORMAT; + goto end; + } + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + kmfrv = KMF_ERR_POLICY_DB_FORMAT; + goto end; + } + + node = cur->xmlChildrenNode; + while (node != NULL) { + char *c; + /* + * Search for the policy that matches the given name. + */ + if (!xmlStrcmp((const xmlChar *)node->name, + (const xmlChar *)KMF_POLICY_ELEMENT)) { + /* Check the name attribute */ + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_NAME_ATTR); + + /* If a match, parse the rest of the data */ + if (c != NULL) { + xmlFree(c); + newitem = malloc(sizeof (POLICY_LIST)); + if (newitem != NULL) { + (void) memset(newitem, 0, + sizeof (POLICY_LIST)); + kmfrv = parsePolicyElement(node, + &newitem->plc); + } else { + kmfrv = KMF_ERR_MEMORY; + goto end; + } + /* add to linked list */ + if (plist == NULL) { + plist = newitem; + } else { + POLICY_LIST *n = plist; + while (n->next != NULL) + n = n->next; + + n->next = newitem; + newitem->next = NULL; + } + } + } + node = node->next; + } + +end: + if (ctxt != NULL) + xmlFreeParserCtxt(ctxt); + + if (doc != NULL) + xmlFreeDoc(doc); + + if (kmfrv != KMF_OK) { + free_policy_list(plist); + rv = KC_ERR_LOADDB; + } else { + *policy_list = plist; + } + + return (rv); +} + +/* + * Return 0 if there is any error in the input string. + */ +uint16_t +parseKUlist(char *kustring) +{ + uint16_t cur_bit; + uint16_t kubits = 0; + char *p; + + p = strtok(kustring, ","); + while (p != NULL) { + cur_bit = KMF_StringToKeyUsage(p); + if (cur_bit == 0) { + kubits = 0; + break; + } + kubits |= cur_bit; + p = strtok(NULL, ","); + } + + return (kubits); +} + +static void +addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid) +{ + if (newoid != NULL && ekus != NULL) { + ekus->eku_count++; + ekus->ekulist = realloc( + ekus->ekulist, + ekus->eku_count * sizeof (KMF_OID)); + if (ekus->ekulist != NULL) { + ekus->ekulist[ekus->eku_count-1] = *newoid; + } + } +} + +int +parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc) +{ + int rv = KC_OK; + char *p; + KMF_OID *newoid; + KMF_EKU_POLICY *ekus = &plc->eku_set; + + if (ekulist == NULL || !strlen(ekulist)) + return (0); + + /* + * The list should be comma separated list of EKU Names. + */ + p = strtok(ekulist, ","); + + /* If no tokens found, then maybe its just a single EKU value */ + if (p == NULL) { + newoid = kmf_ekuname2oid(ekulist); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + } + } + + while (p != NULL) { + newoid = kmf_ekuname2oid(p); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + break; + } + p = strtok(NULL, ","); + } + + if (rv != KC_OK) + KMF_FreeEKUPolicy(ekus); + + return (rv); +} + +int +parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc) +{ + int rv = KC_OK; + char *p; + KMF_OID *newoid; + KMF_EKU_POLICY *ekus = &plc->eku_set; + + if (ekulist == NULL || !strlen(ekulist)) + return (0); + + /* + * The list should be comma separated list of EKU Names. + */ + p = strtok(ekulist, ","); + if (p == NULL) { + newoid = kmf_string2oid(ekulist); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + } + } + + while (p != NULL && rv == 0) { + newoid = kmf_string2oid(p); + if (newoid != NULL) { + addToEKUList(ekus, newoid); + free(newoid); + } else { + rv = KC_ERR_USAGE; + break; + } + p = strtok(NULL, ","); + } + + if (rv != KC_OK) + KMF_FreeEKUPolicy(ekus); + + return (rv); +} + +int +get_boolean(char *arg) +{ + if (arg == NULL) + return (-1); + if (strcasecmp(arg, "true") == 0) + return (1); + if (strcasecmp(arg, "false") == 0) + return (0); + return (-1); +} + +/* + * This function processes the input string. It removes the beginning + * and ending blank's first, makes a copy of the resulting string and + * return it. + * + * This function returns NULL, if there is an error in the + * input string or when the system is out of memory. The output + * "err_flag" argument will record the error code, if it is not NULL. + */ +char * +get_string(char *str, int *err_flag) +{ + char *p; + int len, i; + char *retstr = NULL; + + if (str == NULL) { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + + /* Remove beginning whitespace */ + p = str; + while (p != NULL && isspace(*p)) + p++; + + if (p == NULL) { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + + /* Remove the trailing blanks */ + len = strlen(p); + while (len > 0 && isspace(p[len-1])) + len--; + + if (len == 0) { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + + /* Check if there is any non-printable character */ + i = 0; + while (i < len) { + if (isprint(p[i])) + i++; + else { + if (err_flag != NULL) + *err_flag = KC_ERR_USAGE; + return (NULL); + } + } + + /* Make a copy of the string and return it */ + retstr = malloc(len + 1); + if (retstr == NULL) { + if (err_flag != NULL) + *err_flag = KC_ERR_MEMORY; + return (NULL); + } + + if (err_flag != NULL) + *err_flag = KC_OK; + + (void) strncpy(retstr, p, len); + retstr[len] = '\0'; + return (retstr); +} + +/* + * Breaks out the getopt-style option string into a structure that can be + * traversed later for calls to getopt_av(). Option string is NOT altered, + * but the struct fields point to locations within option string. + */ +static int +populate_opts(char *optstring) +{ + int i; + av_opts *temp; + char *marker; + + if (optstring == NULL || *optstring == '\0') + return (0); + + /* + * This tries to imitate getopt(3c) Each option must conform to: + * <short name char> [ ':' ] [ '(' <long name string> ')' ] + * If long name is missing, the short name is used for long name. + */ + for (i = 0; *optstring != '\0'; i++) { + if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : + realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { + free(opts_av); + opts_av = NULL; + return (0); + } else + opts_av = (av_opts *)temp; + + marker = optstring; /* may need optstring later */ + + opts_av[i].shortnm = *marker++; /* set short name */ + + if (*marker == ':') { /* check for opt arg */ + marker++; + opts_av[i].has_arg = B_TRUE; + } + + if (*marker == '(') { /* check and set long name */ + marker++; + opts_av[i].longnm = marker; + opts_av[i].longnm_len = strcspn(marker, ")"); + optstring = marker + opts_av[i].longnm_len + 1; + } else { + /* use short name option character */ + opts_av[i].longnm = optstring; + opts_av[i].longnm_len = 1; + optstring = marker; + } + } + + return (i); +} + +/* + * getopt_av() is very similar to getopt(3c) in that the takes an option + * string, compares command line arguments for matches, and returns a single + * letter option when a match is found. However, getopt_av() differs from + * getopt(3c) by allowing both longname options and values be found + * on the command line. + */ +int +getopt_av(int argc, char * const *argv, const char *optstring) +{ + int i; + int len; + + if (optind_av >= argc) + return (EOF); + + /* First time or when optstring changes from previous one */ + if (_save_optstr != optstring) { + if (opts_av != NULL) + free(opts_av); + opts_av = NULL; + _save_optstr = optstring; + _save_numopts = populate_opts((char *)optstring); + } + + for (i = 0; i < _save_numopts; i++) { + if (strcmp(argv[optind_av], "--") == 0) { + optind_av++; + break; + } + + len = strcspn(argv[optind_av], "="); + + if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], + opts_av[i].longnm, opts_av[i].longnm_len) == 0) { + /* matched */ + if (!opts_av[i].has_arg) { + optind_av++; + return (opts_av[i].shortnm); + } + + /* needs optarg */ + if (argv[optind_av][len] == '=') { + optarg_av = &(argv[optind_av][len+1]); + optind_av++; + return (opts_av[i].shortnm); + } + + optarg_av = NULL; + optind_av++; + return ((int)'?'); + } + } + + return (EOF); +} + +void +print_sanity_error(KMF_RETURN ret) +{ + switch (ret) { + case KMF_ERR_POLICY_NAME: + (void) fprintf(stderr, gettext("Error in the policy name\n")); + break; + case KMF_ERR_TA_POLICY: + (void) fprintf(stderr, + gettext("Error in trust anchor attributes\n")); + break; + case KMF_ERR_OCSP_POLICY: + (void) fprintf(stderr, + gettext("Error in OCSP policy attributes\n")); + break; + default: + break; + } +} diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/util.h b/usr/src/cmd/cmd-crypto/kmfcfg/util.h new file mode 100644 index 0000000000..74f4b0be9b --- /dev/null +++ b/usr/src/cmd/cmd-crypto/kmfcfg/util.h @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _UTIL_H +#define _UTIL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <kmfapiP.h> + + +typedef struct _policy_list { + KMF_POLICY_RECORD plc; + struct _policy_list *next; +} POLICY_LIST; + +void free_policy_list(POLICY_LIST *); +int getopt_av(int, char * const *, const char *); + +int load_policies(char *, POLICY_LIST **); +int get_boolean(char *); +char *get_string(char *, int *err_flag); +int parseEKUOIDs(char *, KMF_POLICY_RECORD *); +int parseEKUNames(char *, KMF_POLICY_RECORD *); +uint16_t parseKUlist(char *); +void print_sanity_error(KMF_RETURN); + +#define KC_OK 0 +#define KC_ERR_USAGE 1 +#define KC_ERR_LOADDB 2 +#define KC_ERR_FIND_POLICY 3 +#define KC_ERR_DELETE_POLICY 4 +#define KC_ERR_ADD_POLICY 5 +#define KC_ERR_VERIFY_POLICY 6 +#define KC_ERR_INCOMPLETE_POLICY 7 +#define KC_ERR_MEMORY 8 +#define KC_ERR_ACCESS 9 + +#ifdef __cplusplus +} +#endif +#endif /* _UTIL_H */ diff --git a/usr/src/cmd/cmd-crypto/pktool/Makefile b/usr/src/cmd/cmd-crypto/pktool/Makefile index 0ad8e96905..dcfefac49a 100644 --- a/usr/src/cmd/cmd-crypto/pktool/Makefile +++ b/usr/src/cmd/cmd-crypto/pktool/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -30,31 +29,30 @@ PROG = pktool OBJS = pktool.o \ common.o \ - derparse.o \ - osslcommon.o \ - p12common.o \ setpin.o \ list.o \ delete.o \ import.o \ export.o \ - tokens.o + tokens.o \ + gencert.o \ + gencsr.o \ + download.o \ + genkey.o include ../../Makefile.cmd -include $(SRC)/lib/openssl/Makefile.openssl +KMFDIR = $(SRC)/lib/libkmf SRCS = $(OBJS:%.o=%.c) POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_msg.po +MSGFILES=$(SRCS:%.c=%.i) -CPPFLAGS += -I. $(OPENSSL_CPPFLAGS) -CFLAGS += $(CCVERBOSE) +CPPFLAGS += -I. -I$(KMFDIR)/include +CFLAGS += $(CCVERBOSE) -DDEBUG -DYNFLAGS += $(OPENSSL_DYNFLAGS) -LDFLAGS += $(OPENSSL_LDFLAGS) -LDLIBS += -lpkcs11 -lcryptoutil -lcrypto -lldap - -LINTFLAGS += $(OPENSSL_LDFLAGS) +LDFLAGS += -L$(SRC)/lib/libkmf/libkmf/$(MACH) +LDLIBS += -lkmf -lpkcs11 -lcryptoutil .KEEP_STATE: @@ -65,7 +63,7 @@ $(PROG) : $(OBJS) $(POST_PROCESS) $(POFILE) : $(POFILES) - $(RM) $@; cat $(POFILES) > $@ + $(BUILDPO.pofiles) install : all $(ROOTPROG) @@ -75,4 +73,3 @@ clean : lint : lint_SRCS include ../../Makefile.targ - diff --git a/usr/src/cmd/cmd-crypto/pktool/biginteger.h b/usr/src/cmd/cmd-crypto/pktool/biginteger.h deleted file mode 100644 index 3764e47aaa..0000000000 --- a/usr/src/cmd/cmd-crypto/pktool/biginteger.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _PKTOOL_BIGINTEGER_H -#define _PKTOOL_BIGINTEGER_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <security/pkcs11t.h> - -/* - * NOTE: - * - * This is same "biginteger_t" found in both these places: - * usr/src/lib/pkcs11/pkcs11_softtoken/common/softObject.h - * usr/src/lib/pkcs11/pkcs11_kernel/common/kernelObject.h - * The BIGNUM implementation in usr/src/common/bignum does not - * meet the need. It is recommended that the biginteger_t be - * factored out of pkcs11_softtoken/pkcs11_kernel/pktool and - * the pkcs11 libraries and moved into cryptoutil.h - */ -typedef struct biginteger { - CK_BYTE *big_value; - CK_ULONG big_value_len; -} biginteger_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _PKTOOL_BIGINTEGER_H */ diff --git a/usr/src/cmd/cmd-crypto/pktool/common.c b/usr/src/cmd/cmd-crypto/pktool/common.c index 030f8c158a..660afe2d57 100644 --- a/usr/src/cmd/cmd-crypto/pktool/common.c +++ b/usr/src/cmd/cmd-crypto/pktool/common.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,19 +37,19 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <tzfile.h> #include <cryptoutil.h> #include <security/cryptoki.h> -#include "common.h" -#include "biginteger.h" +#include <kmfapi.h> -/* True and false for attribute templates. */ -CK_BBOOL pk_true = B_TRUE; -CK_BBOOL pk_false = B_FALSE; +#include "common.h" /* Local status variables. */ static boolean_t initialized = B_FALSE; static boolean_t session_opened = B_FALSE; -static boolean_t session_writable = B_FALSE; static boolean_t logged_in = B_FALSE; /* Supporting structures and global variables for getopt_av(). */ @@ -67,6 +66,9 @@ static int _save_numopts = 0; int optind_av = 1; char *optarg_av = NULL; +static void close_sess(CK_SESSION_HANDLE); +static void logout_token(CK_SESSION_HANDLE); + /* * Perform PKCS#11 setup here. Currently only C_Initialize is required, * along with setting/resetting state variables. @@ -76,19 +78,15 @@ init_pk11(void) { CK_RV rv = CKR_OK; - cryptodebug("inside init_pk11"); - /* If C_Initialize() already called, nothing to do here. */ if (initialized == B_TRUE) return (CKR_OK); /* Reset state variables because C_Initialize() not yet done. */ session_opened = B_FALSE; - session_writable = B_FALSE; logged_in = B_FALSE; /* Initialize PKCS#11 library. */ - cryptodebug("calling C_Initialize()"); if ((rv = C_Initialize(NULL_PTR)) != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { return (rv); @@ -105,7 +103,6 @@ init_pk11(void) void final_pk11(CK_SESSION_HANDLE sess) { - cryptodebug("inside final_pk11"); /* If the library wasn't initialized, nothing to do here. */ if (!initialized) @@ -114,127 +111,41 @@ final_pk11(CK_SESSION_HANDLE sess) /* Make sure the sesion is closed first. */ close_sess(sess); - cryptodebug("calling C_Finalize()"); (void) C_Finalize(NULL); initialized = B_FALSE; } /* - * Create a PKCS#11 session on the given slot, and set state information. - * If session is already open, check that the read-only/read-write state - * requested matches that of the session. If it doesn't, make it so. - */ -CK_RV -open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess) -{ - CK_RV rv = CKR_OK; - - cryptodebug("inside open_sess"); - - /* If the session is already open, check the session flags. */ - if (session_opened) { - /* - * If requesting R/W session and it is currently R/O, - * need to close the session and reopen it R/W. The - * other cases are considered acceptable: - * sess_flags current state - * ---------- ------------- - * ~CKF_RW_SESSION !session_writable - * ~CKF_RW_SESSION session_writable - * CKF_RW_SESSION session_writable - */ - if ((sess_flags & CKF_RW_SESSION) && !session_writable) - close_sess(*sess); - else - return (CKR_OK); - } - - /* Make sure the PKCS#11 is already initialized. */ - if (!initialized) - if ((rv = init_pk11()) != CKR_OK) - return (rv); - - /* Create a session for subsequent operations. */ - cryptodebug("calling C_OpenSession()"); - if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags, - NULL, NULL, sess)) != CKR_OK) - return (rv); - session_opened = B_TRUE; - session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE; - return (CKR_OK); -} - -/* * Close PKCS#11 session and reset state variables. Any logins are * logged out. */ -void +static void close_sess(CK_SESSION_HANDLE sess) { - cryptodebug("inside close_sess"); if (sess == NULL) { - cryptodebug("session handle is null"); return; } /* If session is already closed, nothing to do here. */ - session_writable = B_FALSE; if (!session_opened) return; /* Make sure user is logged out of token. */ logout_token(sess); - cryptodebug("calling C_CloseSession()"); (void) C_CloseSession(sess); session_opened = B_FALSE; } /* - * Log user into token in given slot. If this first login ever for this - * token, the initial PIN is "changeme", C_Login() will succeed, but all - * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED. - */ -CK_RV -login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, - CK_SESSION_HANDLE_PTR sess) -{ - CK_RV rv = CKR_OK; - - cryptodebug("inside login_token"); - - /* If already logged in, nothing to do here. */ - if (logged_in) - return (CKR_OK); - - /* Make sure we have a session first, assume R/O is enough. */ - if (!session_opened) - if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) != - CKR_OK) - return (rv); - - /* Log the user into the token. */ - cryptodebug("calling C_Login()"); - if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) { - cryptodebug("C_Login returns %s", pkcs11_strerror(rv)); - return (rv); - } - - logged_in = B_TRUE; - return (CKR_OK); -} - -/* * Log user out of token and reset status variable. */ -void +static void logout_token(CK_SESSION_HANDLE sess) { - cryptodebug("inside logout_token"); if (sess == NULL) { - cryptodebug("session handle is null"); return; } @@ -242,49 +153,11 @@ logout_token(CK_SESSION_HANDLE sess) if (!logged_in) return; - cryptodebug("calling C_Logout()"); (void) C_Logout(sess); logged_in = B_FALSE; } /* - * Shortcut function to get from an uninitialized state to user logged in. - * If the library is already initialized, the session is already opened, - * or the user is already logged in, those steps are skipped and the next - * step is checked. - */ -CK_RV -quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, - CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess) -{ - CK_RV rv = CKR_OK; - - cryptodebug("inside quick_start"); - - /* Call open_sess() explicitly if R/W session is needed. */ - if (sess_flags & CKF_RW_SESSION) - if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK) - return (rv); - - if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK) - return (rv); - - return (CKR_OK); -} - -/* - * Shortcut function to go from any state to uninitialized PKCS#11 library. - */ -void -quick_finish(CK_SESSION_HANDLE sess) -{ - cryptodebug("inside quick_finish"); - - /* All the needed calls are done implicitly. */ - final_pk11(sess); -} - -/* * Gets PIN from user. Caller needs to free the returned PIN when done. * If two prompts are given, the PIN is confirmed with second prompt. * Note that getphassphrase() may return data in static memory area. @@ -294,15 +167,20 @@ get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) { char *save_phrase, *phrase1, *phrase2; - cryptodebug("inside get_pin"); + +#ifdef DEBUG + if (getenv("TOKENPIN") != NULL) { + *pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN")); + *pinlen = strlen((char *)(*pin)); + return (CKR_OK); + } +#endif /* DEBUG */ /* Prompt user for a PIN. */ if (prompt1 == NULL) { - cryptodebug("no passphrase prompt given"); return (CKR_ARGUMENTS_BAD); } if ((phrase1 = getpassphrase(prompt1)) == NULL) { - cryptodebug("getpassphrase() failed"); return (CKR_FUNCTION_FAILED); } @@ -313,12 +191,10 @@ get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen) /* If second prompt given, PIN confirmation is requested. */ if (prompt2 != NULL) { if ((phrase2 = getpassphrase(prompt2)) == NULL) { - cryptodebug("getpassphrase() confirmation failed"); free(save_phrase); return (CKR_FUNCTION_FAILED); } if (strcmp(save_phrase, phrase2) != 0) { - cryptodebug("passphrases do not match"); free(save_phrase); return (CKR_PIN_INCORRECT); } @@ -343,7 +219,13 @@ yesno(char *prompt, char *invalid, boolean_t dflt) char *yes = gettext("yes"); char *no = gettext("no"); - cryptodebug("inside yesno"); + +#ifdef DEBUG + /* If debugging or testing, return TRUE and avoid prompting */ + if (getenv("TOKENPIN") != NULL) { + return (B_TRUE); + } +#endif /* DEBUG */ if (prompt == NULL) prompt = gettext("Enter (y)es or (n)o? "); @@ -388,8 +270,6 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; int rv = CKR_OK; - cryptodebug("inside get_token_slots"); - if (!initialized) if ((rv = init_pk11()) != CKR_OK) return (rv); @@ -402,12 +282,10 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) * Also select only those slots that have tokens in them, * because this tool has no need to know about empty slots. */ - cryptodebug("calling C_GetSlotList() for slot count"); if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK) return (rv); if (tmp_count == 0) { - cryptodebug("no slots with tokens found"); *slot_list = NULL_PTR; *slot_count = 0; return (CKR_OK); @@ -420,7 +298,6 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) /* Then get the slot list itself. */ for (;;) { - cryptodebug("calling C_GetSlotList()"); if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) { *slot_list = tmp_list; *slot_count = tmp_count; @@ -433,7 +310,6 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) } /* If the number of slots grew, try again. */ - cryptodebug("number of tokens present increased"); if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, tmp_count * sizeof (CK_SLOT_ID))) == NULL) { free(tmp_list); @@ -447,878 +323,683 @@ get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count) } /* - * memcmp_pad_max() is a specialized version of memcmp() which - * compares two pieces of data up to a maximum length. If the - * the two data match up the maximum length, they are considered - * matching. Trailing blanks do not cause the match to fail if - * one of the data is shorted. - * - * Examples of matches: - * "one" | - * "one " | - * ^maximum length - * - * "Number One | X" (X is beyond maximum length) - * "Number One " | - * ^maximum length - * - * Examples of mismatches: - * " one" - * "one" - * - * "Number One X|" - * "Number One |" - * ^maximum length + * Breaks out the getopt-style option string into a structure that can be + * traversed later for calls to getopt_av(). Option string is NOT altered, + * but the struct fields point to locations within option string. */ static int -memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz) +populate_opts(char *optstring) { - uint_t len, extra_len; + int i; + av_opts *temp; char *marker; - /* No point in comparing anything beyond max_sz */ - if (d1_len > max_sz) - d1_len = max_sz; - if (d2_len > max_sz) - d2_len = max_sz; - - /* Find shorter of the two data. */ - if (d1_len <= d2_len) { - len = d1_len; - extra_len = d2_len; - marker = d2; - } else { /* d1_len > d2_len */ - len = d2_len; - extra_len = d1_len; - marker = d1; - } + if (optstring == NULL || *optstring == '\0') + return (0); + + /* + * This tries to imitate getopt(3c) Each option must conform to: + * <short name char> [ ':' ] [ '(' <long name string> ')' ] + * If long name is missing, the short name is used for long name. + */ + for (i = 0; *optstring != '\0'; i++) { + if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : + realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { + if (opts_av != NULL) + free(opts_av); + opts_av = NULL; + return (0); + } else { + opts_av = (av_opts *)temp; + } - /* Have a match in the shortest length of data? */ - if (memcmp(d1, d2, len) != 0) - /* CONSTCOND */ - return (!0); + (void) memset(&opts_av[i], 0, sizeof (av_opts)); + marker = optstring; /* may need optstring later */ - /* If the rest of longer data is nulls or blanks, call it a match. */ - while (len < extra_len) - if (!isspace(marker[len++])) - /* CONSTCOND */ - return (!0); - return (0); + opts_av[i].shortnm = *marker++; /* set short name */ + + if (*marker == ':') { /* check for opt arg */ + marker++; + opts_av[i].has_arg = B_TRUE; + } + + if (*marker == '(') { /* check and set long name */ + marker++; + opts_av[i].longnm = marker; + opts_av[i].longnm_len = strcspn(marker, ")"); + optstring = marker + opts_av[i].longnm_len + 1; + } else { + /* use short name option character */ + opts_av[i].longnm = optstring; + opts_av[i].longnm_len = 1; + optstring = marker; + } + } + + return (i); } /* - * Locate a token slot whose token matches the label, manufacturer ID, and - * serial number given. Token label must be specified, manufacturer ID and - * serial number are optional. When the token is located, the PIN state - * is also returned to determine if it still has the default PIN. + * getopt_av() is very similar to getopt(3c) in that the takes an option + * string, compares command line arguments for matches, and returns a single + * letter option when a match is found. However, getopt_av() differs from + * getopt(3c) by requiring that only longname options and values be found + * on the command line and all leading dashes are omitted. In other words, + * it tries to enforce only longname "option=value" arguments on the command + * line. Boolean options are not allowed either. */ -CK_RV -find_token_slot(char *token_name, char *manuf_id, char *serial_no, - CK_SLOT_ID *slot_id, CK_FLAGS *pin_state) +int +getopt_av(int argc, char * const *argv, const char *optstring) { - CK_SLOT_ID_PTR slot_list; - CK_TOKEN_INFO token_info; - CK_ULONG slot_count = 0; - int rv = CKR_OK; - int i; - uint_t len, max_sz; - boolean_t tok_match = B_FALSE, - man_match = B_FALSE, - ser_match = B_FALSE; + int i; + int len; + char *cur_option; - cryptodebug("inside find_token_slot"); + if (optind_av >= argc) + return (EOF); - if (token_name == NULL) - return (CKR_ARGUMENTS_BAD); + /* First time or when optstring changes from previous one */ + if (_save_optstr != optstring) { + if (opts_av != NULL) + free(opts_av); + opts_av = NULL; + _save_optstr = optstring; + _save_numopts = populate_opts((char *)optstring); + } - /* Get a list of all slots with tokens present. */ - if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK) - return (rv); + for (i = 0; i < _save_numopts; i++) { + cur_option = argv[optind_av]; - /* If there are no such slots, the desired token won't be found. */ - if (slot_count == 0) - return (CKR_TOKEN_NOT_PRESENT); - - /* Search the slot list for the token. */ - for (i = 0; i < slot_count; i++) { - cryptodebug("calling C_GetTokenInfo()"); - if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) != - CKR_OK) { - cryptodebug("token in slot %d returns %s", i, - pkcs11_strerror(rv)); - continue; + if (strcmp(cur_option, "--") == 0) { + optind_av++; + break; } - /* See if the token label matches. */ - len = strlen(token_name); - max_sz = sizeof (token_info.label); - if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len, - max_sz) == 0) - tok_match = B_TRUE; - - /* - * If manufacturer id was given, see if it actually matches. - * If no manufacturer id was given, assume match is true. - */ - if (manuf_id) { - len = strlen(manuf_id); - max_sz = sizeof ((char *)(token_info.manufacturerID)); - if (memcmp_pad_max(&(token_info.manufacturerID), max_sz, - manuf_id, len, max_sz) == 0) - man_match = B_TRUE; - } else - man_match = B_TRUE; - - /* - * If serial number was given, see if it actually matches. - * If no serial number was given, assume match is true. - */ - if (serial_no) { - len = strlen(serial_no); - max_sz = sizeof ((char *)(token_info.serialNumber)); - if (memcmp_pad_max(&(token_info.serialNumber), max_sz, - serial_no, len, max_sz) == 0) - ser_match = B_TRUE; - } else - ser_match = B_TRUE; - - cryptodebug("slot %d:", i); - cryptodebug("\tlabel = \"%.32s\"%s", token_info.label, - tok_match ? " match" : ""); - cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID, - man_match ? " match" : ""); - cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber, - ser_match ? " match" : ""); - cryptodebug("\tmodel = \"%.16s\"", token_info.model); - - cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s", - (token_info.flags & CKF_USER_PIN_INITIALIZED) ? - "true" : "false"); - cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s", - (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? - "true" : "false"); - - if (tok_match && man_match && ser_match) - break; /* found it! */ - } + if (cur_option[0] == '-' && strlen(cur_option) == 2) { + len = 1; + cur_option++; /* remove "-" */ + } else { + len = strcspn(cur_option, "="); + } - /* Scanned the whole list without finding the token. */ - if (i == slot_count) { - cryptodebug("token not found"); - free(slot_list); - return (CKR_TOKEN_NOT_PRESENT); + if (len == opts_av[i].longnm_len && strncmp(cur_option, + opts_av[i].longnm, opts_av[i].longnm_len) == 0) { + /* matched */ + if (!opts_av[i].has_arg) { + optind_av++; + return (opts_av[i].shortnm); + } + + /* needs optarg */ + if (cur_option[len] == '=') { + optarg_av = &(cur_option[len+1]); + optind_av++; + return (opts_av[i].shortnm); + } + + optarg_av = NULL; + optind_av++; + return ((int)'?'); + } } - /* Return slot id where token was found and its PIN state. */ - cryptodebug("token found at slot %d", i); - *slot_id = slot_list[i]; - *pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED); - free(slot_list); - return (CKR_OK); + return (EOF); } -/* - * Returns pointer to either null-terminator or next unescaped colon. The - * string to be extracted starts at the beginning and goes until one character - * before this pointer. If NULL is returned, the string itself is NULL. - */ -static char * -find_unescaped_colon(char *str) +KMF_KEYSTORE_TYPE +KS2Int(char *keystore_str) { - char *end; + if (keystore_str == NULL) + return (0); + if (!strcasecmp(keystore_str, "pkcs11")) + return (KMF_KEYSTORE_PK11TOKEN); + else if (!strcasecmp(keystore_str, "nss")) + return (KMF_KEYSTORE_NSS); + else if (!strcasecmp(keystore_str, "file")) + return (KMF_KEYSTORE_OPENSSL); + else + return (0); +} - if (str == NULL) - return (NULL); - while ((end = strchr(str, ':')) != NULL) { - if (end != str && *(end-1) != '\\') - return (end); - str = end + 1; /* could point to null-terminator */ +int +Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg) +{ + if (algm == NULL) { + *sigAlg = KMF_ALGID_MD5WithRSA; + *ktype = KMF_RSA; + } else if (strcasecmp(algm, "DSA") == 0) { + *sigAlg = KMF_ALGID_SHA1WithDSA; + *ktype = KMF_DSA; + } else if (strcasecmp(algm, "RSA") == 0) { + *sigAlg = KMF_ALGID_MD5WithRSA; + *ktype = KMF_RSA; + } else { + return (-1); } - if (end == NULL) - end = strchr(str, '\0'); - return (end); + return (0); } -/* - * Compresses away any characters escaped with backslash from given string. - * The string is altered in-place. Example, "ab\:\\e" becomes "ab:\e". - */ -static void -unescape_str(char *str) +int +Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype) { - boolean_t escaped = B_FALSE; - char *mark; - - if (str == NULL) - return; + if (algm == NULL) + *ktype = KMF_AES; + else if (strcasecmp(algm, "aes") == 0) + *ktype = KMF_AES; + else if (strcasecmp(algm, "arcfour") == 0) + *ktype = KMF_RC4; + else if (strcasecmp(algm, "des") == 0) + *ktype = KMF_DES; + else if (strcasecmp(algm, "3des") == 0) + *ktype = KMF_DES3; + else + return (-1); - for (mark = str; *str != '\0'; str++) { - if (*str != '\\' || escaped == B_TRUE) { - *mark++ = *str; - escaped = B_FALSE; - } else { - escaped = B_TRUE; - } - } - *mark = '\0'; + return (0); } -/* - * Given a colon-separated token specifier, this functions splits it into - * its label, manufacturer ID (if any), and serial number (if any). Literal - * colons within the label/manuf/serial can be escaped with a backslash. - * Fields can left blank and trailing colons can be omitted, however leading - * colons are required as placeholders. For example, these are equivalent: - * (a) "lbl", "lbl:", "lbl::" (b) "lbl:man", "lbl:man:" - * but these are not: - * (c) "man", ":man" (d) "ser", "::ser" - * Furthermore, the token label is required always. - * - * The buffer containing the token specifier is altered by replacing the - * colons to null-terminators, and pointers returned are pointers into this - * string. No new memory is allocated. - */ int -parse_token_spec(char *token_spec, char **token_name, char **manuf_id, - char **serial_no) +Str2Lifetime(char *ltimestr, uint32_t *ltime) { - char *mark; + int num; + char timetok[6]; - if (token_spec == NULL || *token_spec == '\0') { - cryptodebug("token specifier is empty"); - return (-1); + if (ltimestr == NULL || !strlen(ltimestr)) { + /* default to 1 year lifetime */ + *ltime = SECSPERDAY * DAYSPERNYEAR; + return (0); } - *token_name = NULL; - *manuf_id = NULL; - *serial_no = NULL; - - /* Token label (required) */ - mark = find_unescaped_colon(token_spec); - *token_name = token_spec; - if (*mark != '\0') - *mark++ = '\0'; /* mark points to next field, if any */ - unescape_str(*token_name); + (void) memset(timetok, 0, sizeof (timetok)); + if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2) + return (-1); - if (*(*token_name) == '\0') { /* token label is required */ - cryptodebug("no token label found"); + if (!strcasecmp(timetok, "day") || + !strcasecmp(timetok, "days")) { + *ltime = num * SECSPERDAY; + } else if (!strcasecmp(timetok, "hour") || + !strcasecmp(timetok, "hours")) { + *ltime = num * SECSPERHOUR; + } else if (!strcasecmp(timetok, "year") || + !strcasecmp(timetok, "years")) { + *ltime = num * SECSPERDAY * DAYSPERNYEAR; + } else { + *ltime = 0; return (-1); } - if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */ - return (0); - token_spec = mark; - - /* Manufacturer identifier (optional) */ - mark = find_unescaped_colon(token_spec); - *manuf_id = token_spec; - if (*mark != '\0') - *mark++ = '\0'; /* mark points to next field, if any */ - unescape_str(*manuf_id); + return (0); +} - if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */ - return (0); - token_spec = mark; +int +OT2Int(char *objclass) +{ + char *c = NULL; + int retval = 0; - /* Serial number (optional) */ - mark = find_unescaped_colon(token_spec); - *serial_no = token_spec; - if (*mark != '\0') - *mark++ = '\0'; /* null-terminate, just in case */ - unescape_str(*serial_no); + if (objclass == NULL) + return (-1); - return (0); + c = strchr(objclass, ':'); + if (c != NULL) { + if (!strcasecmp(c, ":private")) + retval = PK_PRIVATE_OBJ; + else if (!strcasecmp(c, ":public")) + retval = PK_PUBLIC_OBJ; + else if (!strcasecmp(c, ":both")) + retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ; + else /* unrecognized option */ + return (-1); + + *c = '\0'; + } + + if (!strcasecmp(objclass, "public")) { + if (retval) + return (-1); + return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | + PK_PUBKEY_OBJ); + } else if (!strcasecmp(objclass, "private")) { + if (retval) + return (-1); + return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ); + } else if (!strcasecmp(objclass, "both")) { + if (retval) + return (-1); + return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ); + } else if (!strcasecmp(objclass, "cert")) { + return (retval | PK_CERT_OBJ); + } else if (!strcasecmp(objclass, "key")) { + if (retval == 0) /* return all keys */ + return (retval | PK_KEY_OBJ); + else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ)) + /* return all keys */ + return (retval | PK_KEY_OBJ); + else if (retval & PK_PUBLIC_OBJ) + /* Only return public keys */ + return (retval | PK_PUBKEY_OBJ); + else if (retval & PK_PRIVATE_OBJ) + /* Only return private keys */ + return (retval | PK_PRIKEY_OBJ); + } else if (!strcasecmp(objclass, "crl")) { + if (retval) + return (-1); + return (retval | PK_CRL_OBJ); + } + + if (retval == 0) /* No matches found */ + retval = -1; + return (retval); } -/* - * Constructs a fully qualified token name from its label, manufacturer ID - * (if any), and its serial number (if any). Note that the given buf must - * be big enough. Do NOT i18n/l10n. - * - * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified - * token name adds up this way: - * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul) - */ -void -full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf) +KMF_ENCODE_FORMAT +Str2Format(char *formstr) { - char *marker = buf; - int n_written = 0; - int space_left = FULL_NAME_LEN; + if (formstr == NULL || !strcasecmp(formstr, "der")) + return (KMF_FORMAT_ASN1); + if (!strcasecmp(formstr, "pem")) + return (KMF_FORMAT_PEM); + if (!strcasecmp(formstr, "pkcs12")) + return (KMF_FORMAT_PKCS12); + + return (KMF_FORMAT_UNDEF); +} - if (!token_name) - return; - n_written = sprintf(buf, "\"%.32s\"", token_name); - marker += n_written; - space_left -= n_written; +KMF_RETURN +select_token(void *kmfhandle, char *token, + int readonly) +{ + KMF_RETURN rv = KMF_OK; + KMF_CONFIG_PARAMS config; - n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : ""); - marker += n_written; - space_left -= n_written; + if (token == NULL) + return (KMF_ERR_BAD_PARAMETER); - n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : ""); - marker += n_written; - space_left -= n_written; + (void) memset(&config, 0, sizeof (config)); + config.kstype = KMF_KEYSTORE_PK11TOKEN; + config.pkcs11config.label = token; + config.pkcs11config.readonly = readonly; - /* space_left should always be >= 1 */ + rv = KMF_ConfigureKeystore(kmfhandle, &config); + if (rv == KMF_ERR_TOKEN_SELECTED) + rv = KMF_OK; + return (rv); } -/* - * Find how many token objects with the given label. - */ -CK_RV -find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, - CK_ULONG *count) + +KMF_RETURN +configure_nss(void *kmfhandle, char *dir, char *prefix) { - CK_RV rv = CKR_OK; - CK_ATTRIBUTE attrs[4] = { - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { 0, NULL, 0 }, - { 0, NULL, 0 }, - { 0, NULL, 0 } - }; - CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); - CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ - CK_OBJECT_CLASS obj_class; - CK_OBJECT_HANDLE tmp_obj; - CK_ULONG obj_count = 0; - - cryptodebug("inside find_obj_count"); - - if (!session_opened || sess == NULL) { - cryptodebug("session handle is null"); - return (CKR_SESSION_HANDLE_INVALID); - } + KMF_RETURN rv = KMF_OK; + KMF_CONFIG_PARAMS config; - if (label) { - cryptodebug("object label was specified"); - attrs[cur_attr].type = CKA_LABEL; - attrs[cur_attr].pValue = label; - attrs[cur_attr].ulValueLen = strlen((char *)label); - cur_attr++; - } + (void) memset(&config, 0, sizeof (config)); + config.kstype = KMF_KEYSTORE_NSS; + config.nssconfig.configdir = dir; + config.nssconfig.certPrefix = prefix; + config.nssconfig.keyPrefix = prefix; + config.nssconfig.secModName = NULL; - if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { - cryptodebug("only searching for private objects"); - attrs[cur_attr].type = CKA_PRIVATE; - attrs[cur_attr].pValue = &pk_true; - attrs[cur_attr].ulValueLen = sizeof (pk_true); - cur_attr++; - } + rv = KMF_ConfigureKeystore(kmfhandle, &config); + if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED) + rv = KMF_OK; - /* - * If "certs and all keys" is not specified, but at least either - * "certs" or some "keys" is specified, then go into this block. - * If all certs and keys were specified, there's no point in - * putting that fact in the attribute template -- leave that open, - * and all certs and keys will be matched automatically. - * In other words, only if at least one of 0x10,0x20,0x40,0x80 - * bits is off, go into this code block. - * - * NOTE: For now, only one of cert or key types is allowed. - * This needs to change in the future. - */ - if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && - ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { - if (obj_type & PK_CERT_OBJ) { - cryptodebug("only searching for certificates"); - obj_class = CKO_CERTIFICATE; - } else if (obj_type & PK_PRIKEY_OBJ) { - cryptodebug("only searching for private keys"); - obj_class = CKO_PRIVATE_KEY; - } else if (obj_type & PK_PUBKEY_OBJ) { - cryptodebug("only searching for public keys"); - obj_class = CKO_PUBLIC_KEY; - } else if (obj_type & PK_SECKEY_OBJ) { - cryptodebug("only searching for secret keys"); - obj_class = CKO_SECRET_KEY; - } + return (rv); +} - attrs[cur_attr].type = CKA_CLASS; - attrs[cur_attr].pValue = &obj_class; - attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); - cur_attr++; - } + +KMF_RETURN +get_pk12_password(KMF_CREDENTIAL *cred) +{ + KMF_RETURN rv = KMF_OK; + char prompt[1024]; /* - * This can't happen now. When finding objects is enhanced in the - * future. this could lead to buffer overruns. + * Get the password to use for the PK12 encryption. */ - if (cur_attr > num_attrs) - cryptodebug("internal error: attr template overrun"); + (void) strlcpy(prompt, + gettext("Enter password to use for " + "accessing the PKCS12 file: "), + sizeof (prompt)); - cryptodebug("calling C_FindObjectsInit"); - if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) - return (rv); - - /* Look for the object, checking if there are more than one. */ - cryptodebug("calling C_FindObjects"); - for (*count = 0; /* empty */; (*count)++) { - if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != - CKR_OK) - break; - - /* No more found. */ - if (obj_count == 0) - break; + if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, + (ulong_t *)&cred->credlen) != CKR_OK) { + cred->cred = NULL; + cred->credlen = 0; } - cryptodebug("%d matching objects found", *count); - - cryptodebug("calling C_FindObjectsFinal"); - (void) C_FindObjectsFinal(sess); return (rv); } -/* - * Find the token object with the given label. - */ -CK_RV -find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label, - CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count) -{ - CK_RV rv = CKR_OK; - CK_ATTRIBUTE attrs[4] = { - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { 0, NULL, 0 }, - { 0, NULL, 0 }, - { 0, NULL, 0 } - }; - CK_ULONG num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); - CK_ULONG cur_attr = 1; /* CKA_TOKEN already set */ - CK_OBJECT_CLASS obj_class; - CK_OBJECT_HANDLE tmp_obj; - CK_ULONG obj_count = 0; - int i; - - cryptodebug("inside find_obj"); - - if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK) - return (rv); - if (*count == 0) - return (CKR_OK); +#define COUNTRY_PROMPT "Country Name (2 letter code) [US]:" +#define STATE_PROMPT "State or Province Name (full name) [Some-State]:" +#define LOCALITY_PROMPT "Locality Name (eg, city) []:" +#define ORG_PROMPT "Organization Name (eg, company) []:" +#define UNIT_PROMPT "Organizational Unit Name (eg, section) []:" +#define NAME_PROMPT "Common Name (eg, YOUR name) []:" +#define EMAIL_PROMPT "Email Address []:" - if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) * - sizeof (CK_OBJECT_HANDLE))) == NULL) { - cryptodebug("no memory for found object"); - return (CKR_HOST_MEMORY); - } +#define COUNTRY_DEFAULT "US" +#define STATE_DEFAULT "Some-State" +#define INVALID_INPUT "Invalid input; please re-enter ..." - if (label) { - cryptodebug("object label was specified"); - attrs[cur_attr].type = CKA_LABEL; - attrs[cur_attr].pValue = label; - attrs[cur_attr].ulValueLen = strlen((char *)label); - cur_attr++; - } +#define SUBNAMESIZ 1024 +#define RDN_MIN 1 +#define RDN_MAX 64 +#define COUNTRYNAME_MIN 2 +#define COUNTRYNAME_MAX 2 - if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) { - cryptodebug("only searching for private objects"); - attrs[cur_attr].type = CKA_PRIVATE; - attrs[cur_attr].pValue = &pk_true; - attrs[cur_attr].ulValueLen = sizeof (pk_true); - cur_attr++; - } +static char * +get_input_string(char *prompt, char *default_str, int min_len, int max_len) +{ + char buf[1024]; + char *response = NULL; + char *ret = NULL; + int len; - /* - * If "certs and all keys" is not specified, but at least either - * "certs" or some "keys" is specified, then go into this block. - * If all certs and keys were specified, there's no point in - * putting that fact in the attribute template -- leave that open, - * and all certs and keys will be matched automatically. - * In other words, only if at least one of 0x10,0x20,0x40,0x80 - * bits is off, go into this code block. - * - * NOTE: For now, only one of cert or key types is allowed. - * This needs to change in the future. - */ - if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) && - ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) { - if (obj_type & PK_CERT_OBJ) { - cryptodebug("only searching for certificates"); - obj_class = CKO_CERTIFICATE; - } else if (obj_type & PK_PRIKEY_OBJ) { - cryptodebug("only searching for private keys"); - obj_class = CKO_PRIVATE_KEY; - } else if (obj_type & PK_PUBKEY_OBJ) { - cryptodebug("only searching for public keys"); - obj_class = CKO_PUBLIC_KEY; - } else if (obj_type & PK_SECKEY_OBJ) { - cryptodebug("only searching for secret keys"); - obj_class = CKO_SECRET_KEY; + for (;;) { + (void) printf("\t%s", prompt); + (void) fflush(stdout); + + response = fgets(buf, sizeof (buf), stdin); + if (response == NULL) { + if (default_str != NULL) { + ret = strdup(default_str); + } + break; + } + + /* Skip any leading white space. */ + while (isspace(*response)) + response++; + if (*response == '\0') { + if (default_str != NULL) { + ret = strdup(default_str); + } + break; + } + + len = strlen(response); + response[len-1] = '\0'; /* get rid of "LF" */ + len--; + if (len >= min_len && len <= max_len) { + ret = strdup(response); + break; } - attrs[cur_attr].type = CKA_CLASS; - attrs[cur_attr].pValue = &obj_class; - attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS); - cur_attr++; + (void) printf("%s\n", INVALID_INPUT); + } - /* - * This can't happen now. When finding objects is enhanced in the - * future. this could lead to buffer overruns. - */ - if (cur_attr > num_attrs) - cryptodebug("internal error: attr template overrun"); + return (ret); +} - cryptodebug("calling C_FindObjectsInit"); - if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) { - free(*obj); - return (rv); +int +get_subname(char **result) +{ + char *country = NULL; + char *state = NULL; + char *locality = NULL; + char *org = NULL; + char *unit = NULL; + char *name = NULL; + char *email = NULL; + char *subname = NULL; + + (void) printf("Entering following fields for subject (a DN) ...\n"); + country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT, + COUNTRYNAME_MIN, COUNTRYNAME_MAX); + if (country == NULL) + return (-1); + + state = get_input_string(STATE_PROMPT, STATE_DEFAULT, + RDN_MIN, RDN_MAX); + if (state == NULL) { + goto out; } - /* - * Find all the matching objects. The loop goes 1 more beyond - * the number of objects found to determine if any new objects - * were created since the time the object count was done. - */ - cryptodebug("calling C_FindObjects"); - for (i = 0; i < (*count) + 1; i++) { - if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) != - CKR_OK) - break; + locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX); + org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX); + unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX); + name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX); + email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX); - /* No more found. */ - if (obj_count == 0) - break; + /* Now create a subject name from the input strings */ + if ((subname = malloc(SUBNAMESIZ)) == NULL) + goto out; + + (void) memset(subname, 0, SUBNAMESIZ); + (void) strlcpy(subname, "C=", SUBNAMESIZ); + (void) strlcat(subname, country, SUBNAMESIZ); + (void) strlcat(subname, ", ", SUBNAMESIZ); + (void) strlcat(subname, "ST=", SUBNAMESIZ); + (void) strlcat(subname, state, SUBNAMESIZ); - /* - * Save the object in the list being created, as long as - * we don't overrun the size of the list. - */ - if (i < *count) - (*obj)[i] = tmp_obj; - else - cryptodebug("number of objects changed since last count"); + if (locality) { + (void) strlcat(subname, ", ", SUBNAMESIZ); + (void) strlcat(subname, "L=", SUBNAMESIZ); + (void) strlcat(subname, locality, SUBNAMESIZ); } - if (rv != CKR_OK) { - free(*obj); - } else { - /* - * There are three cases to handle: (1) fewer objects were - * found than originally counted => change *count to the - * smaller number; (2) the number of objects found matches - * the number originally counted => do nothing; (3) more - * objects found than originally counted => list passed - * in is too small to contain the extra object(s), flag - * that in the debug output but don't change number of - * objects returned. The caller can double-check by - * calling find_obj_count() after this function to make - * sure the numbers match, if desired. - */ - /* Case 1: Fewer objects. */ - if (i < *count) { - cryptodebug("%d objects found, expected %d", i, *count); - *count = i; - /* Case 3: More objects. */ - } else if (i > *count) { - cryptodebug("at least %d objects found, expected %d", - i, *count); - } - /* - * Case 2: Same number of objects. - * - * else if (i == *count) - * ; - */ + if (org) { + (void) strlcat(subname, ", ", SUBNAMESIZ); + (void) strlcat(subname, "O=", SUBNAMESIZ); + (void) strlcat(subname, org, SUBNAMESIZ); } - cryptodebug("calling C_FindObjectsFinal"); - (void) C_FindObjectsFinal(sess); - return (rv); -} + if (unit) { + (void) strlcat(subname, ", ", SUBNAMESIZ); + (void) strlcat(subname, "OU=", SUBNAMESIZ); + (void) strlcat(subname, unit, SUBNAMESIZ); + } -char * -class_str(CK_OBJECT_CLASS class) -{ - switch (class) { - case CKO_DATA: return (gettext("data")); - case CKO_CERTIFICATE: return (gettext("certificate")); - case CKO_PUBLIC_KEY: return (gettext("public key")); - case CKO_PRIVATE_KEY: return (gettext("private key")); - case CKO_SECRET_KEY: return (gettext("secret key")); - case CKO_DOMAIN_PARAMETERS: return (gettext("domain parameter")); - default: return (gettext("unknown object")); + if (name) { + (void) strlcat(subname, ", ", SUBNAMESIZ); + (void) strlcat(subname, "CN=", SUBNAMESIZ); + (void) strlcat(subname, name, SUBNAMESIZ); } -} -char * -keytype_str(CK_KEY_TYPE keytype) -{ - switch (keytype) { - case CKK_RSA: return (gettext("RSA")); - case CKK_DSA: return (gettext("DSA")); - case CKK_DH: return (gettext("Diffie-Hellman")); - case CKK_X9_42_DH: return (gettext("X9.42 Diffie-Hellman")); - case CKK_GENERIC_SECRET: return (gettext("generic")); - case CKK_RC2: return (gettext("RC2")); - case CKK_RC4: return (gettext("RC4")); - case CKK_DES: return (gettext("DES")); - case CKK_DES2: return (gettext("Double-DES")); - case CKK_DES3: return (gettext("Triple-DES")); - case CKK_RC5: return (gettext("RC5")); - case CKK_AES: return (gettext("AES")); - default: return (gettext("typeless")); + if (email) { + (void) strlcat(subname, ", ", SUBNAMESIZ); + (void) strlcat(subname, "E=", SUBNAMESIZ); + (void) strlcat(subname, email, SUBNAMESIZ); } -} -char * -attr_str(CK_ATTRIBUTE_TYPE attrtype) -{ - switch (attrtype) { - case CKA_PRIVATE: return (gettext("private")); - case CKA_LOCAL: return (gettext("local")); - case CKA_SENSITIVE: return (gettext("sensitive")); - case CKA_EXTRACTABLE: return (gettext("extractable")); - case CKA_ENCRYPT: return (gettext("encrypt")); - case CKA_DECRYPT: return (gettext("decrypt")); - case CKA_WRAP: return (gettext("wrap")); - case CKA_UNWRAP: return (gettext("unwrap")); - case CKA_SIGN: return (gettext("sign")); - case CKA_SIGN_RECOVER: return (gettext("sign-recover")); - case CKA_VERIFY: return (gettext("verify")); - case CKA_VERIFY_RECOVER: return (gettext("verify-recover")); - case CKA_DERIVE: return (gettext("derive")); - case CKA_ALWAYS_SENSITIVE: return (gettext("always sensitive")); - case CKA_NEVER_EXTRACTABLE: return (gettext("never extractable")); - default: return (gettext("unknown capability")); +out: + if (country) + free(country); + if (state) + free(state); + if (locality) + free(locality); + if (org) + free(org); + if (unit) + free(unit); + if (name) + free(name); + if (email) + free(email); + + if (subname == NULL) + return (-1); + else { + *result = subname; + return (0); } } /* - * Convert a byte string into a string of octets formatted like this: - * oo oo oo oo oo ... oo - * where each "oo" is an octet is space separated and in the form: - * [0-f][0-f] if the octet is a non-printable character - * <space><char> if the octet is a printable character - * - * Note: octets_sz must be 3 * str_sz + 1, or at least as long as "blank" + * Parse a string of KeyUsage values and convert + * them to the correct KU Bits. + * The field may be marked "critical" by prepending + * "critical:" to the list. + * EX: critical:digitialSignature,keyEncipherment */ -void -octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz, - boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent, - char *blank) +KMF_RETURN +verify_keyusage(char *kustr, uint16_t *kubits, int *critical) { - char *marker; - int nc; - int newline; - int indent_len; - boolean_t first = B_TRUE; - - cryptodebug("inside octetify"); - - cryptodebug(stop_on_nul ? "stopping on first nul found" : - "continuing to full length of buffer"); - cryptodebug(do_ascii ? "using ascii chars where printable" : - "using only hex octets"); - cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent); - cryptodebug("return \"%s\" if buffer is null or empty", blank); - - /* If string is empty, write as much of the blank string and leave. */ - if (str_sz == 0) { - (void) snprintf(octets, octets_sz, "%s", blank); - return; + KMF_RETURN ret = KMF_OK; + uint16_t kuval; + char *k; + + *kubits = 0; + if (kustr == NULL || !strlen(kustr)) + return (KMF_ERR_BAD_PARAMETER); + + /* Check to see if this is critical */ + if (!strncasecmp(kustr, "critical:", strlen("critical:"))) { + *critical = TRUE; + kustr += strlen("critical:"); + } else { + *critical = FALSE; } - /* If only limit or indent is set, pick default for the other. */ - if (limit > 0 && indent == NULL) - indent = "\n"; - if (indent != NULL && limit == 0) - limit = 60; - indent_len = strlen(indent); - - for (marker = octets, newline = 0, first = B_TRUE; - (stop_on_nul && *str != '\0') || - (!stop_on_nul && str_sz > 0 && octets_sz > 0); - str++, str_sz--, marker += nc, octets_sz -= nc) { - if (!first) { - if (limit > 0 && ((marker - octets) / limit) > - newline) { - nc = snprintf(marker, indent_len, "%s", indent); - newline++; - continue; - } - nc = sprintf(marker, - ((do_ascii && isprint(*str) && !isspace(*str)) ? - "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str); - } else { - nc = sprintf(marker, - ((do_ascii && isprint(*str) && !isspace(*str)) ? - "%c" : "%02x"), *str); - first = B_FALSE; + k = strtok(kustr, ","); + while (k != NULL) { + kuval = KMF_StringToKeyUsage(k); + if (kuval == 0) { + *kubits = 0; + return (KMF_ERR_BAD_PARAMETER); } + *kubits |= kuval; + k = strtok(NULL, ","); } - *marker = '\0'; -} -/* - * Copies a biginteger_t to a template attribute. - * Should be a macro instead of a function. - */ -void -copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr) -{ - attr->pValue = big.big_value; - attr->ulValueLen = big.big_value_len; + return (ret); } /* - * Copies a string and its length to a template attribute. - * Should be a macro instead of a function. + * Verify the alternate subject label is real or invalid. + * + * The field may be marked "critical" by prepending + * "critical:" to the list. + * EX: "critical:IP=1.2.3.4" */ -void -copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr) +KMF_RETURN +verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical) { - attr->pValue = buf; - attr->ulValueLen = buflen; -} + char *p; + KMF_RETURN rv = KMF_OK; -/* - * Copies a template attribute to a biginteger_t. - * Should be a macro instead of a function. - */ -void -copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big) -{ - big->big_value = attr->pValue; - big->big_value_len = attr->ulValueLen; -} + /* Check to see if this is critical */ + if (!strncasecmp(arg, "critical:", strlen("critical:"))) { + *critical = TRUE; + arg += strlen("critical:"); + } else { + *critical = FALSE; + } -/* - * Copies a template attribute to a string and its length. - * Should be a macro instead of a function. - */ -void -copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen) -{ - *buf = attr->pValue; - *buflen = attr->ulValueLen; -} + /* Make sure there is an "=" sign */ + p = strchr(arg, '='); + if (p == NULL) + return (KMF_ERR_BAD_PARAMETER); -/* - * Copies a template attribute to a date and its length. - * Should be a macro instead of a function. - */ -void -copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen) -{ - *buf = (CK_DATE *)attr->pValue; - *buflen = attr->ulValueLen; + p[0] = '\0'; + + if (strcmp(arg, "IP") == 0) + *type = GENNAME_IPADDRESS; + else if (strcmp(arg, "DNS") == 0) + *type = GENNAME_DNSNAME; + else if (strcmp(arg, "EMAIL") == 0) + *type = GENNAME_RFC822NAME; + else if (strcmp(arg, "URI") == 0) + *type = GENNAME_URI; + else if (strcmp(arg, "DN") == 0) + *type = GENNAME_DIRECTORYNAME; + else if (strcmp(arg, "RID") == 0) + *type = GENNAME_REGISTEREDID; + else + rv = KMF_ERR_BAD_PARAMETER; + + p[0] = '='; + + return (rv); } -/* - * Breaks out the getopt-style option string into a structure that can be - * traversed later for calls to getopt_av(). Option string is NOT altered, - * but the struct fields point to locations within option string. - */ -static int -populate_opts(char *optstring) +int +get_token_password(KMF_KEYSTORE_TYPE kstype, + char *token_spec, KMF_CREDENTIAL *cred) { - int i; - av_opts *temp; - char *marker; - - if (optstring == NULL || *optstring == '\0') - return (0); + char prompt[1024]; + char *p = NULL; + if (kstype == KMF_KEYSTORE_PK11TOKEN) { + p = strchr(token_spec, ':'); + if (p != NULL) + *p = 0; + } /* - * This tries to imitate getopt(3c) Each option must conform to: - * <short name char> [ ':' ] [ '(' <long name string> ')' ] - * If long name is missing, the short name is used for long name. + * Login to the token first. */ - for (i = 0; *optstring != '\0'; i++) { - if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) : - realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) { - free(opts_av); - opts_av = NULL; - return (0); - } else - opts_av = (av_opts *)temp; - - marker = optstring; /* may need optstring later */ - - opts_av[i].shortnm = *marker++; /* set short name */ - - if (*marker == ':') { /* check for opt arg */ - marker++; - opts_av[i].has_arg = B_TRUE; - } + (void) snprintf(prompt, sizeof (prompt), + gettext(DEFAULT_TOKEN_PROMPT), + token_spec); - if (*marker == '(') { /* check and set long name */ - marker++; - opts_av[i].longnm = marker; - opts_av[i].longnm_len = strcspn(marker, ")"); - optstring = marker + opts_av[i].longnm_len + 1; - } else { - /* use short name option character */ - opts_av[i].longnm = optstring; - opts_av[i].longnm_len = 1; - optstring = marker; - } + if (get_pin(prompt, NULL, (uchar_t **)&cred->cred, + (ulong_t *)&cred->credlen) != CKR_OK) { + cred->cred = NULL; + cred->credlen = 0; } - return (i); + if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL) + *p = ':'; + return (KMF_OK); } -/* - * getopt_av() is very similar to getopt(3c) in that the takes an option - * string, compares command line arguments for matches, and returns a single - * letter option when a match is found. However, getopt_av() differs from - * getopt(3c) by requiring that only longname options and values be found - * on the command line and all leading dashes are omitted. In other words, - * it tries to enforce only longname "option=value" arguments on the command - * line. Boolean options are not allowed either. - */ -int -getopt_av(int argc, char * const *argv, const char *optstring) +KMF_RETURN +verify_file(char *filename) { - int i; - int len; + KMF_RETURN ret = KMF_OK; + int fd; - if (optind_av >= argc) - return (EOF); + /* + * Attempt to open with the EXCL flag so that if + * it already exists, the open will fail. It will + * also fail if the file cannot be created due to + * permissions on the parent directory, or if the + * parent directory itself does not exist. + */ + fd = open(filename, O_CREAT | O_EXCL, 0600); + if (fd == -1) + return (KMF_ERR_OPEN_FILE); - /* First time or when optstring changes from previous one */ - if (_save_optstr != optstring) { - if (opts_av != NULL) - free(opts_av); - opts_av = NULL; - _save_optstr = optstring; - _save_numopts = populate_opts((char *)optstring); - } + /* If we were able to create it, delete it. */ + (void) close(fd); + (void) unlink(filename); - for (i = 0; i < _save_numopts; i++) { - if (strcmp(argv[optind_av], "--") == 0) { - optind_av++; - break; - } + return (ret); +} - len = strcspn(argv[optind_av], "="); +void +display_error(void *handle, KMF_RETURN errcode, char *prefix) +{ + KMF_RETURN rv1, rv2; + char *plugin_errmsg = NULL; + char *kmf_errmsg = NULL; - if (len == opts_av[i].longnm_len && strncmp(argv[optind_av], - opts_av[i].longnm, opts_av[i].longnm_len) == 0) { - /* matched */ - if (!opts_av[i].has_arg) { - optind_av++; - return (opts_av[i].shortnm); - } + rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg); + rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg); - /* needs optarg */ - if (argv[optind_av][len] == '=') { - optarg_av = &(argv[optind_av][len+1]); - optind_av++; - return (opts_av[i].shortnm); - } + cryptoerror(LOG_STDERR, "%s:", prefix); + if (rv1 == KMF_OK && plugin_errmsg) { + cryptoerror(LOG_STDERR, + gettext("keystore error: %s"), + plugin_errmsg); + KMF_FreeString(plugin_errmsg); + } - optarg_av = NULL; - optind_av++; - return ((int)'?'); - } + if (rv2 == KMF_OK && kmf_errmsg) { + cryptoerror(LOG_STDERR, + gettext("libkmf error: %s"), + kmf_errmsg); + KMF_FreeString(kmf_errmsg); } - return (EOF); + if (rv1 != KMF_OK && rv2 != KMF_OK) + cryptoerror(LOG_STDERR, gettext("<unknown error>\n")); + } diff --git a/usr/src/cmd/cmd-crypto/pktool/common.h b/usr/src/cmd/cmd-crypto/pktool/common.h index 30e2890b4b..e15cee3282 100644 --- a/usr/src/cmd/cmd-crypto/pktool/common.h +++ b/usr/src/cmd/cmd-crypto/pktool/common.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,14 +38,14 @@ extern "C" { #endif #include <cryptoutil.h> -#include <biginteger.h> /* I18N helpers. */ #include <libintl.h> #include <locale.h> +#include <errno.h> +#include <kmfapi.h> /* Defines used throughout */ -#define FULL_NAME_LEN 91 /* See full_token_name() for this number. */ /* Error codes */ #define PK_ERR_NONE 0 @@ -55,6 +54,7 @@ extern "C" { #define PK_ERR_PK11 3 #define PK_ERR_SYSTEM 4 #define PK_ERR_OPENSSL 5 +#define PK_ERR_NSS 6 /* Types of objects for searches. */ #define PK_PRIVATE_OBJ 0x0001 @@ -62,11 +62,18 @@ extern "C" { #define PK_CERT_OBJ 0x0010 #define PK_PRIKEY_OBJ 0x0020 #define PK_PUBKEY_OBJ 0x0040 -#define PK_SECKEY_OBJ 0x0080 +#define PK_SYMKEY_OBJ 0x0080 +#define PK_CRL_OBJ 0x0100 -#define PK_KEY_OBJ (PK_PRIKEY_OBJ|PK_PUBKEY_OBJ|PK_SECKEY_OBJ) -#define PK_ALL_OBJ (PK_PRIVATE_OBJ|PK_PUBLIC_OBJ|\ - PK_CERT_OBJ|PK_KEY_OBJ) +#define PK_KEY_OBJ (PK_PRIKEY_OBJ | PK_PUBKEY_OBJ | PK_SYMKEY_OBJ) +#define PK_ALL_OBJ (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ |\ + PK_CERT_OBJ| PK_CRL_OBJ | PK_KEY_OBJ) + +#define PK_DEFAULT_KEYTYPE "rsa" +#define PK_DEFAULT_KEYLENGTH 1024 +#define PK_DEFAULT_DIRECTORY "." +#define PK_DEFAULT_SERIALNUM 1 +#define PK_DEFAULT_PK11TOKEN SOFT_TOKEN_LABEL /* Constants for attribute templates. */ extern CK_BBOOL pk_false; @@ -77,18 +84,12 @@ extern CK_BBOOL pk_true; extern CK_RV init_pk11(void); extern void final_pk11(CK_SESSION_HANDLE sess); -extern CK_RV open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, - CK_SESSION_HANDLE_PTR sess); -extern void close_sess(CK_SESSION_HANDLE sess); - extern CK_RV login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess); -extern void logout_token(CK_SESSION_HANDLE sess); extern CK_RV quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess); -extern void quick_finish(CK_SESSION_HANDLE sess); extern CK_RV get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen); @@ -96,40 +97,35 @@ extern boolean_t yesno(char *prompt, char *invalid, boolean_t dflt); extern CK_RV get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count); -extern CK_RV find_token_slot(char *token_name, char *manuf_id, - char *serial_no, CK_SLOT_ID *slot_id, CK_FLAGS *pin_state); - -extern CK_RV find_obj_count(CK_SESSION_HANDLE sess, int obj_type, - CK_BYTE *label, CK_ULONG *count); -extern CK_RV find_objs(CK_SESSION_HANDLE sess, int obj_type, - CK_BYTE *label, CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count); - -extern int parse_token_spec(char *spec, char **label, char **manuf, - char **buf); -extern void full_token_name(char *token, char *manuf, char *serial, - char *buf); - -extern char *class_str(CK_OBJECT_CLASS class); -extern char *keytype_str(CK_KEY_TYPE keytype); -extern char *attr_str(CK_ATTRIBUTE_TYPE attrtype); - -extern void octetify(CK_BYTE *str, CK_ULONG str_sz, char *oct, int oct_sz, - boolean_t stop_on_nul, boolean_t do_ascii, int limit, - char *indent, char *blank); - -extern void copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr); -extern void copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, - CK_ATTRIBUTE_PTR attr); -extern void copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big); -extern void copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, - CK_ULONG *buflen); -extern void copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, - CK_ULONG *buflen); + +extern int get_subname(char **); extern int getopt_av(int argc, char * const argv[], const char *optstring); extern char *optarg_av; extern int optind_av; +int OT2Int(char *); +int PK2Int(char *); +KMF_KEYSTORE_TYPE KS2Int(char *); +int Str2KeyType(char *, KMF_KEY_ALG *, KMF_ALGORITHM_INDEX *); +int Str2SymKeyType(char *, KMF_KEY_ALG *); +int Str2Lifetime(char *, uint32_t *); +KMF_RETURN select_token(void *, char *, int); +KMF_RETURN configure_nss(void *, char *, char *); + +KMF_ENCODE_FORMAT Str2Format(char *); +KMF_RETURN get_pk12_password(KMF_CREDENTIAL *); +KMF_RETURN hexstring2bytes(uchar_t *, uchar_t **, size_t *); +KMF_RETURN verify_altname(char *arg, KMF_GENERALNAMECHOICES *, int *); +KMF_RETURN verify_keyusage(char *arg, uint16_t *, int *); +KMF_RETURN verify_file(char *); +int get_token_password(KMF_KEYSTORE_TYPE, char *, KMF_CREDENTIAL *); +void display_error(void *, KMF_RETURN, char *); +#define DEFAULT_NSS_TOKEN "internal" +#define DEFAULT_TOKEN_PROMPT "Enter pin for %s: " + +#define EMPTYSTRING(s) (s == NULL || !strlen((char *)s)) + #ifdef __cplusplus } #endif diff --git a/usr/src/cmd/cmd-crypto/pktool/delete.c b/usr/src/cmd/cmd-crypto/pktool/delete.c index ea550974c5..57d484cbe2 100644 --- a/usr/src/cmd/cmd-crypto/pktool/delete.c +++ b/usr/src/cmd/cmd-crypto/pktool/delete.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,6 +36,382 @@ #include <cryptoutil.h> #include <security/cryptoki.h> #include "common.h" +#include <kmfapi.h> + +static KMF_RETURN +pk_destroy_keys(void *handle, KMF_KEY_HANDLE *keys, + KMF_FINDKEY_PARAMS *fkparams, uint32_t numkeys) +{ + int i; + KMF_RETURN rv = KMF_OK; + KMF_DELETEKEY_PARAMS dkparams; + + (void) memset(&dkparams, 0, sizeof (dkparams)); + dkparams.kstype = fkparams->kstype; + + switch (fkparams->kstype) { + case KMF_KEYSTORE_NSS: + dkparams.nssparms = fkparams->nssparms; + dkparams.cred = fkparams->cred; + break; + case KMF_KEYSTORE_OPENSSL: + break; + case KMF_KEYSTORE_PK11TOKEN: + dkparams.cred = fkparams->cred; + break; + default: + return (PK_ERR_USAGE); + } + + for (i = 0; rv == KMF_OK && i < numkeys; i++) { + rv = KMF_DeleteKeyFromKeystore(handle, &dkparams, &keys[i]); + } + return (rv); +} + +static KMF_RETURN +pk_delete_keys(KMF_HANDLE_T kmfhandle, KMF_FINDKEY_PARAMS *parms, char *desc, + int *keysdeleted) +{ + KMF_RETURN rv = KMF_OK; + uint32_t numkeys = 0; + + *keysdeleted = 0; + numkeys = 0; + rv = KMF_FindKey(kmfhandle, parms, NULL, &numkeys); + if (rv == KMF_OK && numkeys > 0) { + KMF_KEY_HANDLE *keys = NULL; + char prompt[1024]; + + (void) snprintf(prompt, sizeof (prompt), + gettext("%d %s key(s) found, do you want " + "to delete them (y/N) ?"), numkeys, + (desc != NULL ? desc : "")); + + if (!yesno(prompt, + gettext("Respond with yes or no.\n"), + B_FALSE)) { + return (KMF_OK); + } + keys = (KMF_KEY_HANDLE *)malloc(numkeys * + sizeof (KMF_KEY_HANDLE)); + if (keys == NULL) + return (KMF_ERR_MEMORY); + (void) memset(keys, 0, numkeys * + sizeof (KMF_KEY_HANDLE)); + + rv = KMF_FindKey(kmfhandle, parms, keys, &numkeys); + if (rv == KMF_OK) { + rv = pk_destroy_keys(kmfhandle, keys, + parms, numkeys); + } + + free(keys); + } + + if (rv == KMF_ERR_KEY_NOT_FOUND) { + rv = KMF_OK; + } + + *keysdeleted = numkeys; + return (rv); +} + +static KMF_RETURN +pk_delete_certs(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *fcparms, + KMF_DELETECERT_PARAMS *dcparms) +{ + KMF_RETURN rv = KMF_OK; + uint32_t numcerts = 0; + + rv = KMF_FindCert(kmfhandle, fcparms, NULL, &numcerts); + if (rv == KMF_OK && numcerts > 0) { + char prompt[1024]; + (void) snprintf(prompt, sizeof (prompt), + gettext("%d certificate(s) found, do you want " + "to delete them (y/N) ?"), numcerts); + + if (!yesno(prompt, + gettext("Respond with yes or no.\n"), + B_FALSE)) { + return (KMF_OK); + } + + rv = KMF_DeleteCertFromKeystore(kmfhandle, dcparms); + + } else if (rv == KMF_ERR_CERT_NOT_FOUND) { + rv = KMF_OK; + } + + return (rv); +} + +static KMF_RETURN +delete_nss_keys(KMF_HANDLE_T kmfhandle, char *dir, char *prefix, + char *token, int oclass, char *objlabel, + KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN rv = KMF_OK; + KMF_FINDKEY_PARAMS parms; + char *keytype = NULL; + int nk, numkeys = 0; + + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) + return (rv); + + (void) memset(&parms, 0, sizeof (parms)); + parms.kstype = KMF_KEYSTORE_NSS; + parms.findLabel = objlabel; + parms.cred = *tokencred; + parms.nssparms.slotlabel = token; + + if (oclass & PK_PRIKEY_OBJ) { + parms.keyclass = KMF_ASYM_PRI; + keytype = "private"; + rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk); + numkeys += nk; + } + if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { + parms.keyclass = KMF_SYMMETRIC; + keytype = "symmetric"; + rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk); + numkeys += nk; + } + if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { + parms.keyclass = KMF_ASYM_PUB; + keytype = "public"; + rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk); + numkeys += nk; + } + if (rv == KMF_OK && numkeys == 0) + rv = KMF_ERR_KEY_NOT_FOUND; + + return (rv); +} + + +static KMF_RETURN +delete_nss_certs(KMF_HANDLE_T kmfhandle, + char *dir, char *prefix, + char *token, char *objlabel, + KMF_BIGINT *serno, char *issuer, char *subject, + KMF_CERT_VALIDITY find_criteria_flag) +{ + KMF_RETURN rv = KMF_OK; + KMF_DELETECERT_PARAMS dcparms; + KMF_FINDCERT_PARAMS fcargs; + + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) + return (rv); + + (void) memset(&dcparms, 0, sizeof (dcparms)); + dcparms.kstype = KMF_KEYSTORE_NSS; + dcparms.certLabel = objlabel; + dcparms.issuer = issuer; + dcparms.subject = subject; + dcparms.serial = serno; + dcparms.find_cert_validity = find_criteria_flag; + dcparms.nssparms.slotlabel = token; + + (void) memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = KMF_KEYSTORE_NSS; + fcargs.certLabel = objlabel; + fcargs.issuer = issuer; + fcargs.subject = subject; + fcargs.serial = serno; + fcargs.find_cert_validity = find_criteria_flag; + fcargs.nssparms.slotlabel = token; + + rv = pk_delete_certs(kmfhandle, &fcargs, &dcparms); + + return (rv); +} + +static KMF_RETURN +delete_nss_crl(void *kmfhandle, + char *dir, char *prefix, char *token, + char *issuernickname, char *subject) +{ + KMF_RETURN rv = KMF_OK; + KMF_DELETECRL_PARAMS dcrlparms; + + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) + return (rv); + + (void) memset(&dcrlparms, 0, sizeof (dcrlparms)); + + dcrlparms.kstype = KMF_KEYSTORE_NSS; + dcrlparms.nssparms.slotlabel = token; + dcrlparms.nssparms.crl_issuerName = issuernickname; + dcrlparms.nssparms.crl_subjName = subject; + + rv = KMF_DeleteCRL(kmfhandle, &dcrlparms); + + return (rv); +} + +static KMF_RETURN +delete_pk11_keys(KMF_HANDLE_T kmfhandle, + char *token, int oclass, char *objlabel, + KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN rv = KMF_OK; + KMF_FINDKEY_PARAMS parms; + int nk, numkeys = 0; + + /* + * Symmetric keys and RSA/DSA private keys are always + * created with the "CKA_PRIVATE" field == TRUE, so + * make sure we search for them with it also set. + */ + if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ)) + oclass |= PK_PRIVATE_OBJ; + + rv = select_token(kmfhandle, token, FALSE); + if (rv != KMF_OK) { + return (rv); + } + + (void) memset(&parms, 0, sizeof (parms)); + parms.kstype = KMF_KEYSTORE_PK11TOKEN; + parms.findLabel = (char *)objlabel; + parms.keytype = 0; + parms.pkcs11parms.private = ((oclass & PK_PRIVATE_OBJ) > 0); + parms.cred.cred = tokencred->cred; + parms.cred.credlen = tokencred->credlen; + + if (oclass & PK_PRIKEY_OBJ) { + parms.keyclass = KMF_ASYM_PRI; + rv = pk_delete_keys(kmfhandle, &parms, "private", &nk); + numkeys += nk; + } + + if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { + parms.keyclass = KMF_SYMMETRIC; + rv = pk_delete_keys(kmfhandle, &parms, "symmetric", &nk); + numkeys += nk; + } + + if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { + parms.keyclass = KMF_ASYM_PUB; + rv = pk_delete_keys(kmfhandle, &parms, "public", &nk); + numkeys += nk; + } + if (rv == KMF_OK && numkeys == 0) + rv = KMF_ERR_KEY_NOT_FOUND; + + return (rv); +} + +static KMF_RETURN +delete_pk11_certs(KMF_HANDLE_T kmfhandle, + char *token, char *objlabel, + KMF_BIGINT *serno, char *issuer, char *subject, + KMF_CERT_VALIDITY find_criteria_flag) +{ + KMF_RETURN kmfrv; + KMF_DELETECERT_PARAMS dparms; + KMF_FINDCERT_PARAMS fcargs; + + kmfrv = select_token(kmfhandle, token, FALSE); + + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + (void) memset(&dparms, 0, sizeof (dparms)); + dparms.kstype = KMF_KEYSTORE_PK11TOKEN; + dparms.certLabel = objlabel; + dparms.issuer = issuer; + dparms.subject = subject; + dparms.serial = serno; + dparms.find_cert_validity = find_criteria_flag; + + fcargs = dparms; + kmfrv = pk_delete_certs(kmfhandle, &fcargs, &dparms); + + return (kmfrv); +} + +static KMF_RETURN +delete_file_certs(KMF_HANDLE_T kmfhandle, + char *dir, char *filename, KMF_BIGINT *serial, char *issuer, + char *subject, KMF_CERT_VALIDITY find_criteria_flag) +{ + KMF_RETURN rv; + KMF_DELETECERT_PARAMS dparms; + KMF_FINDCERT_PARAMS fcargs; + + (void *)memset(&dparms, 0, sizeof (dparms)); + (void *)memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = KMF_KEYSTORE_OPENSSL; + fcargs.certLabel = NULL; + fcargs.issuer = issuer; + fcargs.subject = subject; + fcargs.serial = serial; + fcargs.sslparms.dirpath = dir; + fcargs.sslparms.certfile = filename; + fcargs.find_cert_validity = find_criteria_flag; + + /* For now, delete parameters and find parameters are the same */ + dparms = fcargs; + + rv = pk_delete_certs(kmfhandle, &fcargs, &dparms); + + return (rv); +} + +static KMF_RETURN +delete_file_keys(KMF_HANDLE_T kmfhandle, int oclass, + char *dir, char *infile) +{ + KMF_RETURN rv = KMF_OK; + KMF_FINDKEY_PARAMS parms; + char *keytype = ""; + int nk, numkeys = 0; + + (void) memset(&parms, 0, sizeof (parms)); + parms.kstype = KMF_KEYSTORE_OPENSSL; + parms.sslparms.dirpath = dir; + parms.sslparms.keyfile = infile; + + if (oclass & (PK_PUBKEY_OBJ | PK_PRIKEY_OBJ)) { + parms.keyclass = KMF_ASYM_PRI; + keytype = "Asymmetric"; + rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk); + numkeys += nk; + } + if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { + parms.keyclass = KMF_SYMMETRIC; + keytype = "symmetric"; + rv = pk_delete_keys(kmfhandle, &parms, keytype, &nk); + numkeys += nk; + } + if (rv == KMF_OK && numkeys == 0) + rv = KMF_ERR_KEY_NOT_FOUND; + + return (rv); +} + +static KMF_RETURN +delete_file_crl(void *kmfhandle, char *dir, char *filename) +{ + KMF_RETURN rv; + KMF_DELETECRL_PARAMS dcrlparms; + + (void) memset(&dcrlparms, 0, sizeof (dcrlparms)); + + dcrlparms.kstype = KMF_KEYSTORE_OPENSSL; + dcrlparms.sslparms.dirpath = dir; + dcrlparms.sslparms.crlfile = filename; + + rv = KMF_DeleteCRL(kmfhandle, &dcrlparms); + + return (rv); +} /* * Delete token objects. @@ -48,31 +423,34 @@ pk_delete(int argc, char *argv[]) extern int optind_av; extern char *optarg_av; char *token_spec = NULL; - char *token_name = NULL; - char *manuf_id = NULL; - char *serial_no = NULL; - char *type_spec = NULL; - char full_name[FULL_NAME_LEN]; - boolean_t public_objs = B_FALSE; - boolean_t private_objs = B_FALSE; - CK_BYTE *object_label = NULL; - int obj_type = 0x00; - CK_SLOT_ID slot_id; - CK_FLAGS pin_state; - CK_UTF8CHAR_PTR pin = NULL; - CK_ULONG pinlen = 0; - CK_SESSION_HANDLE sess; - CK_OBJECT_HANDLE *objs; - CK_ULONG num_objs; - CK_ATTRIBUTE label = { CKA_LABEL, NULL, 0 }; - CK_RV rv = CKR_OK; - int i; - - cryptodebug("inside pk_delete"); + char *subject = NULL; + char *issuer = NULL; + char *dir = NULL; + char *prefix = NULL; + char *infile = NULL; + char *object_label = NULL; + char *serstr = NULL; + + int oclass = 0; + KMF_BIGINT serial = { NULL, 0 }; + KMF_HANDLE_T kmfhandle = NULL; + KMF_KEYSTORE_TYPE kstype = 0; + KMF_RETURN kmfrv; + int rv = 0; + char *find_criteria = NULL; + KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS; + KMF_CREDENTIAL tokencred = {NULL, 0}; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, - "T:(token)y:(objtype)l:(label)")) != EOF) { + "T:(token)y:(objtype)l:(label)" + "k:(keystore)s:(subject)n:(nickname)" + "d:(dir)p:(prefix)S:(serial)i:(issuer)" + "c:(criteria)" + "f:(infile)")) != EOF) { + + if (EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) @@ -80,14 +458,52 @@ pk_delete(int argc, char *argv[]) token_spec = optarg_av; break; case 'y': /* object type: public, private, both */ - if (type_spec) + if (oclass) + return (PK_ERR_USAGE); + oclass = OT2Int(optarg_av); + if (oclass == -1) return (PK_ERR_USAGE); - type_spec = optarg_av; break; case 'l': /* objects with specific label */ + case 'n': if (object_label) return (PK_ERR_USAGE); - object_label = (CK_BYTE *)optarg_av; + object_label = (char *)optarg_av; + break; + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 's': + subject = optarg_av; + break; + case 'i': + issuer = optarg_av; + break; + case 'd': + dir = optarg_av; + break; + case 'p': + prefix = optarg_av; + break; + case 'S': + serstr = optarg_av; + break; + case 'f': + infile = optarg_av; + break; + case 'c': + find_criteria = optarg_av; + if (!strcasecmp(find_criteria, "valid")) + find_criteria_flag = + KMF_NONEXPIRED_CERTS; + else if (!strcasecmp(find_criteria, "expired")) + find_criteria_flag = KMF_EXPIRED_CERTS; + else if (!strcasecmp(find_criteria, "both")) + find_criteria_flag = KMF_ALL_CERTS; + else + return (PK_ERR_USAGE); break; default: return (PK_ERR_USAGE); @@ -95,55 +511,23 @@ pk_delete(int argc, char *argv[]) } } - /* If no token is specified, default is to use softtoken. */ - if (token_spec == NULL) { - token_name = SOFT_TOKEN_LABEL; - manuf_id = SOFT_MANUFACTURER_ID; - serial_no = SOFT_TOKEN_SERIAL; - } else { - /* - * Parse token specifier into token_name, manuf_id, serial_no. - * Token_name is required; manuf_id and serial_no are optional. - */ - if (parse_token_spec(token_spec, &token_name, &manuf_id, - &serial_no) < 0) - return (PK_ERR_USAGE); - } + /* Assume keystore = PKCS#11 if not specified */ + if (kstype == 0) + kstype = KMF_KEYSTORE_PK11TOKEN; - /* If no object type specified, default is public objects. */ - if (!type_spec) { - public_objs = B_TRUE; - } else { - /* - * Otherwise, the object type must be "public", "private", - * or "both". - */ - if (strcmp(type_spec, "private") == 0) { - private_objs = B_TRUE; - } else if (strcmp(type_spec, "public") == 0) { - public_objs = B_TRUE; - } else if (strcmp(type_spec, "both") == 0) { - private_objs = B_TRUE; - public_objs = B_TRUE; - } else - return (PK_ERR_USAGE); - } - - if (private_objs) - obj_type |= PK_PRIVATE_OBJ; - if (public_objs) - obj_type |= PK_PUBLIC_OBJ; + /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ + if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && + kstype != KMF_KEYSTORE_PK11TOKEN) { - /* At least one of public, private, or object label is required. */ - if (!private_objs && !public_objs && object_label == NULL) + (void) fprintf(stderr, gettext("The objtype parameter " + "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); + } - /* - * If object label is given but neither public/private is specified, - * delete all objects with that label. - */ - if (!private_objs && !public_objs && object_label != NULL) - obj_type = PK_ALL_OBJ; + /* If no object class specified, delete everything but CRLs */ + if (oclass == 0) + oclass = PK_CERT_OBJ | PK_PUBKEY_OBJ | PK_PRIKEY_OBJ | + PK_SYMKEY_OBJ; /* No additional args allowed. */ argc -= optind_av; @@ -152,112 +536,129 @@ pk_delete(int argc, char *argv[]) return (PK_ERR_USAGE); /* Done parsing command line options. */ - full_token_name(token_name, manuf_id, serial_no, full_name); - - /* Find the slot with token. */ - if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id, - &pin_state)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to find token %s (%s)."), full_name, - pkcs11_strerror(rv)); - return (PK_ERR_PK11); + if (kstype == KMF_KEYSTORE_PK11TOKEN && token_spec == NULL) { + token_spec = PK_DEFAULT_PK11TOKEN; + } else if (kstype == KMF_KEYSTORE_NSS && token_spec == NULL) { + token_spec = DEFAULT_NSS_TOKEN; } - /* Always get the user's PIN for delete operations. */ - if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin, - &pinlen)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get token passphrase (%s)."), - pkcs11_strerror(rv)); - quick_finish(NULL); - return (PK_ERR_PK11); - } + if (serstr != NULL) { + uchar_t *bytes = NULL; + size_t bytelen; - /* Log the user R/W into the token. */ - if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to log into token (%s)."), pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); + rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen); + if (rv != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, gettext("serial number " + "must be specified as a hex number " + "(ex: 0x0102030405ffeeddee)\n")); + return (PK_ERR_USAGE); + } + serial.val = bytes; + serial.len = bytelen; } - /* Find the object(s) with the given label and/or type. */ - if ((rv = find_objs(sess, obj_type, object_label, &objs, &num_objs)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to find token objects (%s)."), pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); - } + if ((kstype == KMF_KEYSTORE_PK11TOKEN || + kstype == KMF_KEYSTORE_NSS) && + (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ))) { - if (num_objs == 0) { - (void) fprintf(stdout, gettext("No matching objects found.\n")); - quick_finish(sess); - return (0); + (void) get_token_password(kstype, token_spec, + &tokencred); } - if (num_objs != 1) { - (void) fprintf(stdout, gettext( - "Warning: %d matching objects found, deleting all.\n"), - num_objs); - if (yesno(gettext("Continue with delete? "), - gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { - quick_finish(sess); - return (0); - } - } + if ((kmfrv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) + return (kmfrv); - /* Destroy the objects if found. */ - for (i = 0; i < num_objs; i++) { - /* - * To give nice feedback to the user, get the object's - * label before deleting it. - */ - cryptodebug("calling C_GetAttributeValue for label"); - label.pValue = NULL; - label.ulValueLen = 0; - if (C_GetAttributeValue(sess, objs[i], &label, 1) == CKR_OK) { - if (label.ulValueLen != (CK_ULONG)-1 && - label.ulValueLen != 0 && - (label.pValue = malloc(label.ulValueLen)) != NULL) { - if (C_GetAttributeValue(sess, objs[i], &label, - 1) != CKR_OK) { - free(label.pValue); - label.pValue = NULL; - label.ulValueLen = 0; - } - } else { - label.ulValueLen = 0; + switch (kstype) { + case KMF_KEYSTORE_PK11TOKEN: + if (oclass & PK_KEY_OBJ) { + kmfrv = delete_pk11_keys(kmfhandle, + token_spec, oclass, + object_label, + &tokencred); + /* + * If deleting groups of objects, it is OK + * to ignore the "key not found" case so that + * we can continue to find other objects. + */ + if (kmfrv == KMF_ERR_KEY_NOT_FOUND && + (oclass != PK_KEY_OBJ)) + kmfrv = KMF_OK; + if (kmfrv != KMF_OK) + break; } - } - - cryptodebug("calling C_DestroyObject"); - if ((rv = C_DestroyObject(sess, objs[i])) != CKR_OK) { - if (label.pValue != NULL) - cryptoerror(LOG_STDERR, gettext( - "Unable to delete object #%d \"%.*s\" " - "(%s)."), i+1, label.ulValueLen, - label.pValue, pkcs11_strerror(rv)); - else - cryptoerror(LOG_STDERR, gettext( - "Unable to delete object #%d (%s)."), - i+1, pkcs11_strerror(rv)); - } else { - if (label.pValue != NULL) - (void) fprintf(stdout, gettext("Object #%d " - "\"%.*s\" successfully deleted.\n"), - i+1, label.ulValueLen, label.pValue); - else - (void) fprintf(stdout, gettext( - "Object #%d successfully deleted.\n"), i+1); - } + if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { + kmfrv = delete_pk11_certs(kmfhandle, + token_spec, + object_label, + &serial, issuer, + subject, find_criteria_flag); + /* + * If cert delete failed, but we are looking at + * other objects, then it is OK. + */ + if (kmfrv == KMF_ERR_CERT_NOT_FOUND && + (oclass & (PK_CRL_OBJ | PK_KEY_OBJ))) + kmfrv = KMF_OK; + if (kmfrv != KMF_OK) + break; + } + if (oclass & PK_CRL_OBJ) + kmfrv = delete_file_crl(kmfhandle, + dir, infile); + break; + case KMF_KEYSTORE_NSS: + if (oclass & PK_KEY_OBJ) { + kmfrv = delete_nss_keys(kmfhandle, + dir, prefix, token_spec, + oclass, (char *)object_label, + &tokencred); + if (kmfrv != KMF_OK) + break; + } + if (oclass & PK_CERT_OBJ) { + kmfrv = delete_nss_certs(kmfhandle, + dir, prefix, token_spec, + (char *)object_label, + &serial, issuer, subject, + find_criteria_flag); + if (kmfrv != KMF_OK) + break; + } + if (oclass & PK_CRL_OBJ) + kmfrv = delete_nss_crl(kmfhandle, + dir, prefix, token_spec, + (char *)object_label, subject); + break; + case KMF_KEYSTORE_OPENSSL: + if (oclass & PK_KEY_OBJ) { + kmfrv = delete_file_keys(kmfhandle, oclass, + dir, infile); + if (kmfrv != KMF_OK) + break; + } + if (oclass & (PK_CERT_OBJ)) { + kmfrv = delete_file_certs(kmfhandle, + dir, infile, &serial, issuer, + subject, find_criteria_flag); + if (kmfrv != KMF_OK) + break; + } + if (oclass & PK_CRL_OBJ) + kmfrv = delete_file_crl(kmfhandle, + dir, infile); + break; + default: + rv = PK_ERR_USAGE; + break; + } - if (label.pValue != NULL) - free(label.pValue); + if (kmfrv != KMF_OK) { + display_error(kmfhandle, kmfrv, + gettext("Error deleting objects")); } - /* Clean up. */ - quick_finish(sess); - return (0); + if (serial.val != NULL) + free(serial.val); + (void) KMF_Finalize(kmfhandle); + return (kmfrv); } diff --git a/usr/src/cmd/cmd-crypto/pktool/derparse.c b/usr/src/cmd/cmd-crypto/pktool/derparse.c deleted file mode 100644 index cec607220a..0000000000 --- a/usr/src/cmd/cmd-crypto/pktool/derparse.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * derparse.c - Functions for parsing DER-encoded data - * - * NOTE: This code was originally written by Cryptographic Products - * Group at Sun Microsystems for the SCA 1000 "realmparse" program. - * It is mostly intact except for necessary adaptaions to allow it to - * compile in this environment. - */ - -#include <errno.h> -#include <fcntl.h> -#include <lber.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <cryptoutil.h> -#include "derparse.h" - -/* I18N helpers. */ -#include <libintl.h> -#include <locale.h> - -/* - * Some types that we need below. - */ -typedef struct oidinfo { - uint8_t *value; /* OID value in bytes */ - size_t length; /* Length of OID */ - char *strval; /* String rep. for OID in RDN */ -} oidinfo_t; - -/* - * X.509 Issuer OIDs as recommended by RFC 3280 - * We might see these in certificates in their subject an issuer names. - */ -static uint8_t common_name_oid[] = {0x55, 0x04, 0x03}; -static uint8_t surname_oid[] = {0x55, 0x04, 0x04}; -static uint8_t serial_number_oid[] = {0x55, 0x04, 0x05}; -static uint8_t country_name_oid[] = {0x55, 0x04, 0x06}; -static uint8_t locality_name_oid[] = {0x55, 0x04, 0x07}; -static uint8_t state_name_oid[] = {0x55, 0x04, 0x08}; -static uint8_t org_name_oid[] = {0x55, 0x04, 0x0a}; -static uint8_t org_unit_name_oid[] = {0x55, 0x04, 0x0b}; -static uint8_t title_oid[] = {0x55, 0x04, 0x0c}; -static uint8_t name_oid[] = {0x55, 0x04, 0x29}; -static uint8_t given_name_oid[] = {0x55, 0x04, 0x2a}; -static uint8_t initials_oid[] = {0x55, 0x04, 0x2b}; -static uint8_t gen_qual_oid[] = {0x55, 0x04, 0x2c}; -static uint8_t dn_qual_oid[] = {0x55, 0x04, 0x2e}; -static uint8_t pseudonym_oid[] = {0x55, 0x04, 0x31}; -static uint8_t uid_oid[] = - {0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x01}; -static uint8_t domain_comp_oid[] = - {0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19}; -static uint8_t email_addr_oid[] = - {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01}; - -/* Define this structure so we can match on a given oid */ -static oidinfo_t oids[] = { - {common_name_oid, sizeof (common_name_oid), "CN"}, - {surname_oid, sizeof (surname_oid), "SN"}, - {serial_number_oid, sizeof (serial_number_oid), "SerialNum"}, - {country_name_oid, sizeof (country_name_oid), "C"}, - {locality_name_oid, sizeof (locality_name_oid), "L"}, - {state_name_oid, sizeof (state_name_oid), "ST"}, - {org_name_oid, sizeof (org_name_oid), "O"}, - {org_unit_name_oid, sizeof (org_unit_name_oid), "OU"}, - {title_oid, sizeof (title_oid), "Title"}, - {name_oid, sizeof (name_oid), "Name"}, - {given_name_oid, sizeof (given_name_oid), "GN"}, - {initials_oid, sizeof (initials_oid), "Initials"}, - {gen_qual_oid, sizeof (gen_qual_oid), "GenQual"}, - {dn_qual_oid, sizeof (dn_qual_oid), "DNQual"}, - {pseudonym_oid, sizeof (pseudonym_oid), "Pseudonym"}, - {uid_oid, sizeof (uid_oid), "UID"}, - {domain_comp_oid, sizeof (domain_comp_oid), "DC"}, - {email_addr_oid, sizeof (email_addr_oid), "E"} -}; -static int oidblocklen = sizeof (oids) / sizeof (oidinfo_t); - -/* Local functions */ -static int oid_to_str(uint8_t *, size_t, char *, size_t); -static int get_oid_type(char *); - -/* - * An RDNSequence is what is handed to us when we get attributes like - * CKA_ISSUER and CKA_SUBJECT_NAME. This function will take in a buffer - * with the DER encoded bytes of an RDNSequence and print out the components. - * - * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - * - * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue - * - * AttributeTypeAndValue ::= SEQUENCE { - * type AttributeType, - * value AttributeValue - * } - * - * AttributeType ::= OBJECT IDENTIFIER - * - * AttributeValue ::= ANY DEFINED BY AttributeType - */ -void -rdnseq_to_str(uchar_t *derdata, size_t dersz, char *out, size_t outsz) -{ -#define PKTOOL_LINEMAX 1024 - char oidout[PKTOOL_LINEMAX]; - BerElement *ber = NULL; - BerValue ber_rdns; - int tag; - ber_len_t size; - char *atv_type = NULL; /* Attribute Type */ - ber_len_t atv_type_size; - char *atv_value = NULL; /* Attribute Value */ - ber_len_t atv_value_size; - char *cookie = NULL; - int idx; - char *prndata = NULL; - int prnsz; - int offset = 0; - boolean_t first = B_TRUE; - - cryptodebug("inside rdnseq_to_str"); - - if (derdata == NULL || dersz == 0) { - cryptodebug("nothing to parse"); - return; - } - - /* Take the raw bytes and stuff them into a BerValue structure */ - ber_rdns.bv_val = (char *)derdata; - ber_rdns.bv_len = dersz; - - /* Allocate the BerElement */ - if ((ber = ber_init(&ber_rdns)) == NULLBER) { - cryptodebug("ber_init failed to return ber element"); - cryptoerror(LOG_STDERR, gettext( - "Unable to begin parsing RDNSequence.")); - return; - } - - /* Begin by parsing out the outer sequence */ - tag = ber_next_element(ber, &size, cookie); - if (tag != LBER_SEQUENCE) { - cryptodebug("ber_next_element tag is not SEQUENCE"); - cryptoerror(LOG_STDERR, gettext( - "Expected RDNSequence SEQUENCE object, got tag [%02x]."), - tag); - return; - } - tag = ber_scanf(ber, "{"); - - /* Parse the sequence of RelativeDistinguishedName objects */ - while ((tag = ber_next_element(ber, &size, cookie)) != -1) { - if (tag != LBER_SET) { - cryptodebug("ber_next_element tag is not SET"); - cryptoerror(LOG_STDERR, gettext( - "Expected RelativeDistinguishedName SET object, " - "got tag [%02x]."), tag); - return; - } - tag = ber_scanf(ber, "["); - - /* AttributeTypeAndValue */ - tag = ber_next_element(ber, &size, cookie); - if (tag != LBER_SEQUENCE) { - cryptodebug("ber_next_element tag is not SEQUENCE"); - cryptoerror(LOG_STDERR, gettext( - "Expected AttributeTypeAndValue SEQUENCE object, " - "got tag [%02x]."), tag); - return; - } - tag = ber_scanf(ber, "{"); - - /* AttributeType OID */ - tag = ber_next_element(ber, &atv_type_size, cookie); - atv_type_size++; /* Add room for null terminator */ - if (tag != LBER_OID) { - cryptodebug("ber_next_element tag is not OID"); - cryptoerror(LOG_STDERR, gettext( - "Expected an OID, got tag [%02x]."), tag); - return; - } - /* Note: ber_scanf() allocates memory here for "a". */ - tag = ber_scanf(ber, "a", &atv_type, &atv_type_size); - - /* AttributeValue */ - tag = ber_next_element(ber, &atv_value_size, cookie); - atv_value_size++; - if ((tag != LBER_PRINTABLE_STRING) && (tag != LBER_IA5STRING)) { - cryptodebug("ber_next_element tag is not " - "PRINTABLE_STRING/IA5STRING"); - cryptoerror(LOG_STDERR, gettext("Expected a STRING, " - "got tag [%02x]."), tag); - free(atv_type); - return; - } - /* Note: ber_scanf() allocates memory here for "a". */ - tag = ber_scanf(ber, "a", &atv_value, &atv_value_size); - - /* - * Now go and turn the attribute type and value into - * some kind of meaningful output. - */ - if ((idx = get_oid_type(atv_type)) == -1) { - if (oid_to_str((uint8_t *)atv_type, strlen(atv_type), - oidout, sizeof (oidout)) < 0) { - cryptodebug("oid_to_str failed"); - cryptoerror(LOG_STDERR, gettext( - "Unable to convert OID to string.")); - free(atv_type); - free(atv_value); - return; - } - prndata = oidout; - } else { - prndata = oids[idx].strval; - } - - if (!first) - prnsz = snprintf(out + offset, outsz - offset, - ", %s = %s", prndata, atv_value); - else { - prnsz = snprintf(out + offset, outsz - offset, - "%s = %s", prndata, atv_value); - first = B_FALSE; - } - - free(atv_type); - free(atv_value); - atv_type = NULL; - atv_value = NULL; - - offset += prnsz; - if (offset >= outsz) - break; - } -} - -/* - * Convert OID to dotted notation string. - */ -static int -oid_to_str(uint8_t *oid, size_t oidlen, char *oidout, size_t oidout_len) -{ - int count = 0; - int offset = 0; - int prnsz; - uint_t firstnum; - uint_t secondnum; - uint64_t nextnum = 0; - - cryptodebug("inside oid_to_str"); - - if (oidlen == 0) - return (-1); - - /* - * The first octet has a value of (40 x oidnum1) + oidnum2. We - * will deconstruct it here and sanity check the result. According - * to X.690, oidnum1 should never be more than 2 and oidnum2 - * shouldn't be greater than 39 when oidnum1 = 0 or 1. - */ - firstnum = oid[count] / 40; - if (firstnum > 2) /* force remainder to be > 39 */ - firstnum = 2; - secondnum = oid[count] - (firstnum * 40); - - (void) memset(oidout, 0, oidout_len); - - prnsz = snprintf(oidout, oidout_len, "%d.%d", firstnum, secondnum); - offset += prnsz; - if (offset >= oidout_len) - return (0); - - /* Start at the second byte and move our way forward */ - for (count = 1; count < oidlen; count++) { - /* ORIGINAL COMMENT */ - /* - * Each oid byte is taken as a 7-bit number. If bit 8 is - * set, it means the next octet and this one are to be - * chained together as a single bit string, and so forth. - * We need to mask of bit 8, then shift over 7 bits in the - * resulting integer, and then stuff the new 7 bits in - * the low order byte, all the while making sure we don't - * stomp bit 1 from the previous octet. - * See X.690 or the layman's guide to ASN.1 for more. - */ - - /* - * String together as many of the next octets if each of - * their high order bits is set to 1. For example, - * 1 1010111, 1 0010100, 1 0010110, 0 1101111, ... - * (3 8-bit octets) - * becomes - * 1010111 0010100 0010110, 1101111, ... - * (one 21 bit integer) - * The high order bit functions as a "link" between octets. - * Note that if there are more than 9 octets with their - * high order bits set, it will overflow a 64-bit integer. - */ - for (nextnum = 0; (oid[count] & 0x80) && (count < oidlen); - count++) { - nextnum <<= 7; - nextnum |= (oid[count] & 0x7f); - } - if (count == oidlen) /* last number not terminated? */ - return (-1); - - /* We're done with this oid number, write it and move on */ - prnsz = snprintf(oidout + offset, oidout_len - offset, - ".%lld", nextnum); - offset += prnsz; - if (offset >= oidout_len) - return (0); - } - - return (0); -} - -/* - * Returns the index in the oids[] array that matches the input type, - * or -1 if it could not find a match. - */ -static int -get_oid_type(char *type) -{ - int count; - - cryptodebug("inside get_oid_type"); - - for (count = 0; count < oidblocklen; count++) { - if (memcmp(oids[count].value, type, oids[count].length) == 0) { - return (count); - } - } - - /* If we get here, we haven't found a match, so return -1 */ - return (-1); -} diff --git a/usr/src/cmd/cmd-crypto/pktool/download.c b/usr/src/cmd/cmd-crypto/pktool/download.c new file mode 100644 index 0000000000..1eabc85ee3 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/pktool/download.c @@ -0,0 +1,274 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <malloc.h> +#include <libgen.h> +#include <fcntl.h> +#include <errno.h> +#include <cryptoutil.h> +#include "common.h" +#include <kmfapi.h> + +int +pk_download(int argc, char *argv[]) +{ + int rv; + int opt; + extern int optind_av; + extern char *optarg_av; + int oclass = 0; + char *url = NULL; + char *http_proxy = NULL; + char *dir = NULL; + char *outfile = NULL; + char *proxy = NULL; + int proxy_port = 0; + KMF_HANDLE_T kmfhandle = NULL; + KMF_ENCODE_FORMAT format; + KMF_RETURN ch_rv = KMF_OK; + char *fullpath = NULL; + KMF_DATA cert = {NULL, 0}; + KMF_DATA cert_der = {NULL, 0}; + + while ((opt = getopt_av(argc, argv, + "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) { + + if (EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); + switch (opt) { + case 't': + if (oclass) + return (PK_ERR_USAGE); + oclass = OT2Int(optarg_av); + if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ))) + return (PK_ERR_USAGE); + break; + case 'u': + if (url) + return (PK_ERR_USAGE); + url = optarg_av; + break; + case 'h': + if (http_proxy) + return (PK_ERR_USAGE); + http_proxy = optarg_av; + break; + case 'o': + if (outfile) + return (PK_ERR_USAGE); + outfile = optarg_av; + break; + case 'd': + if (dir) + return (PK_ERR_USAGE); + dir = optarg_av; + break; + default: + cryptoerror(LOG_STDERR, gettext( + "unrecognized download option '%s'\n"), + argv[optind_av]); + return (PK_ERR_USAGE); + } + } + + /* No additional args allowed. */ + argc -= optind_av; + argv += optind_av; + if (argc) { + return (PK_ERR_USAGE); + } + + /* Check the dir and outfile options */ + if (outfile == NULL) { + /* If outfile is not specified, use the basename of URI */ + outfile = basename(url); + } + + fullpath = get_fullpath(dir, outfile); + if (fullpath == NULL) { + cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile " + "option value \n")); + return (PK_ERR_USAGE); + } + /* Check if the file exists and might be overwritten. */ + if (access(fullpath, F_OK) == 0) { + cryptoerror(LOG_STDERR, + gettext("Warning: file \"%s\" exists, " + "will be overwritten."), fullpath); + if (yesno(gettext("Continue with download? "), + gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { + return (0); + } + } else { + rv = verify_file(fullpath); + if (rv != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("The file (%s) " + "cannot be created.\n"), fullpath); + return (PK_ERR_USAGE); + } + } + + + /* URI MUST be specified */ + if (url == NULL) { + cryptoerror(LOG_STDERR, gettext("A URL must be specified\n")); + rv = PK_ERR_USAGE; + goto end; + } + + /* + * Get the http proxy from the command "http_proxy" option or the + * environment variable. The command option has a higher priority. + */ + if (http_proxy == NULL) + http_proxy = getenv("http_proxy"); + + if (http_proxy != NULL) { + char *ptmp = http_proxy; + char *proxy_port_s; + + if (strncasecmp(ptmp, "http://", 7) == 0) + ptmp += 7; /* skip the scheme prefix */ + + proxy = strtok(ptmp, ":"); + proxy_port_s = strtok(NULL, "\0"); + if (proxy_port_s != NULL) + proxy_port = strtol(proxy_port_s, NULL, 0); + else + proxy_port = 8080; + } + + /* If objtype is not specified, default to CRL */ + if (oclass == 0) { + oclass = PK_CRL_OBJ; + } + + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); + rv = PK_ERR_USAGE; + goto end; + } + + /* Now we are ready to download */ + if (oclass & PK_CRL_OBJ) { + rv = KMF_DownloadCRL(kmfhandle, url, proxy, proxy_port, 30, + fullpath, &format); + } else if (oclass & PK_CERT_OBJ) { + rv = KMF_DownloadCert(kmfhandle, url, proxy, proxy_port, 30, + fullpath, &format); + } + + if (rv != KMF_OK) { + switch (rv) { + case KMF_ERR_BAD_URI: + cryptoerror(LOG_STDERR, + gettext("Error in parsing URI\n")); + rv = PK_ERR_USAGE; + break; + case KMF_ERR_OPEN_FILE: + cryptoerror(LOG_STDERR, + gettext("Error in opening file\n")); + rv = PK_ERR_USAGE; + break; + case KMF_ERR_WRITE_FILE: + cryptoerror(LOG_STDERR, + gettext("Error in writing file\n")); + rv = PK_ERR_USAGE; + break; + case KMF_ERR_BAD_CRLFILE: + cryptoerror(LOG_STDERR, gettext("Not a CRL file\n")); + rv = PK_ERR_USAGE; + break; + case KMF_ERR_BAD_CERTFILE: + cryptoerror(LOG_STDERR, + gettext("Not a certificate file\n")); + rv = PK_ERR_USAGE; + break; + case KMF_ERR_MEMORY: + cryptoerror(LOG_STDERR, + gettext("Not enough memory\n")); + rv = PK_ERR_SYSTEM; + break; + default: + cryptoerror(LOG_STDERR, + gettext("Error in downloading the file.\n")); + rv = PK_ERR_SYSTEM; + break; + } + goto end; + } + + /* + * If the file is successfully downloaded, we also check the date. + * If the downloaded file is outdated, give a warning. + */ + if (oclass & PK_CRL_OBJ) { + KMF_CHECKCRLDATE_PARAMS params; + + params.crl_name = fullpath; + ch_rv = KMF_CheckCRLDate(kmfhandle, ¶ms); + + } else { /* certificate */ + ch_rv = KMF_ReadInputFile(kmfhandle, fullpath, &cert); + if (ch_rv != KMF_OK) + goto end; + + if (format == KMF_FORMAT_PEM) { + int len; + ch_rv = KMF_Pem2Der(cert.Data, cert.Length, + &cert_der.Data, &len); + if (ch_rv != KMF_OK) + goto end; + cert_der.Length = (size_t)len; + } + + ch_rv = KMF_CheckCertDate(kmfhandle, + format == KMF_FORMAT_ASN1 ? &cert : &cert_der); + } + +end: + if (ch_rv == KMF_ERR_VALIDITY_PERIOD) { + cryptoerror(LOG_STDERR, + gettext("Warning: the downloaded file is expired.\n")); + } else if (ch_rv != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Warning: failed to check the validity.\n")); + } + + if (fullpath) + free(fullpath); + + KMF_FreeData(&cert); + KMF_FreeData(&cert_der); + + (void) KMF_Finalize(kmfhandle); + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/pktool/export.c b/usr/src/cmd/cmd-crypto/pktool/export.c index 46fbccb37e..9170a00468 100644 --- a/usr/src/cmd/cmd-crypto/pktool/export.c +++ b/usr/src/cmd/cmd-crypto/pktool/export.c @@ -17,8 +17,8 @@ * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END - */ -/* + * + * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,1170 +38,264 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <cryptoutil.h> -#include <security/cryptoki.h> +#include <fcntl.h> #include "common.h" -#include "biginteger.h" -#include "osslcommon.h" -#include "p12common.h" -#include <openssl/pkcs12.h> - -/* - * Writes OpenSSL objects to PKCS#12 file. The PKCS#11 objects from - * the soft token need to be converted to OpenSSL structures prior - * to this call, since the PKCS#12 routines depend on that format. - * This code is patterned from OpenSSL apps that write PKCS#12 files. - * - * Note: it's not clear from the usage of all the functions here by - * OpenSSL apps whether these functions have return values or error - * conditions that can be checked. This function may benefit from - * a closer review at a later time. - */ -static int -write_objs_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen, - CK_BYTE_PTR id, CK_ULONG id_len, EVP_PKEY *priv_key, X509 *cert, - STACK_OF(X509) *ca_certs, int *successes, int *failures) -/* ARGSUSED */ -{ - STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL; - PKCS12_SAFEBAG *bag = NULL; - X509 *ca = NULL; - PKCS7 *cert_authsafe = NULL; - PKCS8_PRIV_KEY_INFO *p8 = NULL; - PKCS7 *key_authsafe = NULL; - STACK_OF(PKCS7) *authsafe_stack = NULL; - PKCS12 *p12_elem = NULL; - unsigned char *lab = NULL; - int lab_len = 0; - int i; - int n_writes = 0; - - cryptodebug("inside write_objs_pkcs12"); - - /* Do not reset *successes or *failures -- keep running totals. */ - - /* If there is nothing to write to the PKCS#12 file, leave. */ - if (cert == NULL && ca_certs == NULL && priv_key == NULL) { - cryptodebug("nothing to write to export file"); - return (0); - } - - /* - * Section 1: - * - * The first PKCS#12 container (safebag) will hold the certificates - * associated with this key. The result of this section is a - * PIN-encrypted PKCS#7 container (authsafe). If there are no - * certificates, there is no point in creating the "safebag" or the - * "authsafe" so we go to the next section. - */ - if (cert != NULL || ca_certs != NULL) { - /* Start a PKCS#12 safebag container for the certificates. */ - cryptodebug("creating certificate PKCS#12 safebag"); - bag_stack = sk_PKCS12_SAFEBAG_new_null(); - if (bag_stack == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create PKCS#12 certificate bag.")); - (*failures)++; - return (-1); - } - - /* Add the cert corresponding to private key to bag_stack. */ - if (cert) { - /* Convert cert from X509 struct to PKCS#12 bag */ - cryptodebug("adding certificate to PKCS#12 safebag"); - bag = PKCS12_x5092certbag(cert); - if (bag == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert certificate to " - "PKCS#12 bag.")); - /* Cleanup the safebag. */ - sk_PKCS12_SAFEBAG_pop_free(bag_stack, - PKCS12_SAFEBAG_free); - (*failures)++; - return (-1); - } - - /* Add the key id to the certificate bag. */ - cryptodebug("add key id to PKCS#12 safebag"); - if (!PKCS12_add_localkeyid(bag, id, id_len)) - cryptodebug("error not caught"); - - /* Add the friendly name to the certificate bag. */ - if ((lab = X509_alias_get0(cert, &lab_len)) != NULL) { - cryptodebug( - "label PKCS#12 safebag with friendly name"); - if (!PKCS12_add_friendlyname(bag, (char *)lab, - lab_len)) - cryptodebug("error not caught"); - } - - /* Pile it on the bag_stack. */ - if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) - cryptodebug("error not caught"); - - n_writes++; - } - - /* Add all the CA chain certs to the bag_stack. */ - if (ca_certs) { - cryptodebug("adding CA certificate chain to PKCS#12 " - "safebag"); - /* - * Go through the stack of CA certs, converting each - * one to a PKCS#12 bag and piling them onto the - * bag_stack. - */ - for (i = 0; i < sk_X509_num(ca_certs); i++) { - /* - * sk_X509_value() is macro that embeds a - * cast to (X509 *). Here it translates - * into ((X509 *)sk_value((ca_certs), (i))). - * Lint is complaining about the embedded - * casting, and to fix it, you need to fix - * openssl header files. - */ - /* LINTED E_BAD_PTR_CAST_ALIGN */ - ca = sk_X509_value(ca_certs, i); - - /* Convert CA cert to PKCS#12 bag. */ - cryptodebug("adding CA certificate #%d " - "to PKCS#12 safebag", i+1); - bag = PKCS12_x5092certbag(ca); - if (bag == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert CA certificate " - "#%d to PKCS#12 bag."), i+1); - /* Cleanup the safebag. */ - sk_PKCS12_SAFEBAG_pop_free(bag_stack, - PKCS12_SAFEBAG_free); - (*failures)++; - return (-1); - } - - /* Note CA certs do not have friendly name. */ - - /* Pile it onto the bag_stack. */ - if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) - cryptodebug("error not caught"); - - n_writes++; - } - } - - /* Turn bag_stack of certs into encrypted authsafe. */ - cryptodebug("encrypt certificate PKCS#12 bag into " - "PKCS#7 authsafe"); - cert_authsafe = PKCS12_pack_p7encdata( - NID_pbe_WithSHA1And40BitRC2_CBC, (char *)pin, -1, NULL, - 0, PKCS12_DEFAULT_ITER, bag_stack); - - /* Clear away this bag_stack, we're done with it. */ - sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); - bag_stack = NULL; - - if (cert_authsafe == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to PKCS#7-encrypt certificate bag.")); - (*failures)++; - return (-1); - } - } - - /* - * Section 2: - * - * The second PKCS#12 container (safebag) will hold the private key - * that goes with the certificates above. The results of this section - * is an unencrypted PKCS#7 container (authsafe). If there is no - * private key, there is no point in creating the "safebag" or the - * "authsafe" so we go to the next section. - */ - if (priv_key != NULL) { - /* Make a PKCS#8 shrouded key bag. */ - cryptodebug("create PKCS#8 shrouded key out of private key"); - p8 = EVP_PKEY2PKCS8(priv_key); - if (p8 == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create PKCS#8 shrouded key for " - "private key.")); - (*failures)++; - return (-1); - } - - /* Put the shrouded key into a PKCS#12 bag. */ - cryptodebug("convert shrouded key to PKCS#12 bag"); - bag = PKCS12_MAKE_SHKEYBAG( - NID_pbe_WithSHA1And3_Key_TripleDES_CBC, (char *)pin, - -1, NULL, 0, PKCS12_DEFAULT_ITER, p8); - - /* Clean up the PKCS#8 shrouded key, don't need it now. */ - PKCS8_PRIV_KEY_INFO_free(p8); - p8 = NULL; - - if (bag == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert private key to PKCS#12 bag.")); - (*failures)++; - return (-1); - } - - /* Add the key id to the certificate bag. */ - cryptodebug("add key id to PKCS#12 safebag"); - if (!PKCS12_add_localkeyid(bag, id, id_len)) - cryptodebug("error not caught"); - - /* Add the cert friendly name to the private key bag. */ - if (lab != NULL) { - cryptodebug("label PKCS#12 safebag with friendly name"); - if (!PKCS12_add_friendlyname(bag, (char *)lab, lab_len)) - cryptodebug("error not caught"); - } - - /* Start a PKCS#12 safebag container for the private key. */ - cryptodebug("creating private key PKCS#12 safebag"); - bag_stack = sk_PKCS12_SAFEBAG_new_null(); - if (bag_stack == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create PKCS#12 private key bag.")); - (*failures)++; - return (-1); - } - - /* Pile on the private key on the bag_stack. */ - if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) - cryptodebug("error not caught"); - /* Turn bag_stack with private key into unencrypted authsafe. */ - cryptodebug("put private PKCS#12 bag into PKCS#7 authsafe"); - key_authsafe = PKCS12_pack_p7data(bag_stack); +#include <kmfapi.h> - /* Clear away this bag_stack, we're done with it. */ - sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); - bag_stack = NULL; - - if (key_authsafe == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to PKCS#7-convert private key bag.")); - (*failures)++; - return (-1); - } - - n_writes++; - } - - /* - * Section 3: - * - * This is where the two PKCS#7 containers, one for the certificates - * and one for the private key, are put together into a PKCS#12 - * element. This final PKCS#12 element is written to the export file. - */ - /* Start a PKCS#7 stack. */ - cryptodebug("create PKCS#7 authsafe for private key and certificates"); - authsafe_stack = sk_PKCS7_new_null(); - if (authsafe_stack == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create PKCS#7 container for private key " - "and certificates.")); - (*failures)++; - return (-1); - } - - /* Put certificates and private key into PKCS#7 stack. */ - if (key_authsafe != NULL) { - cryptodebug("put private key authsafe into PKCS#7 container"); - if (!sk_PKCS7_push(authsafe_stack, key_authsafe)) - cryptodebug("error not caught"); - } - if (cert_authsafe != NULL) { - cryptodebug("put certificate authsafe into PKCS#7 container"); - if (!sk_PKCS7_push(authsafe_stack, cert_authsafe)) - cryptodebug("error not caught"); - } - - /* Create PKCS#12 element out of PKCS#7 stack. */ - cryptodebug("create PKCS#12 element for export file"); - p12_elem = PKCS12_init(NID_pkcs7_data); - if (p12_elem == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create PKCS#12 element for export file.")); - sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); - (*failures)++; - return (-1); - } - - /* Put the PKCS#7 stack into the PKCS#12 element. */ - if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack)) - cryptodebug("error not caught"); - - /* Clear away the PKCS#7 stack, we're done with it. */ - sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); - authsafe_stack = NULL; - - /* Set the integrity MAC on the PKCS#12 element. */ - cryptodebug("setting MAC for PKCS#12 element"); - if (!PKCS12_set_mac(p12_elem, (char *)pin, -1, NULL, 0, - PKCS12_DEFAULT_ITER, NULL)) - cryptodebug("error not caught"); - - /* Write the PKCS#12 element to the export file. */ - cryptodebug("writing PKCS#12 element to export file"); - if (!i2d_PKCS12_bio(fbio, p12_elem)) - cryptodebug("error not caught"); - - (*successes) += n_writes; - - /* Clear away the PKCS#12 element. */ - PKCS12_free(p12_elem); - return (0); -} - -/* - * Get token objects: private key, its cert, and its cert chain. - */ -static CK_RV -get_token_objs(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, - CK_OBJECT_HANDLE *mate, CK_OBJECT_HANDLE_PTR *chain, - CK_ULONG *chain_len, CK_BYTE_PTR *id, CK_ULONG *id_len) +static KMF_RETURN +pk_find_export_cert(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *parms, + KMF_X509_DER_CERT *cert) { - CK_RV rv = CKR_OK; - CK_ATTRIBUTE keyid_attr[1] = { - { CKA_ID, NULL, 0 } - }; - static CK_OBJECT_CLASS class = CKO_CERTIFICATE; - static CK_CERTIFICATE_TYPE certtype = CKC_X_509; - CK_ATTRIBUTE cert_attr[4] = { - { CKA_CLASS, &class, sizeof (CK_OBJECT_CLASS) }, - { CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) }, - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { CKA_ID, NULL, 0 } - }; - CK_ULONG num_attr = sizeof (cert_attr) / sizeof (CK_ATTRIBUTE); - CK_OBJECT_HANDLE cert = ~0UL; - CK_ULONG num = 0; - - cryptodebug("inside get_token_objs"); - - /* Get the size of the object's CKA_ID field first. */ - cryptodebug("getting CKA_ID size for object 0x%x", obj); - if ((rv = C_GetAttributeValue(sess, obj, keyid_attr, 1)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext("Unable to get size of object" - " key id (%s)."), pkcs11_strerror(rv)); - return (rv); - } - - /* Allocate the space needed for the key id. */ - if ((keyid_attr[0].pValue = malloc(keyid_attr[0].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - return (CKR_HOST_MEMORY); - } + KMF_RETURN rv = KMF_OK; + uint32_t numcerts = 0; - /* Get the CKA_ID field to match obj with its cert. */ - cryptodebug("getting CKA_ID attribute for object 0x%x", obj); - if ((rv = C_GetAttributeValue(sess, obj, keyid_attr, 1)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext("Unable to get object " - "key id (%s)."), pkcs11_strerror(rv)); - free(keyid_attr[0].pValue); + numcerts = 0; + (void) memset(cert, 0, sizeof (KMF_X509_DER_CERT)); + rv = KMF_FindCert(kmfhandle, parms, NULL, &numcerts); + if (rv != KMF_OK) { return (rv); } + if (numcerts == 0) { + cryptoerror(LOG_STDERR, + gettext("No matching certificates found.")); + return (KMF_ERR_CERT_NOT_FOUND); - /* Now try to find any certs that have the same id. */ - cryptodebug("searching for certificates with same CKA_ID"); - cert_attr[3].pValue = keyid_attr[0].pValue; - cert_attr[3].ulValueLen = keyid_attr[0].ulValueLen; - if ((rv = C_FindObjectsInit(sess, cert_attr, num_attr)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext("Unable to initialize " - "certificate search (%s)."), pkcs11_strerror(rv)); - free(keyid_attr[0].pValue); - return (rv); - } + } else if (numcerts == 1) { + rv = KMF_FindCert(kmfhandle, parms, cert, &numcerts); - /* Find the first cert that matches the key id. */ - if ((rv = C_FindObjects(sess, &cert, 1, &num)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext("Certificate search failed " - "(%s)."), pkcs11_strerror(rv)); - free(keyid_attr[0].pValue); - return (rv); + } else if (numcerts > 1) { + cryptoerror(LOG_STDERR, + gettext("%d certificates found, refine the " + "search parameters to eliminate ambiguity\n"), + numcerts); + return (KMF_ERR_BAD_PARAMETER); } - - (void) C_FindObjectsFinal(sess); - - *id = keyid_attr[0].pValue; - *id_len = keyid_attr[0].ulValueLen; - - *mate = (num == 1) ? cert : ~0UL; - - /* We currently do not find all the certs in the chain. */ - *chain_len = 0; - *chain = NULL; - - return (CKR_OK); + return (rv); } -/* - * Converts PKCS#11 biginteger_t format to OpenSSL BIGNUM. - * "to" should be the address of a ptr init'ed to NULL to - * receive the BIGNUM, e.g., - * biginteger_t from; - * BIGNUM *foo = NULL; - * cvt_bigint2bn(&from, &foo); - */ -static int -cvt_bigint2bn(biginteger_t *from, BIGNUM **to) +static KMF_RETURN +pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass, + char *issuer, char *subject, KMF_BIGINT *serial, + KMF_ENCODE_FORMAT ofmt, + char *dir, char *infile, char *filename) { - BIGNUM *temp = NULL; - - cryptodebug("inside cvt_bigint2bn"); - - if (from == NULL || to == NULL) - return (-1); - - cryptodebug("calling BN_bin2bn"); - if ((temp = BN_bin2bn(from->big_value, from->big_value_len, *to)) == - NULL) - return (-1); - - *to = temp; - return (0); + KMF_RETURN rv = KMF_OK; + KMF_STORECERT_PARAMS scparms; + KMF_X509_DER_CERT kmfcert; + + /* If searching for public objects or certificates, find certs now */ + if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { + KMF_FINDCERT_PARAMS fcargs; + + (void) memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = KMF_KEYSTORE_OPENSSL; + fcargs.certLabel = NULL; + fcargs.issuer = issuer; + fcargs.subject = subject; + fcargs.serial = serial; + fcargs.sslparms.dirpath = dir; + fcargs.sslparms.certfile = infile; + fcargs.sslparms.format = ofmt; + + rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert); + if (rv == KMF_OK) { + (void) memset(&scparms, 0, sizeof (scparms)); + scparms.kstype = KMF_KEYSTORE_OPENSSL; + scparms.sslparms.certfile = filename; + rv = KMF_StoreCert(kmfhandle, &scparms, + &kmfcert.certificate); + + KMF_FreeKMFCert(kmfhandle, &kmfcert); + } + } + return (rv); } -/* - * Convert PKCS#11 RSA private key to OpenSSL EVP_PKEY structure. - */ -static CK_RV -cvt_rsa2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk) +static KMF_RETURN +pk_export_pk12_nss(KMF_HANDLE_T kmfhandle, + char *token_spec, char *dir, char *prefix, + char *certlabel, char *issuer, char *subject, + KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, + char *filename) { - CK_RV rv = CKR_OK; - EVP_PKEY *key = NULL; /* OpenSSL representation */ - RSA *rsa = NULL; /* OpenSSL representation */ - biginteger_t mod = { NULL, 0 }; /* required */ - biginteger_t pubexp = { NULL, 0 }; /* required */ - biginteger_t priexp = { NULL, 0 }; /* optional */ - biginteger_t prime1 = { NULL, 0 }; /* optional */ - biginteger_t prime2 = { NULL, 0 }; /* optional */ - biginteger_t exp1 = { NULL, 0 }; /* optional */ - biginteger_t exp2 = { NULL, 0 }; /* optional */ - biginteger_t coef = { NULL, 0 }; /* optional */ - CK_ATTRIBUTE rsa_pri_attrs[8] = { - { CKA_MODULUS, NULL, 0 }, - { CKA_PUBLIC_EXPONENT, NULL, 0 }, - { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */ - { CKA_PRIME_1, NULL, 0 }, /* | */ - { CKA_PRIME_2, NULL, 0 }, /* | */ - { CKA_EXPONENT_1, NULL, 0 }, /* | */ - { CKA_EXPONENT_2, NULL, 0 }, /* | */ - { CKA_COEFFICIENT, NULL, 0 } /* V */ - }; - CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE); - int i; - - cryptodebug("inside cvt_rsa2evp_pkey"); - - cryptodebug("calling RSA_new"); - if ((rsa = RSA_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal RSA structure.")); - return (CKR_HOST_MEMORY); - } + KMF_RETURN rv = KMF_OK; + KMF_EXPORTP12_PARAMS p12parms; - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, rsa_pri_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get RSA private key attribute sizes (%s)."), - pkcs11_strerror(rv)); + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) return (rv); - } - /* Allocate memory for each attribute. */ - for (i = 0; i < count; i++) { - if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || - rsa_pri_attrs[i].ulValueLen == 0) { - cryptodebug("cvt_rsa2evp_pkey: *** should not happen"); - rsa_pri_attrs[i].ulValueLen = 0; - continue; - } - if ((rsa_pri_attrs[i].pValue = - malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - return (CKR_HOST_MEMORY); - } - } + (void) memset(&p12parms, 0, sizeof (p12parms)); + if (token_spec == NULL) + token_spec = DEFAULT_NSS_TOKEN; - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, rsa_pri_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get RSA private key attributes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } + p12parms.kstype = KMF_KEYSTORE_NSS; + p12parms.certLabel = certlabel; + p12parms.issuer = issuer; + p12parms.subject = subject; + p12parms.serial = serial; + p12parms.idstr = NULL; + if (tokencred != NULL) + p12parms.cred = *tokencred; + p12parms.nssparms.slotlabel = token_spec; - /* - * Fill in all the temp variables. Modulus and public exponent - * are required. The rest are optional. - */ - i = 0; - copy_attr_to_bigint(&(rsa_pri_attrs[i++]), &mod); - copy_attr_to_bigint(&(rsa_pri_attrs[i++]), &pubexp); - - if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && - rsa_pri_attrs[i].ulValueLen != 0) - copy_attr_to_bigint(&(rsa_pri_attrs[i]), &priexp); - i++; - - if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && - rsa_pri_attrs[i].ulValueLen != 0) - copy_attr_to_bigint(&(rsa_pri_attrs[i]), &prime1); - i++; - - if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && - rsa_pri_attrs[i].ulValueLen != 0) - copy_attr_to_bigint(&(rsa_pri_attrs[i]), &prime2); - i++; - - if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && - rsa_pri_attrs[i].ulValueLen != 0) - copy_attr_to_bigint(&(rsa_pri_attrs[i]), &exp1); - i++; - - if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && - rsa_pri_attrs[i].ulValueLen != 0) - copy_attr_to_bigint(&(rsa_pri_attrs[i]), &exp2); - i++; - - if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && - rsa_pri_attrs[i].ulValueLen != 0) - copy_attr_to_bigint(&(rsa_pri_attrs[i]), &coef); - i++; - - /* Start the conversion to internal OpenSSL RSA structure. */ - - /* Modulus n */ - if (cvt_bigint2bn(&mod, &(rsa->n)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key modulus.")); - return (CKR_GENERAL_ERROR); - } + (void) get_pk12_password(&p12parms.p12cred); - /* Public exponent e */ - if (cvt_bigint2bn(&pubexp, &(rsa->e)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key public exponent.")); - return (CKR_GENERAL_ERROR); - } + rv = KMF_ExportPK12(kmfhandle, &p12parms, filename); + if (p12parms.p12cred.cred) + free(p12parms.p12cred.cred); - /* Private exponent e */ - if (priexp.big_value != NULL) { - if (cvt_bigint2bn(&priexp, &(rsa->d)) < 0) { - cryptoerror(LOG_STDERR, gettext("Unable to convert " - "RSA private key private exponent.")); - return (CKR_GENERAL_ERROR); - } - } else - cryptodebug("no RSA private key private exponent"); - - /* Prime p */ - if (prime1.big_value != NULL) { - if (cvt_bigint2bn(&prime1, &(rsa->p)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key prime 1.")); - return (CKR_GENERAL_ERROR); - } - } else - cryptodebug("no RSA private key prime 1"); - - /* Prime q */ - if (prime2.big_value != NULL) { - if (cvt_bigint2bn(&prime2, &(rsa->q)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key prime 2.")); - return (CKR_GENERAL_ERROR); - } - } else - cryptodebug("no RSA private key prime 2"); - - /* Private exponent d modulo p-1 */ - if (exp1.big_value != NULL) { - if (cvt_bigint2bn(&exp1, &(rsa->dmp1)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key exponent 1.")); - return (CKR_GENERAL_ERROR); - } - } else - cryptodebug("no RSA private key exponent 1"); - - /* Private exponent d modulo q-1 */ - if (exp2.big_value != NULL) { - if (cvt_bigint2bn(&exp2, &(rsa->dmq1)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key exponent 2.")); - return (CKR_GENERAL_ERROR); - } - } else - cryptodebug("no RSA private key exponent 2"); - - /* CRT coefficient q-inverse mod p */ - if (coef.big_value != NULL) { - if (cvt_bigint2bn(&coef, &(rsa->iqmp)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key coefficient.")); - return (CKR_GENERAL_ERROR); - } - } else - cryptodebug("no RSA private key coefficient"); - - /* Create OpenSSL EVP_PKEY struct in which to stuff RSA struct. */ - cryptodebug("calling EVP_PKEY_new"); - if ((key = EVP_PKEY_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal EVP_PKEY structure.")); - return (CKR_HOST_MEMORY); - } - - /* Put the RSA struct into the EVP_PKEY struct and return it. */ - cryptodebug("calling EVP_PKEY_set1_RSA"); - (void) EVP_PKEY_set1_RSA(key, rsa); - - *pk = key; - return (CKR_OK); + return (rv); } -/* - * Convert PKCS#11 DSA private key to OpenSSL EVP_PKEY structure. - */ -static CK_RV -cvt_dsa2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk) +static KMF_RETURN +pk_export_pk12_files(KMF_HANDLE_T kmfhandle, + char *certfile, char *keyfile, char *dir, + char *outfile) { - CK_RV rv = CKR_OK; - EVP_PKEY *key = NULL; /* OpenSSL representation */ - DSA *dsa = NULL; /* OpenSSL representation */ - biginteger_t prime = { NULL, 0 }; /* required */ - biginteger_t subprime = { NULL, 0 }; /* required */ - biginteger_t base = { NULL, 0 }; /* required */ - biginteger_t value = { NULL, 0 }; /* required */ - CK_ATTRIBUTE dsa_pri_attrs[4] = { - { CKA_PRIME, NULL, 0 }, - { CKA_SUBPRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE); - int i; - - cryptodebug("inside cvt_dsa2evp_pkey"); - - cryptodebug("calling DSA_new"); - if ((dsa = DSA_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal DSA structure.")); - return (CKR_HOST_MEMORY); - } - - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, dsa_pri_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get DSA private key object attributes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } - - /* Allocate memory for each attribute. */ - for (i = 0; i < count; i++) { - if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || - dsa_pri_attrs[i].ulValueLen == 0) { - cryptodebug("cvt_dsa2evp_pkey: *** should not happen"); - dsa_pri_attrs[i].ulValueLen = 0; - continue; - } - if ((dsa_pri_attrs[i].pValue = - malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - return (CKR_HOST_MEMORY); - } - } - - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, dsa_pri_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get DSA private key attributes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } - - /* Fill in all the temp variables. They are all required. */ - i = 0; - copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &prime); - copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &subprime); - copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &base); - copy_attr_to_bigint(&(dsa_pri_attrs[i++]), &value); - - /* Start the conversion to internal OpenSSL DSA structure. */ + KMF_RETURN rv; + KMF_EXPORTP12_PARAMS p12parms; - /* Prime p */ - if (cvt_bigint2bn(&prime, &(dsa->p)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key prime.")); - return (CKR_GENERAL_ERROR); - } + (void) memset(&p12parms, 0, sizeof (p12parms)); - /* Subprime q */ - if (cvt_bigint2bn(&subprime, &(dsa->q)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key subprime.")); - return (CKR_GENERAL_ERROR); - } + p12parms.kstype = KMF_KEYSTORE_OPENSSL; + p12parms.certLabel = NULL; + p12parms.issuer = NULL; + p12parms.subject = NULL; + p12parms.serial = 0; + p12parms.idstr = NULL; + p12parms.sslparms.dirpath = dir; + p12parms.sslparms.certfile = certfile; + p12parms.sslparms.keyfile = keyfile; - /* Base g */ - if (cvt_bigint2bn(&base, &(dsa->g)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key base.")); - return (CKR_GENERAL_ERROR); - } + (void) get_pk12_password(&p12parms.p12cred); - /* Private key x */ - if (cvt_bigint2bn(&value, &(dsa->priv_key)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key value.")); - return (CKR_GENERAL_ERROR); - } + rv = KMF_ExportPK12(kmfhandle, &p12parms, outfile); - /* Create OpenSSL EVP PKEY struct in which to stuff DSA struct. */ - cryptodebug("calling EVP_PKEY_new"); - if ((key = EVP_PKEY_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal EVP_PKEY structure.")); - return (CKR_HOST_MEMORY); - } - - /* Put the DSA struct into the EVP_PKEY struct and return it. */ - cryptodebug("calling EVP_PKEY_set1_DSA"); - (void) EVP_PKEY_set1_DSA(key, dsa); + if (p12parms.p12cred.cred) + free(p12parms.p12cred.cred); - *pk = key; - return (CKR_OK); + return (rv); } -/* - * Convert PKCS#11 DH private key to OpenSSL EVP_PKEY structure. - */ -static CK_RV -cvt_dh2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk) +static KMF_RETURN +pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec, + int oclass, char *certlabel, char *issuer, char *subject, + KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir, + char *prefix, char *filename) { - CK_RV rv = CKR_OK; - EVP_PKEY *key = NULL; /* OpenSSL representation */ - DH *dh = NULL; /* OpenSSL representation */ - biginteger_t prime = { NULL, 0 }; /* required */ - biginteger_t base = { NULL, 0 }; /* required */ - biginteger_t value = { NULL, 0 }; /* required */ - CK_ATTRIBUTE dh_pri_attrs[3] = { - { CKA_PRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE); - int i; - - cryptodebug("inside cvt_dh2evp_pkey"); - - cryptodebug("calling DH_new"); - if ((dh = DH_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal DH structure.")); - return (CKR_HOST_MEMORY); - } + KMF_RETURN rv = KMF_OK; + KMF_STORECERT_PARAMS scparms; + KMF_X509_DER_CERT kmfcert; - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, dh_pri_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get DH private key object attributes (%s)."), - pkcs11_strerror(rv)); + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) return (rv); - } - /* Allocate memory for each attribute. */ - for (i = 0; i < count; i++) { - if (dh_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || - dh_pri_attrs[i].ulValueLen == 0) { - cryptodebug("cvt_dh2evp_pkey: ***should not happen"); - dh_pri_attrs[i].ulValueLen = 0; - continue; - } - if ((dh_pri_attrs[i].pValue = - malloc(dh_pri_attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - return (CKR_HOST_MEMORY); + /* If searching for public objects or certificates, find certs now */ + if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { + KMF_FINDCERT_PARAMS fcargs; + + (void) memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = KMF_KEYSTORE_NSS; + fcargs.certLabel = certlabel; + fcargs.issuer = issuer; + fcargs.subject = subject; + fcargs.serial = serial; + fcargs.nssparms.slotlabel = token_spec; + + rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert); + if (rv == KMF_OK) { + (void) memset(&scparms, 0, sizeof (scparms)); + scparms.kstype = KMF_KEYSTORE_OPENSSL; + scparms.sslparms.certfile = filename; + scparms.sslparms.format = kfmt; + + rv = KMF_StoreCert(kmfhandle, &scparms, + &kmfcert.certificate); + + KMF_FreeKMFCert(kmfhandle, &kmfcert); } } + return (rv); +} - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, dh_pri_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get DH private key attributes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } - - /* Fill in all the temp variables. They are all required. */ - i = 0; - copy_attr_to_bigint(&(dh_pri_attrs[i++]), &prime); - copy_attr_to_bigint(&(dh_pri_attrs[i++]), &base); - copy_attr_to_bigint(&(dh_pri_attrs[i++]), &value); - - /* Start the conversion to internal OpenSSL DH structure. */ +static KMF_RETURN +pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec, + char *certlabel, char *issuer, char *subject, + KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename) +{ + KMF_RETURN rv = KMF_OK; + KMF_EXPORTP12_PARAMS p12parms; - /* Prime p */ - if (cvt_bigint2bn(&prime, &(dh->p)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DH private key prime.")); - return (CKR_GENERAL_ERROR); + rv = select_token(kmfhandle, token_spec, TRUE); + if (rv != KMF_OK) { + return (rv); } - /* Base g */ - if (cvt_bigint2bn(&base, &(dh->g)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DH private key base.")); - return (CKR_GENERAL_ERROR); - } + (void) memset(&p12parms, 0, sizeof (p12parms)); - /* Private value x */ - if (cvt_bigint2bn(&value, &(dh->priv_key)) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DH private key value.")); - return (CKR_GENERAL_ERROR); - } + p12parms.kstype = KMF_KEYSTORE_PK11TOKEN; + p12parms.certLabel = certlabel; + p12parms.issuer = issuer; + p12parms.subject = subject; + p12parms.serial = serial; + p12parms.idstr = NULL; + if (tokencred != NULL) + p12parms.cred = *tokencred; + (void) get_pk12_password(&p12parms.p12cred); - /* Create OpenSSL EVP PKEY struct in which to stuff DH struct. */ - cryptodebug("calling EVP_PKEY_new"); - if ((key = EVP_PKEY_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal EVP_PKEY structure.")); - return (CKR_HOST_MEMORY); - } + rv = KMF_ExportPK12(kmfhandle, &p12parms, filename); - /* Put the DH struct into the EVP_PKEY struct and return it. */ - cryptodebug("calling EVP_PKEY_set1_DH"); - (void) EVP_PKEY_set1_DH(key, dh); + if (p12parms.p12cred.cred) + free(p12parms.p12cred.cred); - *pk = key; - return (CKR_OK); + return (rv); } -/* - * Convert PKCS#11 private key object to OpenSSL EVP_PKEY structure. - */ -static CK_RV -cvt_obj2evp_pkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, EVP_PKEY **pk) +static KMF_RETURN +pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec, + char *certlabel, char *issuer, char *subject, + KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, + char *filename) { - CK_RV rv = CKR_OK; - static CK_KEY_TYPE keytype = 0; - CK_ATTRIBUTE keytype_attr[1] = { - { CKA_KEY_TYPE, &keytype, sizeof (keytype) } - }; - - cryptodebug("inside cvt_obj2evp_pkey"); - - /* Find out the key type to do the right conversion. */ - cryptodebug("calling C_GetAttributeValue"); - if ((rv = C_GetAttributeValue(sess, obj, keytype_attr, 1)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get token object key type (%s)."), - pkcs11_strerror(rv)); - return (rv); - } + KMF_RETURN rv = KMF_OK; + KMF_FINDCERT_PARAMS fcparms; + KMF_STORECERT_PARAMS scparms; + KMF_X509_DER_CERT kmfcert; - switch (keytype) { - case CKK_RSA: - cryptodebug("converting RSA key"); - return (cvt_rsa2evp_pkey(sess, obj, pk)); - case CKK_DSA: - cryptodebug("converting DSA key"); - return (cvt_dsa2evp_pkey(sess, obj, pk)); - case CKK_DH: - cryptodebug("converting DH key"); - return (cvt_dh2evp_pkey(sess, obj, pk)); - default: - cryptoerror(LOG_STDERR, gettext( - "Private key type 0x%02x conversion not supported."), - keytype); - return (CKR_GENERAL_ERROR); - } -} - -/* - * Convert PKCS#11 certificate object to OpenSSL X509 structure. - */ -static CK_RV -cvt_cert2x509(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, X509 **c) -{ - CK_RV rv = CKR_OK; - X509 *cert = NULL; /* OpenSSL representation */ - X509 *temp_cert = NULL; - CK_BYTE *subject = NULL; - CK_ULONG subject_len = 0; - CK_BYTE *value = NULL; - CK_ULONG value_len = 0; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_BYTE *issuer = NULL; - CK_ULONG issuer_len = 0; - CK_BYTE *serial = NULL; - CK_ULONG serial_len = 0; - CK_ATTRIBUTE cert_attrs[6] = { - { CKA_SUBJECT, NULL, 0 }, /* required */ - { CKA_VALUE, NULL, 0 }, /* required */ - { CKA_LABEL, NULL, 0 }, /* optional */ - { CKA_ID, NULL, 0 }, /* optional */ - { CKA_ISSUER, NULL, 0 }, /* optional */ - { CKA_SERIAL_NUMBER, NULL, 0 } /* optional */ - }; - CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE); - int i = 0; - X509_NAME *ssl_subject = NULL; - X509_NAME *ssl_issuer = NULL; - ASN1_INTEGER *ssl_serial = NULL; - - cryptodebug("inside cvt_cert2x509"); - - cryptodebug("calling X509_new"); - if ((cert = X509_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to allocate internal X509 structure.")); - return (CKR_HOST_MEMORY); - } + rv = select_token(kmfhandle, token_spec, TRUE); - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, cert_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get certificate attribute sizes (%s)."), - pkcs11_strerror(rv)); + if (rv != KMF_OK) { return (rv); } - /* Allocate memory for each attribute. */ - for (i = 0; i < count; i++) { - if (cert_attrs[i].ulValueLen == (CK_ULONG)-1 || - cert_attrs[i].ulValueLen == 0) { - cryptodebug("cvt_cert2x509: *** should not happen"); - cert_attrs[i].ulValueLen = 0; - continue; - } - if ((cert_attrs[i].pValue = malloc(cert_attrs[i].ulValueLen)) - == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - return (CKR_HOST_MEMORY); - } - } + (void) memset(&fcparms, 0, sizeof (fcparms)); + fcparms.kstype = KMF_KEYSTORE_PK11TOKEN; + fcparms.certLabel = certlabel; + fcparms.issuer = issuer; + fcparms.subject = subject; + fcparms.serial = serial; - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, cert_attrs, count)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get certificate attributes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } - - /* - * Fill in all the temp variables. Subject and value are required. - * The rest are optional. - */ - i = 0; - copy_attr_to_string(&(cert_attrs[i++]), &subject, &subject_len); - copy_attr_to_string(&(cert_attrs[i++]), &value, &value_len); - - if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 && - cert_attrs[i].ulValueLen != 0) - copy_attr_to_string(&(cert_attrs[i]), &label, &label_len); - i++; - - if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 && - cert_attrs[i].ulValueLen != 0) - copy_attr_to_string(&(cert_attrs[i]), &id, &id_len); - i++; - - if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 && - cert_attrs[i].ulValueLen != 0) - copy_attr_to_string(&(cert_attrs[i]), &issuer, &issuer_len); - i++; - - if (cert_attrs[i].ulValueLen != (CK_ULONG)-1 && - cert_attrs[i].ulValueLen != 0) - copy_attr_to_string(&(cert_attrs[i]), &serial, &serial_len); - i++; - - /* Start the conversion to internal OpenSSL X509 structure. */ - - /* Subject name (required) */ - cryptodebug("calling d2i_X509_NAME for subject name"); - if ((ssl_subject = d2i_X509_NAME(NULL, - (const unsigned char **) &subject, subject_len)) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert certificate subject name.")); - return (CKR_GENERAL_ERROR); - } - cryptodebug("calling X509_set_subject_name"); - if (!X509_set_subject_name(cert, ssl_subject)) { - cryptoerror(LOG_STDERR, gettext( - "Unable to pack certificate subject name entries.")); - return (CKR_GENERAL_ERROR); - } - - /* Label (optional) */ - cryptodebug("calling X509_alias_set1"); - if (!X509_alias_set1(cert, label, label_len)) - cryptodebug("error not caught"); - - /* Id (optional) */ - cryptodebug("calling X509_keyid_set1"); - if (!X509_keyid_set1(cert, id, id_len)) - cryptodebug("error not caught"); - - /* Issuer name (optional) */ - cryptodebug("calling d2i_X509_NAME for issuer name"); - if ((ssl_issuer = d2i_X509_NAME(NULL, (const unsigned char **) &issuer, - issuer_len)) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert certificate issuer name.")); - return (CKR_GENERAL_ERROR); - } - cryptodebug("calling X509_set_issuer_name"); - if (!X509_set_issuer_name(cert, ssl_issuer)) { - cryptoerror(LOG_STDERR, gettext( - "Unable to pack certificate issuer name entries.")); - return (CKR_GENERAL_ERROR); - } - - /* Serial number (optional) */ - cryptodebug("calling OPENSSL_malloc() for serial number"); - if ((ssl_serial = OPENSSL_malloc(sizeof (ASN1_INTEGER))) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert certificate serial number.")); - return (CKR_HOST_MEMORY); - } - ssl_serial->length = serial_len; - ssl_serial->type = (serial[0] & 0x80) ? V_ASN1_NEG_INTEGER : - V_ASN1_INTEGER; - ssl_serial->data = serial; - ssl_serial->flags = 0; - cryptodebug("calling X509_set_serialNumber"); - if (!X509_set_serialNumber(cert, ssl_serial)) - cryptodebug("error not caught"); - - /* - * Value (required) - * - * The rest of this code takes the CKA_VALUE attribute, converts - * it into a temp OpenSSL X509 structure and picks out the rest - * of the fields we need to convert it back into the current X509 - * structure that will get exported. The reason we don't just - * start with CKA_VALUE is because while the object was in the - * softtoken, it is possible that some of its attributes changed. - * Those changes would not appear in CKA_VALUE and would be lost - * if we started with CKA_VALUE that was saved originally. - */ - cryptodebug("calling d2i_X509 for cert value"); - if ((temp_cert = d2i_X509(NULL, (const unsigned char **) &value, - value_len)) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert main certificate values.")); - return (CKR_GENERAL_ERROR); - } - - /* Transfer these values from temp_cert to cert. */ - cryptodebug("calling X509_set_version/X509_get_version"); - if (!X509_set_version(cert, X509_get_version(temp_cert))) - cryptodebug("error not caught"); - - cryptodebug("calling X509_set_notBefore/X509_get_notBefore"); - if (!X509_set_notBefore(cert, X509_get_notBefore(temp_cert))) - cryptodebug("error not caught"); - - cryptodebug("calling X509_set_notAfter/X509_get_notAfter"); - if (!X509_set_notAfter(cert, X509_get_notAfter(temp_cert))) - cryptodebug("error not caught"); - - cryptodebug("calling X509_set_pubkey/X509_get_pubkey"); - if (!X509_set_pubkey(cert, X509_get_pubkey(temp_cert))) - cryptodebug("error not caught"); - - /* - * These don't get transfered from temp_cert to cert. - * It -appears- that they may get regenerated as needed. - * - * cert->cert_info->signature = dup(temp_cert->cert_info->signature); - * cert->sig_alg = dup(temp_cert->sig_alg); - * cert->signature = dup(temp_cert->signature); - * cert->skid = dup(temp_cert->skid); - * cert->akid = dup(temp_cert->akid); - */ - - *c = cert; - return (CKR_OK); -} - -static CK_RV -convert_token_objs(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, - CK_OBJECT_HANDLE mate, CK_OBJECT_HANDLE *chain, CK_ULONG chain_len, - EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca) -{ - CK_RV rv = CKR_OK; - EVP_PKEY *pk = NULL; - X509 *c = NULL; - X509 *one_ca = NULL; - STACK_OF(X509) *ch = NULL; - int i; + rv = pk_find_export_cert(kmfhandle, &fcparms, &kmfcert); - cryptodebug("inside convert_token_objs"); + if (rv == KMF_OK) { + (void) memset(&scparms, 0, sizeof (scparms)); + scparms.kstype = KMF_KEYSTORE_OPENSSL; + scparms.sslparms.certfile = filename; + scparms.sslparms.format = kfmt; - if ((rv = cvt_obj2evp_pkey(sess, obj, &pk)) != CKR_OK) - return (rv); - - if (mate != ~0UL) { - cryptodebug("converting cert corresponding to private key"); - if ((rv = cvt_cert2x509(sess, mate, &c)) != CKR_OK) - return (rv); - } + rv = KMF_StoreCert(kmfhandle, &scparms, + &kmfcert.certificate); - if (chain_len != 0) { - cryptodebug("converting ca chain of %d certs corresponding " - "to private key", chain_len); - ch = sk_X509_new_null(); - for (i = 0; i < chain_len; i++) { - if ((rv = cvt_cert2x509(sess, chain[i], &one_ca)) != - CKR_OK) { - return (rv); - } - if (!sk_X509_push(ch, one_ca)) - cryptodebug("error not caught"); - } + KMF_FreeKMFCert(kmfhandle, &kmfcert); } - - *priv_key = pk; - *cert = (mate != ~0UL) ? c : NULL; - *ca = (chain_len != 0) ? ch : NULL; - return (CKR_OK); + return (rv); } /* - * Export objects from token to PKCS#12 file. + * Export objects from one keystore to a file. */ int pk_export(int argc, char *argv[]) @@ -1210,231 +304,263 @@ pk_export(int argc, char *argv[]) extern int optind_av; extern char *optarg_av; char *token_spec = NULL; - char *token_name = NULL; - char *manuf_id = NULL; - char *serial_no = NULL; - char full_name[FULL_NAME_LEN]; char *filename = NULL; - CK_SLOT_ID slot_id; - CK_FLAGS pin_state; - CK_UTF8CHAR_PTR pin = NULL; - CK_ULONG pinlen = 0; - CK_UTF8CHAR_PTR pk12pin = NULL; - CK_ULONG pk12pinlen = 0; - CK_SESSION_HANDLE sess; - BIO *fbio = NULL; - EVP_PKEY *priv_key = NULL; - X509 *cert = NULL; - STACK_OF(X509) *ca = NULL; - CK_RV rv = CKR_OK; - CK_OBJECT_HANDLE *objs = NULL; - CK_ULONG num_objs = 0; - CK_OBJECT_HANDLE mate = ~0UL; - CK_OBJECT_HANDLE *chain = NULL; - CK_ULONG chain_len; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - int i = 0; - int good_ones = 0, bad_ones = 0; /* running totals */ - - cryptodebug("inside pk_export"); + char *dir = NULL; + char *prefix = NULL; + char *certlabel = NULL; + char *subject = NULL; + char *issuer = NULL; + char *infile = NULL; + char *keyfile = NULL; + char *certfile = NULL; + char *serstr = NULL; + KMF_KEYSTORE_TYPE kstype = 0; + KMF_ENCODE_FORMAT kfmt = KMF_FORMAT_PKCS12; + KMF_RETURN rv = KMF_OK; + int oclass = PK_CERT_OBJ; + KMF_BIGINT serial = { NULL, 0 }; + KMF_HANDLE_T kmfhandle = NULL; + KMF_CREDENTIAL tokencred = {NULL, 0}; /* Parse command line options. Do NOT i18n/l10n. */ - while ((opt = getopt_av(argc, argv, "T:(token)o:(outfile)")) != EOF) { + while ((opt = getopt_av(argc, argv, + "k:(keystore)y:(objtype)T:(token)" + "d:(dir)p:(prefix)" + "l:(label)n:(nickname)s:(subject)" + "i:(issuer)S:(serial)" + "K:(keyfile)c:(certfile)" + "F:(outformat)" + "I:(infile)o:(outfile)")) != EOF) { + if (EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); switch (opt) { + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 'y': + oclass = OT2Int(optarg_av); + if (oclass == -1) + return (PK_ERR_USAGE); + break; case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; + case 'd': + if (dir) + return (PK_ERR_USAGE); + dir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + case 'n': + case 'l': + if (certlabel) + return (PK_ERR_USAGE); + certlabel = optarg_av; + break; + case 's': + if (subject) + return (PK_ERR_USAGE); + subject = optarg_av; + break; + case 'i': + if (issuer) + return (PK_ERR_USAGE); + issuer = optarg_av; + break; + case 'S': + serstr = optarg_av; + break; + case 'F': + kfmt = Str2Format(optarg_av); + if (kfmt == KMF_FORMAT_UNDEF) + return (PK_ERR_USAGE); + break; + case 'I': /* output file name */ + if (infile) + return (PK_ERR_USAGE); + infile = optarg_av; + break; case 'o': /* output file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; + case 'c': /* input cert file name */ + if (certfile) + return (PK_ERR_USAGE); + certfile = optarg_av; + break; + case 'K': /* input key file name */ + if (keyfile) + return (PK_ERR_USAGE); + keyfile = optarg_av; + break; default: return (PK_ERR_USAGE); break; } } - /* If nothing is specified, default is to use softtoken. */ - if (token_spec == NULL) { - token_name = SOFT_TOKEN_LABEL; - manuf_id = SOFT_MANUFACTURER_ID; - serial_no = SOFT_TOKEN_SERIAL; - } else { - /* - * Parse token specifier into token_name, manuf_id, serial_no. - * Token_name is required; manuf_id and serial_no are optional. - */ - if (parse_token_spec(token_spec, &token_name, &manuf_id, - &serial_no) < 0) - return (PK_ERR_USAGE); - } + /* Assume keystore = PKCS#11 if not specified */ + if (kstype == 0) + kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ - if (filename == NULL) + if (EMPTYSTRING(filename)) { + cryptoerror(LOG_STDERR, gettext("You must specify " + "an 'outfile' parameter when exporting.\n")); return (PK_ERR_USAGE); + } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); - /* Done parsing command line options. */ + + /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ + if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && + kstype != KMF_KEYSTORE_PK11TOKEN) { + + (void) fprintf(stderr, gettext("The objtype parameter " + "is only relevant if keystore=pkcs11\n")); + return (PK_ERR_USAGE); + } + + if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) + token_spec = PK_DEFAULT_PK11TOKEN; + else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) + token_spec = DEFAULT_NSS_TOKEN; + + if (kstype == KMF_KEYSTORE_OPENSSL) { + if (kfmt != KMF_FORMAT_PKCS12) { + cryptoerror(LOG_STDERR, gettext("PKCS12 " + "is the only export format " + "supported for the 'file' " + "keystore.\n")); + return (PK_ERR_USAGE); + } + if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { + cryptoerror(LOG_STDERR, gettext("A cert file" + "and a key file must be specified " + "when exporting to PKCS12 from the " + "'file' keystore.\n")); + return (PK_ERR_USAGE); + } + } /* Check if the file exists and might be overwritten. */ if (access(filename, F_OK) == 0) { - cryptoerror(LOG_STDERR, gettext("Warning: file \"%s\" exists, " - "will be overwritten."), filename); + cryptoerror(LOG_STDERR, + gettext("Warning: file \"%s\" exists, " + "will be overwritten."), filename); if (yesno(gettext("Continue with export? "), gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { return (0); } + } else { + rv = verify_file(filename); + if (rv != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("The file (%s) " + "cannot be created.\n"), filename); + return (PK_ERR_USAGE); + } } - full_token_name(token_name, manuf_id, serial_no, full_name); - - /* Find the slot with token. */ - if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id, - &pin_state)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to find token %s (%s)."), full_name, - pkcs11_strerror(rv)); - return (PK_ERR_PK11); - } - - /* Get the user's PIN. */ - if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin, - &pinlen)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get token passphrase (%s)."), - pkcs11_strerror(rv)); - quick_finish(NULL); - return (PK_ERR_PK11); - } - - /* Assume user must be logged in R/W to export objects from token. */ - if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) != - CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to log into token (%s)."), - pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); - } + if (serstr != NULL) { + uchar_t *bytes = NULL; + size_t bytelen; - /* Collect all private keys first. */ - if ((rv = find_objs(sess, PK_PRIVATE_OBJ|PK_KEY_OBJ, NULL, - &objs, &num_objs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to retrieve private key token objects (%s)."), - pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); + rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen); + if (rv != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, gettext("serial number " + "must be specified as a hex number " + "(ex: 0x0102030405ffeeddee)\n")); + return (PK_ERR_USAGE); + } + serial.val = bytes; + serial.len = bytelen; } - /* Nothing to do? */ - if (num_objs == 0) { - cryptoerror(LOG_STDERR, gettext("No objects found.")); - quick_finish(sess); - return (0); + if ((kstype == KMF_KEYSTORE_PK11TOKEN || + kstype == KMF_KEYSTORE_NSS) && + (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ) || + kfmt == KMF_FORMAT_PKCS12)) { + (void) get_token_password(kstype, token_spec, + &tokencred); } - /* Setup OpenSSL context. */ - PKTOOL_setup_openssl(); - - /* Create PKCS#12 file. */ - if ((create_pkcs12(filename, &fbio)) < 0) { - cryptoerror(LOG_STDERR, gettext("No export file created.")); - quick_finish(sess); - return (PK_ERR_SYSTEM); + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Error initializing " + "KMF: 0x%02x\n"), rv); + return (rv); } - /* Get the PIN for the PKCS#12 export file. */ - if ((rv = get_pin(gettext("Create export file passphrase:"), gettext( - "Re-enter export file passphrase:"), &pk12pin, &pk12pinlen)) != - CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to get export file passphrase (%s)."), - pkcs11_strerror(rv)); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_PK11); + switch (kstype) { + case KMF_KEYSTORE_PK11TOKEN: + if (kfmt == KMF_FORMAT_PKCS12) + rv = pk_export_pk12_pk11( + kmfhandle, + token_spec, + certlabel, + issuer, subject, + &serial, &tokencred, + filename); + else + rv = pk_export_pk11_objects(kmfhandle, + token_spec, + certlabel, + issuer, subject, + &serial, kfmt, + filename); + break; + case KMF_KEYSTORE_NSS: + if (dir == NULL) + dir = PK_DEFAULT_DIRECTORY; + if (kfmt == KMF_FORMAT_PKCS12) + rv = pk_export_pk12_nss(kmfhandle, + token_spec, dir, prefix, + certlabel, issuer, + subject, &serial, + &tokencred, filename); + else + rv = pk_export_nss_objects(kmfhandle, + token_spec, + oclass, certlabel, issuer, subject, + &serial, kfmt, dir, prefix, filename); + break; + case KMF_KEYSTORE_OPENSSL: + if (kfmt == KMF_FORMAT_PKCS12) + rv = pk_export_pk12_files(kmfhandle, + certfile, keyfile, dir, + filename); + else + rv = pk_export_file_objects(kmfhandle, oclass, + issuer, subject, &serial, kfmt, + dir, infile, filename); + break; + default: + rv = PK_ERR_USAGE; + break; } - for (i = 0; i < num_objs; i++) { - /* Get a private key and its certificate and CA chain. */ - if ((rv = get_token_objs(sess, objs[i], &mate, &chain, - &chain_len, &id, &id_len)) != CKR_OK) { - /* - * Note this "rv" is either CKR_OK or !CKR_OK. The - * real error codes/messages are handled inside - * read_token_objs(). - */ - cryptoerror(LOG_STDERR, - gettext("Unable to get token objects.")); - free(id); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_PK11); - } - - /* Convert to OpenSSL equivalents. */ - if ((rv = convert_token_objs(sess, objs[i], mate, chain, - chain_len, &priv_key, &cert, &ca)) != CKR_OK) { - /* - * Note this "rv" is either CKR_OK or !CKR_OK. The - * real error codes/messages are handled inside - * read_token_objs(). - */ - cryptoerror(LOG_STDERR, - gettext("Unable to convert token objects.")); - free(id); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_PK11); - } - - /* - * When exporting of cert chains is implemented, these - * messages should be updated accordingly. - */ - if (mate == ~0UL) - (void) fprintf(stdout, gettext( - "Writing object #%d...\n"), i+1); - else - (void) fprintf(stdout, gettext("Writing object #%d " - "and its certificate...\n"), i+1); - - /* Write object and its certs to the PKCS#12 export file. */ - if (write_objs_pkcs12(fbio, pk12pin, pk12pinlen, id, id_len, - priv_key, cert, ca, &good_ones, &bad_ones) < 0) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write object #%d to export file."), i+1); - sk_X509_pop_free(ca, X509_free); - free(id); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_OPENSSL); - } - - /* Destroy key id and CA cert chain, done with them. */ - free(id); - id = NULL; - sk_X509_pop_free(ca, X509_free); - ca = NULL; + if (rv != KMF_OK) { + display_error(kmfhandle, rv, + gettext("Error exporting objects")); } - (void) fprintf(stdout, gettext( - "%d token objects exported, %d errors occurred.\n"), - good_ones, bad_ones); + if (serial.val != NULL) + free(serial.val); - /* Close PKCS#12 file. */ - close_pkcs12(fbio); + (void) KMF_Finalize(kmfhandle); - /* Clean up. */ - quick_finish(sess); - return (0); + return (rv); } diff --git a/usr/src/cmd/cmd-crypto/pktool/gencert.c b/usr/src/cmd/cmd-crypto/pktool/gencert.c new file mode 100644 index 0000000000..ae79c579a4 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/pktool/gencert.c @@ -0,0 +1,729 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <malloc.h> +#include <libgen.h> +#include <errno.h> +#include <cryptoutil.h> +#include <security/cryptoki.h> +#include "common.h" + +#include <kmfapi.h> + +#define SET_VALUE(f, s) \ + kmfrv = f; \ + if (kmfrv != KMF_OK) { \ + cryptoerror(LOG_STDERR, \ + gettext("Failed to set %s: 0x%02x\n"), \ + s, kmfrv); \ + goto cleanup; \ + } + +static int +gencert_pkcs11(KMF_HANDLE_T kmfhandle, + char *token, char *subject, char *altname, + KMF_GENERALNAMECHOICES alttype, int altcrit, + char *certlabel, KMF_KEY_ALG keyAlg, + KMF_ALGORITHM_INDEX sigAlg, + int keylen, uint32_t ltime, KMF_BIGINT *serial, + uint16_t kubits, int kucrit, KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN kmfrv = KMF_OK; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_STORECERT_PARAMS sc_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_CERTIFICATE signedCert; + KMF_X509_NAME certSubject; + KMF_X509_NAME certIssuer; + KMF_DATA x509DER; + + (void) memset(&signedCert, 0, sizeof (signedCert)); + (void) memset(&certSubject, 0, sizeof (certSubject)); + (void) memset(&certIssuer, 0, sizeof (certIssuer)); + (void) memset(&x509DER, 0, sizeof (x509DER)); + (void) memset(&kp_params, 0, sizeof (kp_params)); + + /* If the subject name cannot be parsed, flag it now and exit */ + if (KMF_DNParser(subject, &certSubject) != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Subject name cannot be parsed.\n")); + return (PK_ERR_USAGE); + } + + /* For a self-signed cert, the issuser and subject are the same */ + if (KMF_DNParser(subject, &certIssuer) != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Subject name cannot be parsed.\n")); + return (PK_ERR_USAGE); + } + + kp_params.kstype = KMF_KEYSTORE_PK11TOKEN; + kp_params.keylabel = certlabel; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + kp_params.cred.cred = tokencred->cred; + kp_params.cred.credlen = tokencred->credlen; + + /* Select a PKCS11 token */ + kmfrv = select_token(kmfhandle, token, FALSE); + + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + SET_VALUE(KMF_SetCertPubKey(kmfhandle, &pubk, &signedCert), + "keypair"); + + SET_VALUE(KMF_SetCertVersion(&signedCert, 2), "version number"); + + SET_VALUE(KMF_SetCertSerialNumber(&signedCert, serial), + "serial number"); + + SET_VALUE(KMF_SetCertValidityTimes(&signedCert, NULL, ltime), + "validity time"); + + SET_VALUE(KMF_SetCertSignatureAlgorithm(&signedCert, sigAlg), + "signature algorithm"); + + SET_VALUE(KMF_SetCertSubjectName(&signedCert, &certSubject), + "subject name"); + + SET_VALUE(KMF_SetCertIssuerName(&signedCert, &certIssuer), + "issuer name"); + + if (altname != NULL) + SET_VALUE(KMF_SetCertSubjectAltName(&signedCert, altcrit, + alttype, altname), "subjectAltName"); + + if (kubits != 0) + SET_VALUE(KMF_SetCertKeyUsage(&signedCert, kucrit, kubits), + "KeyUsage"); + + if ((kmfrv = KMF_SignCertRecord(kmfhandle, &prik, + &signedCert, &x509DER)) != KMF_OK) { + goto cleanup; + } + + (void) memset(&sc_params, 0, sizeof (sc_params)); + sc_params.kstype = KMF_KEYSTORE_PK11TOKEN; + sc_params.certLabel = certlabel; + + /* + * Store the cert in the DB. + */ + kmfrv = KMF_StoreCert(kmfhandle, &sc_params, &x509DER); + +cleanup: + KMF_FreeData(&x509DER); + KMF_FreeDN(&certSubject); + KMF_FreeDN(&certIssuer); + return (kmfrv); +} + +static int +gencert_file(KMF_HANDLE_T kmfhandle, + KMF_KEY_ALG keyAlg, KMF_ALGORITHM_INDEX sigAlg, + int keylen, KMF_ENCODE_FORMAT fmt, + uint32_t ltime, char *subject, char *altname, + KMF_GENERALNAMECHOICES alttype, int altcrit, + KMF_BIGINT *serial, uint16_t kubits, int kucrit, + char *dir, char *outcert, char *outkey) +{ + KMF_RETURN kmfrv; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_STORECERT_PARAMS sc_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_CERTIFICATE signedCert; + KMF_X509_NAME certSubject; + KMF_X509_NAME certIssuer; + KMF_DATA x509DER; + char *fullcertpath = NULL; + char *fullkeypath = NULL; + + (void) memset(&signedCert, 0, sizeof (signedCert)); + (void) memset(&certSubject, 0, sizeof (certSubject)); + (void) memset(&certIssuer, 0, sizeof (certIssuer)); + (void) memset(&x509DER, 0, sizeof (x509DER)); + (void) memset(&kp_params, 0, sizeof (kp_params)); + (void) memset(&sc_params, 0, sizeof (sc_params)); + + if (EMPTYSTRING(outcert) || EMPTYSTRING(outkey)) { + cryptoerror(LOG_STDERR, + gettext("No output file was specified for " + "the cert or key\n")); + return (PK_ERR_USAGE); + } + if (dir != NULL) { + fullcertpath = get_fullpath(dir, outcert); + if (fullcertpath == NULL) { + cryptoerror(LOG_STDERR, + gettext("Cannot create file %s in " + "directory %s\n"), dir, outcert); + return (PK_ERR_USAGE); + } + } else { + fullcertpath = strdup(outcert); + } + if (verify_file(fullcertpath)) { + cryptoerror(LOG_STDERR, + gettext("Cannot write the indicated output " + "certificate file (%s).\n"), + fullcertpath); + free(fullcertpath); + return (PK_ERR_USAGE); + } + if (dir != NULL) { + fullkeypath = get_fullpath(dir, outkey); + if (fullkeypath == NULL) { + cryptoerror(LOG_STDERR, + gettext("Cannot create file %s in " + "directory %s\n"), dir, outkey); + free(fullcertpath); + return (PK_ERR_USAGE); + } + } else { + fullkeypath = strdup(outkey); + } + if (verify_file(fullkeypath)) { + cryptoerror(LOG_STDERR, + gettext("Cannot write the indicated output " + "key file (%s).\n"), + fullkeypath); + free(fullkeypath); + free(fullcertpath); + return (PK_ERR_USAGE); + } + + /* If the subject name cannot be parsed, flag it now and exit */ + if (KMF_DNParser(subject, &certSubject) != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Subject name cannot be parsed (%s)\n"), + subject); + return (PK_ERR_USAGE); + } + + /* For a self-signed cert, the issuser and subject are the same */ + if (KMF_DNParser(subject, &certIssuer) != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Subject name cannot be parsed (%s)\n"), + subject); + KMF_FreeDN(&certSubject); + return (PK_ERR_USAGE); + } + + kp_params.kstype = KMF_KEYSTORE_OPENSSL; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + + kp_params.sslparms.keyfile = fullkeypath; + kp_params.sslparms.format = fmt; + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + goto cleanup; + } + SET_VALUE(KMF_SetCertPubKey(kmfhandle, &pubk, &signedCert), + "keypair"); + + SET_VALUE(KMF_SetCertVersion(&signedCert, 2), "version number"); + + SET_VALUE(KMF_SetCertSerialNumber(&signedCert, serial), + "serial number"); + + SET_VALUE(KMF_SetCertValidityTimes(&signedCert, NULL, ltime), + "validity time"); + + SET_VALUE(KMF_SetCertSignatureAlgorithm(&signedCert, sigAlg), + "signature algorithm"); + + SET_VALUE(KMF_SetCertSubjectName(&signedCert, &certSubject), + "subject name"); + + SET_VALUE(KMF_SetCertIssuerName(&signedCert, &certIssuer), + "issuer name"); + + if (altname != NULL) + SET_VALUE(KMF_SetCertSubjectAltName(&signedCert, altcrit, + alttype, altname), "subjectAltName"); + + if (kubits != 0) + SET_VALUE(KMF_SetCertKeyUsage(&signedCert, kucrit, kubits), + "KeyUsage"); + + if ((kmfrv = KMF_SignCertRecord(kmfhandle, &prik, + &signedCert, &x509DER)) != KMF_OK) { + goto cleanup; + } + + sc_params.kstype = KMF_KEYSTORE_OPENSSL; + sc_params.sslparms.certfile = fullcertpath; + sc_params.sslparms.keyfile = fullkeypath; + sc_params.sslparms.format = fmt; + /* + * Store the cert in the DB. + */ + kmfrv = KMF_StoreCert(kmfhandle, &sc_params, &x509DER); + +cleanup: + if (fullkeypath != NULL) + free(fullkeypath); + if (fullcertpath != NULL) + free(fullcertpath); + + KMF_FreeData(&x509DER); + KMF_FreeDN(&certSubject); + KMF_FreeDN(&certIssuer); + return (kmfrv); +} + +static KMF_RETURN +gencert_nss(KMF_HANDLE_T kmfhandle, + char *token, char *subject, char *altname, + KMF_GENERALNAMECHOICES alttype, int altcrit, + char *nickname, char *dir, char *prefix, + KMF_KEY_ALG keyAlg, + KMF_ALGORITHM_INDEX sigAlg, + int keylen, char *trust, + uint32_t ltime, KMF_BIGINT *serial, uint16_t kubits, + int kucrit, KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN kmfrv; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_STORECERT_PARAMS sc_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_CERTIFICATE signedCert; + KMF_X509_NAME certSubject; + KMF_X509_NAME certIssuer; + KMF_DATA x509DER; + + if (token == NULL) + token = DEFAULT_NSS_TOKEN; + + kmfrv = configure_nss(kmfhandle, dir, prefix); + if (kmfrv != KMF_OK) + return (kmfrv); + + (void) memset(&signedCert, 0, sizeof (signedCert)); + (void) memset(&certSubject, 0, sizeof (certSubject)); + (void) memset(&certIssuer, 0, sizeof (certIssuer)); + (void) memset(&x509DER, 0, sizeof (x509DER)); + + /* If the subject name cannot be parsed, flag it now and exit */ + if (KMF_DNParser(subject, &certSubject) != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Subject name cannot be parsed.\n")); + return (PK_ERR_USAGE); + } + + /* For a self-signed cert, the issuser and subject are the same */ + if (KMF_DNParser(subject, &certIssuer) != KMF_OK) { + cryptoerror(LOG_STDERR, + gettext("Subject name cannot be parsed.\n")); + return (PK_ERR_USAGE); + } + + (void) memset(&kp_params, 0, sizeof (kp_params)); + + kp_params.kstype = KMF_KEYSTORE_NSS; + kp_params.keylabel = nickname; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + kp_params.cred.cred = tokencred->cred; + kp_params.cred.credlen = tokencred->credlen; + kp_params.nssparms.slotlabel = token; + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + SET_VALUE(KMF_SetCertPubKey(kmfhandle, &pubk, &signedCert), + "keypair"); + + SET_VALUE(KMF_SetCertVersion(&signedCert, 2), "version number"); + + SET_VALUE(KMF_SetCertSerialNumber(&signedCert, serial), + "serial number"); + + SET_VALUE(KMF_SetCertValidityTimes(&signedCert, NULL, ltime), + "validity time"); + + SET_VALUE(KMF_SetCertSignatureAlgorithm(&signedCert, sigAlg), + "signature algorithm"); + + SET_VALUE(KMF_SetCertSubjectName(&signedCert, &certSubject), + "subject name"); + + SET_VALUE(KMF_SetCertIssuerName(&signedCert, &certIssuer), + "issuer name"); + + if (altname != NULL) + SET_VALUE(KMF_SetCertSubjectAltName(&signedCert, altcrit, + alttype, altname), "subjectAltName"); + + if (kubits) + SET_VALUE(KMF_SetCertKeyUsage(&signedCert, kucrit, kubits), + "subjectAltName"); + + if ((kmfrv = KMF_SignCertRecord(kmfhandle, &prik, + &signedCert, &x509DER)) != KMF_OK) { + goto cleanup; + } + + sc_params.kstype = KMF_KEYSTORE_NSS; + sc_params.certLabel = nickname; + sc_params.nssparms.trustflag = trust; + sc_params.nssparms.slotlabel = token; + + /* + * Store the cert in the DB. + */ + kmfrv = KMF_StoreCert(kmfhandle, &sc_params, &x509DER); + +cleanup: + KMF_FreeData(&x509DER); + KMF_FreeDN(&certSubject); + KMF_FreeDN(&certIssuer); + return (kmfrv); +} + +int +pk_gencert(int argc, char *argv[]) +{ + int rv; + int opt; + extern int optind_av; + extern char *optarg_av; + KMF_KEYSTORE_TYPE kstype = 0; + char *subject = NULL; + char *tokenname = NULL; + char *dir = NULL; + char *prefix = NULL; + char *keytype = PK_DEFAULT_KEYTYPE; + int keylen = PK_DEFAULT_KEYLENGTH; + char *trust = NULL; + char *lifetime = NULL; + char *certlabel = NULL; + char *outcert = NULL; + char *outkey = NULL; + char *format = NULL; + char *serstr = NULL; + char *altname = NULL; + char *keyusagestr = NULL; + KMF_GENERALNAMECHOICES alttype = 0; + KMF_BIGINT serial = { NULL, 0 }; + uint32_t ltime; + KMF_HANDLE_T kmfhandle = NULL; + KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; + KMF_KEY_ALG keyAlg = KMF_RSA; + KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA; + boolean_t interactive = B_FALSE; + char *subname = NULL; + KMF_CREDENTIAL tokencred = {NULL, 0}; + uint16_t kubits = 0; + int altcrit = 0, kucrit = 0; + + while ((opt = getopt_av(argc, argv, + "ik:(keystore)s:(subject)n:(nickname)A:(altname)" + "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)" + "r:(trust)L:(lifetime)l:(label)c:(outcert)" + "K:(outkey)S:(serial)F:(format)u:(keyusage)")) != EOF) { + + if (opt != 'i' && EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); + + switch (opt) { + case 'A': + altname = optarg_av; + break; + case 'i': + if (interactive || subject) + return (PK_ERR_USAGE); + else + interactive = B_TRUE; + break; + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 's': + if (interactive || subject) + return (PK_ERR_USAGE); + else + subject = optarg_av; + break; + case 'l': + case 'n': + if (certlabel) + return (PK_ERR_USAGE); + certlabel = optarg_av; + break; + case 'T': + if (tokenname) + return (PK_ERR_USAGE); + tokenname = optarg_av; + break; + case 'd': + if (dir) + return (PK_ERR_USAGE); + dir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + case 't': + keytype = optarg_av; + break; + case 'u': + keyusagestr = optarg_av; + break; + case 'y': + if (sscanf(optarg_av, "%d", + &keylen) != 1) { + cryptoerror(LOG_STDERR, + gettext("key length must be" + "a numeric value (%s)\n"), + optarg_av); + return (PK_ERR_USAGE); + } + break; + case 'r': + if (trust) + return (PK_ERR_USAGE); + trust = optarg_av; + break; + case 'L': + if (lifetime) + return (PK_ERR_USAGE); + lifetime = optarg_av; + break; + case 'c': + if (outcert) + return (PK_ERR_USAGE); + outcert = optarg_av; + break; + case 'K': + if (outkey) + return (PK_ERR_USAGE); + outkey = optarg_av; + break; + case 'S': + serstr = optarg_av; + break; + case 'F': + if (format) + return (PK_ERR_USAGE); + format = optarg_av; + break; + default: + return (PK_ERR_USAGE); + } + } + + /* No additional args allowed. */ + argc -= optind_av; + argv += optind_av; + if (argc) { + return (PK_ERR_USAGE); + } + + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); + return (PK_ERR_USAGE); + } + + /* Assume keystore = PKCS#11 if not specified. */ + if (kstype == 0) + kstype = KMF_KEYSTORE_PK11TOKEN; + + if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) && + EMPTYSTRING(certlabel)) { + cryptoerror(LOG_STDERR, gettext("A label must be specified " + "to create a self-signed certificate.\n")); + return (PK_ERR_USAGE); + } else if (kstype == KMF_KEYSTORE_OPENSSL && EMPTYSTRING(outcert)) { + cryptoerror(LOG_STDERR, gettext("A certificate filename must " + "be specified to create a self-signed certificate.\n")); + return (PK_ERR_USAGE); + } + + if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { + cryptoerror(LOG_STDERR, + gettext("Error parsing format string (%s).\n"), + format); + return (PK_ERR_USAGE); + } + + if (Str2Lifetime(lifetime, <ime) != 0) { + cryptoerror(LOG_STDERR, + gettext("Error parsing lifetime string\n")); + return (PK_ERR_USAGE); + } + + if (Str2KeyType(keytype, &keyAlg, &sigAlg) != 0) { + cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"), + keytype); + return (PK_ERR_USAGE); + } + + + /* + * Check the subject name. + * If interactive is true, get it now interactively. + */ + if (interactive) { + if (get_subname(&subname) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Failed to get the " + "subject name interactively.\n")); + return (PK_ERR_USAGE); + } + } else { + if (EMPTYSTRING(subject)) { + cryptoerror(LOG_STDERR, gettext("A subject name or " + "-i must be specified to create a self-signed " + "certificate.\n")); + return (PK_ERR_USAGE); + } else { + subname = strdup(subject); + if (subname == NULL) { + cryptoerror(LOG_STDERR, + gettext("Out of memory.\n")); + return (PK_ERR_SYSTEM); + } + } + } + + if (serstr == NULL) { + (void) fprintf(stderr, gettext("A serial number " + "must be specified as a hex number when creating" + " a self-signed certificate " + "(ex: serno=0x0102030405feedface)\n")); + rv = PK_ERR_USAGE; + goto end; + } else { + uchar_t *bytes = NULL; + size_t bytelen; + + rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen); + if (rv != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, gettext("serial number " + "must be specified as a hex number " + "(ex: 0x0102030405ffeeddee)\n")); + rv = PK_ERR_USAGE; + goto end; + } + serial.val = bytes; + serial.len = bytelen; + } + + if (altname != NULL) { + rv = verify_altname(altname, &alttype, &altcrit); + if (rv != KMF_OK) { + (void) fprintf(stderr, gettext("Subject AltName " + "must be specified as a name=value pair. " + "See the man page for details.\n")); + rv = PK_ERR_USAGE; + goto end; + } else { + /* advance the altname past the '=' sign */ + char *p = strchr(altname, '='); + if (p != NULL) + altname = p + 1; + } + } + + if (keyusagestr != NULL) { + rv = verify_keyusage(keyusagestr, &kubits, &kucrit); + if (rv != KMF_OK) { + (void) fprintf(stderr, gettext("KeyUsage " + "must be specified as a comma-separated list. " + "See the man page for details.\n")); + rv = PK_ERR_USAGE; + goto end; + } + } + + if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { + if (tokenname == NULL || !strlen(tokenname)) { + if (kstype == KMF_KEYSTORE_NSS) { + tokenname = "internal"; + } else { + tokenname = PK_DEFAULT_PK11TOKEN; + } + } + + (void) get_token_password(kstype, tokenname, &tokencred); + } + + if (kstype == KMF_KEYSTORE_NSS) { + if (dir == NULL) + dir = PK_DEFAULT_DIRECTORY; + + rv = gencert_nss(kmfhandle, + tokenname, subname, altname, alttype, altcrit, + certlabel, dir, prefix, keyAlg, sigAlg, keylen, + trust, ltime, &serial, kubits, kucrit, &tokencred); + + } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { + rv = gencert_pkcs11(kmfhandle, + tokenname, subname, altname, alttype, altcrit, + certlabel, keyAlg, sigAlg, keylen, ltime, + &serial, kubits, kucrit, &tokencred); + + } else if (kstype == KMF_KEYSTORE_OPENSSL) { + rv = gencert_file(kmfhandle, + keyAlg, sigAlg, keylen, fmt, + ltime, subname, altname, alttype, altcrit, + &serial, kubits, kucrit, dir, outcert, outkey); + } + + if (rv != KMF_OK) + display_error(kmfhandle, rv, + gettext("Error creating certificate and keypair")); +end: + if (subname) + free(subname); + if (tokencred.cred != NULL) + free(tokencred.cred); + + if (serial.val != NULL) + free(serial.val); + + (void) KMF_Finalize(kmfhandle); + return (rv); +} diff --git a/usr/src/cmd/cmd-crypto/pktool/gencsr.c b/usr/src/cmd/cmd-crypto/pktool/gencsr.c new file mode 100644 index 0000000000..fcc00d01c8 --- /dev/null +++ b/usr/src/cmd/cmd-crypto/pktool/gencsr.c @@ -0,0 +1,631 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <malloc.h> +#include <libgen.h> +#include <errno.h> +#include <cryptoutil.h> +#include <security/cryptoki.h> +#include "common.h" + +#include <kmfapi.h> + +#define SET_VALUE(f, s) \ + kmfrv = f; \ + if (kmfrv != KMF_OK) { \ + cryptoerror(LOG_STDERR, \ + gettext("Failed to %s: 0x%02\n"), \ + s, kmfrv); \ + goto cleanup; \ + } + +static KMF_RETURN +gencsr_pkcs11(KMF_HANDLE_T kmfhandle, + char *token, char *subject, char *altname, + KMF_GENERALNAMECHOICES alttype, int altcrit, + char *certlabel, KMF_KEY_ALG keyAlg, + int keylen, + uint16_t kubits, int kucrit, + KMF_ENCODE_FORMAT fmt, char *csrfile, + KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN kmfrv = KMF_OK; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_DELETEKEY_PARAMS dk_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_NAME csrSubject; + KMF_CSR_DATA csr; + KMF_ALGORITHM_INDEX sigAlg; + KMF_DATA signedCsr = {NULL, 0}; + + (void) memset(&csr, 0, sizeof (csr)); + (void) memset(&csrSubject, 0, sizeof (csrSubject)); + (void) memset(&kp_params, 0, sizeof (kp_params)); + + if (keyAlg == KMF_DSA) + sigAlg = KMF_ALGID_SHA1WithDSA; + else + sigAlg = KMF_ALGID_MD5WithRSA; + + + /* If the subject name cannot be parsed, flag it now and exit */ + if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) { + return (kmfrv); + } + + kp_params.kstype = KMF_KEYSTORE_PK11TOKEN; + kp_params.keylabel = certlabel; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + kp_params.cred.cred = tokencred->cred; + kp_params.cred.credlen = tokencred->credlen; + + /* Select a PKCS11 token */ + kmfrv = select_token(kmfhandle, token, FALSE); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "keypair"); + + SET_VALUE(KMF_SetCSRVersion(&csr, 2), "version number"); + + SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), + "subject name"); + + SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg), + "SignatureAlgorithm"); + + if (altname != NULL) { + SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit, + alttype), "SetCSRSubjectAltName"); + } + + if (kubits != 0) { + SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits), + "SetCSRKeyUsage"); + } + + if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) == + KMF_OK) { + kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, csrfile); + } + +cleanup: + (void) KMF_FreeData(&signedCsr); + (void) KMF_FreeKMFKey(kmfhandle, &prik); + /* delete the key */ + (void) memset(&dk_params, 0, sizeof (dk_params)); + dk_params.kstype = KMF_KEYSTORE_PK11TOKEN; + (void) KMF_DeleteKeyFromKeystore(kmfhandle, &dk_params, &pubk); + (void) KMF_FreeSignedCSR(&csr); + + return (kmfrv); +} + +static KMF_RETURN +gencsr_file(KMF_HANDLE_T kmfhandle, + KMF_KEY_ALG keyAlg, + int keylen, KMF_ENCODE_FORMAT fmt, + char *subject, char *altname, KMF_GENERALNAMECHOICES alttype, + int altcrit, uint16_t kubits, int kucrit, + char *dir, char *outcsr, char *outkey) +{ + KMF_RETURN kmfrv; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_NAME csrSubject; + KMF_CSR_DATA csr; + KMF_ALGORITHM_INDEX sigAlg; + KMF_DATA signedCsr = {NULL, 0}; + char *fullcsrpath = NULL; + char *fullkeypath = NULL; + + (void) memset(&csr, 0, sizeof (csr)); + (void) memset(&csrSubject, 0, sizeof (csrSubject)); + (void) memset(&kp_params, 0, sizeof (kp_params)); + + if (EMPTYSTRING(outcsr) || EMPTYSTRING(outkey)) { + cryptoerror(LOG_STDERR, + gettext("No output file was specified for " + "the csr or key\n")); + return (KMF_ERR_BAD_PARAMETER); + } + if (dir != NULL) { + fullcsrpath = get_fullpath(dir, outcsr); + if (fullcsrpath == NULL) { + cryptoerror(LOG_STDERR, + gettext("Cannot create file %s in " + "directory %s\n"), dir, outcsr); + return (PK_ERR_USAGE); + } + } else { + fullcsrpath = strdup(outcsr); + } + if (verify_file(fullcsrpath)) { + cryptoerror(LOG_STDERR, + gettext("Cannot write the indicated output " + "certificate file (%s).\n"), fullcsrpath); + free(fullcsrpath); + return (PK_ERR_USAGE); + } + if (dir != NULL) { + fullkeypath = get_fullpath(dir, outkey); + if (fullkeypath == NULL) { + cryptoerror(LOG_STDERR, + gettext("Cannot create file %s in " + "directory %s\n"), dir, outkey); + free(fullcsrpath); + return (PK_ERR_USAGE); + } + } else { + fullkeypath = strdup(outkey); + } + if (verify_file(fullcsrpath)) { + cryptoerror(LOG_STDERR, + gettext("Cannot write the indicated output " + "key file (%s).\n"), fullkeypath); + free(fullcsrpath); + return (PK_ERR_USAGE); + } + + if (keyAlg == KMF_DSA) + sigAlg = KMF_ALGID_SHA1WithDSA; + else + sigAlg = KMF_ALGID_MD5WithRSA; + + /* If the subject name cannot be parsed, flag it now and exit */ + if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) { + return (kmfrv); + } + + kp_params.kstype = KMF_KEYSTORE_OPENSSL; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + + kp_params.sslparms.keyfile = fullkeypath; + kp_params.sslparms.format = fmt; + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + goto cleanup; + } + SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), + "SetCSRPubKey"); + + SET_VALUE(KMF_SetCSRVersion(&csr, 2), "SetCSRVersion"); + + SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), + "SetCSRSubjectName"); + + SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg), + "SetCSRSignatureAlgorithm"); + + if (altname != NULL) { + SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit, + alttype), "SetCSRSubjectAltName"); + } + if (kubits != NULL) { + SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits), + "SetCSRKeyUsage"); + } + if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) == + KMF_OK) { + kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, fullcsrpath); + } + +cleanup: + if (fullkeypath) + free(fullkeypath); + if (fullcsrpath) + free(fullcsrpath); + + KMF_FreeData(&signedCsr); + KMF_FreeKMFKey(kmfhandle, &prik); + KMF_FreeSignedCSR(&csr); + + return (kmfrv); +} + +static KMF_RETURN +gencsr_nss(KMF_HANDLE_T kmfhandle, + char *token, char *subject, char *altname, + KMF_GENERALNAMECHOICES alttype, int altcrit, + char *nickname, char *dir, char *prefix, + KMF_KEY_ALG keyAlg, int keylen, + uint16_t kubits, int kucrit, + KMF_ENCODE_FORMAT fmt, char *csrfile, + KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN kmfrv; + KMF_CREATEKEYPAIR_PARAMS kp_params; + KMF_KEY_HANDLE pubk, prik; + KMF_X509_NAME csrSubject; + KMF_CSR_DATA csr; + KMF_ALGORITHM_INDEX sigAlg; + KMF_DATA signedCsr = {NULL, 0}; + KMF_DELETEKEY_PARAMS dk_params; + + if (token == NULL) + token = DEFAULT_NSS_TOKEN; + + if (keyAlg == KMF_DSA) + sigAlg = KMF_ALGID_SHA1WithDSA; + else + sigAlg = KMF_ALGID_MD5WithRSA; + + kmfrv = configure_nss(kmfhandle, dir, prefix); + if (kmfrv != KMF_OK) + return (kmfrv); + + (void) memset(&csr, 0, sizeof (csr)); + (void) memset(&csrSubject, 0, sizeof (csrSubject)); + + /* If the subject name cannot be parsed, flag it now and exit */ + if ((kmfrv = KMF_DNParser(subject, &csrSubject)) != KMF_OK) { + return (kmfrv); + } + + (void) memset(&kp_params, 0, sizeof (kp_params)); + + kp_params.kstype = KMF_KEYSTORE_NSS; + kp_params.keylabel = nickname; + kp_params.keylength = keylen; /* bits */ + kp_params.keytype = keyAlg; + kp_params.cred.cred = tokencred->cred; + kp_params.cred.credlen = tokencred->credlen; + kp_params.nssparms.slotlabel = token; + + kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk); + if (kmfrv != KMF_OK) { + goto cleanup; + } + + SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "SetCSRPubKey"); + SET_VALUE(KMF_SetCSRVersion(&csr, 2), "SetCSRVersion"); + SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), + "SetCSRSubjectName"); + SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg), + "SetCSRSignatureAlgorithm"); + + if (altname != NULL) { + SET_VALUE(KMF_SetCSRSubjectAltName(&csr, altname, altcrit, + alttype), "SetCSRSubjectAltName"); + } + if (kubits != NULL) { + SET_VALUE(KMF_SetCSRKeyUsage(&csr, kucrit, kubits), + "SetCSRKeyUsage"); + } + if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) == + KMF_OK) { + kmfrv = KMF_CreateCSRFile(&signedCsr, fmt, csrfile); + } + +cleanup: + (void) KMF_FreeData(&signedCsr); + (void) KMF_FreeKMFKey(kmfhandle, &prik); + /* delete the key */ + (void) memset(&dk_params, 0, sizeof (dk_params)); + dk_params.kstype = KMF_KEYSTORE_NSS; + dk_params.cred.cred = tokencred->cred; + dk_params.cred.credlen = tokencred->credlen; + dk_params.nssparms.slotlabel = token; + (void) KMF_DeleteKeyFromKeystore(kmfhandle, &dk_params, &pubk); + (void) KMF_FreeSignedCSR(&csr); + + return (kmfrv); +} + +int +pk_gencsr(int argc, char *argv[]) +{ + KMF_RETURN rv; + int opt; + extern int optind_av; + extern char *optarg_av; + KMF_KEYSTORE_TYPE kstype = 0; + char *subject = NULL; + char *tokenname = NULL; + char *dir = NULL; + char *prefix = NULL; + int keylen = PK_DEFAULT_KEYLENGTH; + char *certlabel = NULL; + char *outcsr = NULL; + char *outkey = NULL; + char *format = NULL; + char *altname = NULL; + char *kustr = NULL; + uint16_t kubits = 0; + char *keytype = PK_DEFAULT_KEYTYPE; + KMF_HANDLE_T kmfhandle = NULL; + KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1; + KMF_KEY_ALG keyAlg = KMF_RSA; + KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA; + boolean_t interactive = B_FALSE; + char *subname = NULL; + KMF_CREDENTIAL tokencred = {NULL, 0}; + KMF_GENERALNAMECHOICES alttype = 0; + int altcrit = 0, kucrit = 0; + + while ((opt = getopt_av(argc, argv, + "ik:(keystore)s:(subject)n:(nickname)A:(altname)" + "u:(keyusage)T:(token)d:(dir)p:(prefix)t:(keytype)" + "y:(keylen)l:(label)c:(outcsr)" + "K:(outkey)F:(format)")) != EOF) { + + if (opt != 'i' && EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); + + switch (opt) { + case 'A': + altname = optarg_av; + break; + case 'i': + if (interactive || subject) + return (PK_ERR_USAGE); + else + interactive = B_TRUE; + break; + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 's': + if (interactive || subject) + return (PK_ERR_USAGE); + else + subject = optarg_av; + break; + case 'l': + case 'n': + if (certlabel) + return (PK_ERR_USAGE); + certlabel = optarg_av; + break; + case 'T': + if (tokenname) + return (PK_ERR_USAGE); + tokenname = optarg_av; + break; + case 'd': + dir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + case 't': + keytype = optarg_av; + break; + case 'u': + kustr = optarg_av; + break; + case 'y': + if (sscanf(optarg_av, "%d", + &keylen) != 1) { + cryptoerror(LOG_STDERR, + gettext("Unrecognized " + "key length (%s)\n"), + optarg_av); + return (PK_ERR_USAGE); + } + break; + case 'c': + if (outcsr) + return (PK_ERR_USAGE); + outcsr = optarg_av; + break; + case 'K': + if (outkey) + return (PK_ERR_USAGE); + outkey = optarg_av; + break; + case 'F': + if (format) + return (PK_ERR_USAGE); + format = optarg_av; + break; + default: + cryptoerror(LOG_STDERR, gettext( + "unrecognized gencsr option '%s'\n"), + argv[optind_av]); + return (PK_ERR_USAGE); + } + } + /* No additional args allowed. */ + argc -= optind_av; + argv += optind_av; + if (argc) { + return (PK_ERR_USAGE); + } + + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); + return (PK_ERR_USAGE); + } + + /* Assume keystore = PKCS#11 if not specified. */ + if (kstype == 0) + kstype = KMF_KEYSTORE_PK11TOKEN; + + if (EMPTYSTRING(outcsr)) { + (void) printf(gettext("A filename must be specified to hold" + "the final certificate request data.\n")); + return (PK_ERR_USAGE); + } else { + /* + * verify that the outcsr file does not already exist + * and that it can be created. + */ + rv = verify_file(outcsr); + if (rv != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("output file (%s) " + "cannot be created.\n"), outcsr); + return (PK_ERR_USAGE); + } + } + + if ((kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) && + EMPTYSTRING(certlabel)) { + cryptoerror(LOG_STDERR, gettext("A label must be specified " + "to create a certificate request.\n")); + return (PK_ERR_USAGE); + } else if (kstype == KMF_KEYSTORE_OPENSSL && EMPTYSTRING(outkey)) { + cryptoerror(LOG_STDERR, gettext("A key filename must be " + "specified to create a certificate request.\n")); + return (PK_ERR_USAGE); + } + + if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) { + cryptoerror(LOG_STDERR, + gettext("Error parsing format string (%s).\n"), + format); + return (PK_ERR_USAGE); + } + if (format && fmt != KMF_FORMAT_ASN1 && fmt != KMF_FORMAT_PEM) { + cryptoerror(LOG_STDERR, + gettext("CSR must be DER or PEM format.\n")); + return (PK_ERR_USAGE); + } + + /* + * Check the subject name. + * If interactive is true, get it now interactively. + */ + if (interactive) { + if (get_subname(&subname) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Failed to get the " + "subject name interactively.\n")); + return (PK_ERR_USAGE); + } + } else { + if (EMPTYSTRING(subject)) { + cryptoerror(LOG_STDERR, gettext("A subject name or " + "-i must be specified to create a certificate " + "request.\n")); + return (PK_ERR_USAGE); + } else { + subname = strdup(subject); + if (subname == NULL) { + cryptoerror(LOG_STDERR, + gettext("Out of memory.\n")); + return (PK_ERR_SYSTEM); + } + } + } + if (altname != NULL) { + rv = verify_altname(altname, &alttype, &altcrit); + if (rv != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Subject AltName " + "must be specified as a name=value pair. " + "See the man page for details.")); + goto end; + } else { + /* advance the altname past the '=' sign */ + char *p = strchr(altname, '='); + if (p != NULL) + altname = p + 1; + } + } + + if (kustr != NULL) { + rv = verify_keyusage(kustr, &kubits, &kucrit); + if (rv != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("KeyUsage " + "must be specified as a comma-separated list. " + "See the man page for details.")); + goto end; + } + } + if ((rv = Str2KeyType(keytype, &keyAlg, &sigAlg)) != 0) { + cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"), + keytype); + goto end; + } + + if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) { + if (tokenname == NULL || !strlen(tokenname)) { + if (kstype == KMF_KEYSTORE_NSS) { + tokenname = "internal"; + } else { + tokenname = PK_DEFAULT_PK11TOKEN; + } + } + + (void) get_token_password(kstype, tokenname, &tokencred); + } + + if (kstype == KMF_KEYSTORE_NSS) { + if (dir == NULL) + dir = PK_DEFAULT_DIRECTORY; + + rv = gencsr_nss(kmfhandle, + tokenname, subname, altname, alttype, altcrit, + certlabel, dir, prefix, + keyAlg, keylen, kubits, kucrit, + fmt, outcsr, &tokencred); + + } else if (kstype == KMF_KEYSTORE_PK11TOKEN) { + rv = gencsr_pkcs11(kmfhandle, + tokenname, subname, altname, alttype, altcrit, + certlabel, keyAlg, keylen, + kubits, kucrit, fmt, outcsr, &tokencred); + + } else if (kstype == KMF_KEYSTORE_OPENSSL) { + rv = gencsr_file(kmfhandle, + keyAlg, keylen, fmt, subname, altname, + alttype, altcrit, kubits, kucrit, + dir, outcsr, outkey); + } + +end: + if (rv != KMF_OK) + display_error(kmfhandle, rv, + gettext("Error creating CSR or keypair")); + + if (subname) + free(subname); + + if (tokencred.cred != NULL) + free(tokencred.cred); + + (void) KMF_Finalize(kmfhandle); + if (rv != KMF_OK) + return (PK_ERR_USAGE); + + return (0); +} diff --git a/usr/src/cmd/cmd-crypto/pktool/genkey.c b/usr/src/cmd/cmd-crypto/pktool/genkey.c new file mode 100644 index 0000000000..f94093029e --- /dev/null +++ b/usr/src/cmd/cmd-crypto/pktool/genkey.c @@ -0,0 +1,450 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <malloc.h> +#include <libgen.h> +#include <errno.h> +#include <cryptoutil.h> +#include <security/cryptoki.h> +#include "common.h" +#include <kmfapi.h> + + +static KMF_RETURN +genkey_nss(KMF_HANDLE_T kmfhandle, char *token, char *dir, char *prefix, + char *keylabel, KMF_KEY_ALG keyAlg, int keylen, KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN kmfrv = KMF_OK; + KMF_CREATESYMKEY_PARAMS csk_params; + KMF_KEY_HANDLE key; + + if (keylabel == NULL) { + cryptoerror(LOG_STDERR, + gettext("A key label must be specified \n")); + return (KMF_ERR_BAD_PARAMETER); + } + + kmfrv = configure_nss(kmfhandle, dir, prefix); + if (kmfrv != KMF_OK) + return (kmfrv); + + (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE)); + csk_params.kstype = KMF_KEYSTORE_NSS; + csk_params.nssparms.slotlabel = token; + csk_params.keytype = keyAlg; + csk_params.keylength = keylen; + csk_params.keylabel = keylabel; + csk_params.cred.cred = tokencred->cred; + csk_params.cred.credlen = tokencred->credlen; + kmfrv = KMF_CreateSymKey(kmfhandle, &csk_params, &key); + + return (kmfrv); +} + +static KMF_RETURN +genkey_pkcs11(KMF_HANDLE_T kmfhandle, char *token, + char *keylabel, KMF_KEY_ALG keyAlg, int keylen, + char *senstr, char *extstr, boolean_t print_hex, + KMF_CREDENTIAL *tokencred) +{ + KMF_RETURN kmfrv = KMF_OK; + KMF_CREATESYMKEY_PARAMS params; + KMF_KEY_HANDLE key; + KMF_RAW_SYM_KEY *rkey = NULL; + boolean_t sensitive = B_FALSE; + boolean_t not_extractable = B_FALSE; + char *hexstr = NULL; + int hexstrlen; + + if (keylabel == NULL) { + cryptoerror(LOG_STDERR, + gettext("A key label must be specified \n")); + return (KMF_ERR_BAD_PARAMETER); + } + + /* Check the sensitive option value if specified. */ + if (senstr != NULL) { + if (tolower(senstr[0]) == 'y') + sensitive = B_TRUE; + else if (tolower(senstr[0]) == 'n') + sensitive = B_FALSE; + else { + cryptoerror(LOG_STDERR, + gettext("Incorrect sensitive option value.\n")); + return (KMF_ERR_BAD_PARAMETER); + } + } + + /* Check the extractable option value if specified. */ + if (extstr != NULL) { + if (tolower(extstr[0]) == 'y') + not_extractable = B_FALSE; + else if (tolower(extstr[0]) == 'n') + not_extractable = B_TRUE; + else { + cryptoerror(LOG_STDERR, + gettext("Incorrect extractable option value.\n")); + return (KMF_ERR_BAD_PARAMETER); + } + } + + /* Select a PKCS11 token first */ + kmfrv = select_token(kmfhandle, token, FALSE); + if (kmfrv != KMF_OK) { + return (kmfrv); + } + + (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE)); + params.kstype = KMF_KEYSTORE_PK11TOKEN; + params.keytype = keyAlg; + params.keylength = keylen; /* bits */ + params.keylabel = keylabel; + params.pkcs11parms.sensitive = sensitive; + params.pkcs11parms.not_extractable = not_extractable; + params.cred.cred = tokencred->cred; + params.cred.credlen = tokencred->credlen; + kmfrv = KMF_CreateSymKey(kmfhandle, ¶ms, &key); + if (kmfrv != KMF_OK) { + goto out; + } + + if (print_hex) { + if (sensitive == B_TRUE || not_extractable == B_TRUE) { + cryptoerror(LOG_STDERR, + gettext("Warning: can not reveal the key value " + "for a sensitive or non-extractable key.\n")); + goto out; + } else { + rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); + if (rkey == NULL) { + kmfrv = KMF_ERR_MEMORY; + goto out; + } + (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); + kmfrv = KMF_GetSymKeyValue(kmfhandle, &key, rkey); + if (kmfrv != KMF_OK) { + goto out; + } + hexstrlen = 2 * rkey->keydata.len + 1; + hexstr = malloc(hexstrlen); + if (hexstr == NULL) { + kmfrv = KMF_ERR_MEMORY; + goto out; + } + + tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr, + hexstrlen); + (void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr); + } + } + +out: + KMF_FreeRawSymKey(rkey); + + if (hexstr != NULL) + free(hexstr); + + return (kmfrv); +} + + +static KMF_RETURN +genkey_file(KMF_HANDLE_T kmfhandle, KMF_KEY_ALG keyAlg, int keylen, char *dir, + char *outkey, boolean_t print_hex) +{ + KMF_RETURN kmfrv = KMF_OK; + KMF_CREATESYMKEY_PARAMS csk_params; + KMF_KEY_HANDLE key; + KMF_RAW_SYM_KEY *rkey = NULL; + char *hexstr = NULL; + int hexstrlen; + + if (EMPTYSTRING(outkey)) { + cryptoerror(LOG_STDERR, + gettext("No output key file was specified for the key\n")); + return (KMF_ERR_BAD_PARAMETER); + } + + if (verify_file(outkey)) { + cryptoerror(LOG_STDERR, + gettext("Cannot write the indicated output " + "key file (%s).\n"), outkey); + return (KMF_ERR_BAD_PARAMETER); + } + + (void) memset(&key, 0, sizeof (KMF_KEY_HANDLE)); + csk_params.kstype = KMF_KEYSTORE_OPENSSL; + csk_params.keytype = keyAlg; + csk_params.keylength = keylen; + csk_params.cred.cred = NULL; + csk_params.cred.credlen = 0; + csk_params.sslparms.dirpath = (dir == NULL) ? "." : dir; + csk_params.sslparms.keyfile = outkey; + + kmfrv = KMF_CreateSymKey(kmfhandle, &csk_params, &key); + if (kmfrv != KMF_OK) { + goto out; + } + + if (print_hex) { + rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); + if (rkey == NULL) { + kmfrv = KMF_ERR_MEMORY; + goto out; + } + (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); + kmfrv = KMF_GetSymKeyValue(kmfhandle, &key, rkey); + if (kmfrv != KMF_OK) { + goto out; + } + + hexstrlen = 2 * rkey->keydata.len + 1; + hexstr = malloc(hexstrlen); + if (hexstr == NULL) { + kmfrv = KMF_ERR_MEMORY; + goto out; + } + tohexstr(rkey->keydata.val, rkey->keydata.len, hexstr, + hexstrlen); + (void) printf(gettext("\tKey Value =\"%s\"\n"), hexstr); + } + +out: + KMF_FreeRawSymKey(rkey); + + if (hexstr != NULL) + free(hexstr); + + return (kmfrv); +} + +int +pk_genkey(int argc, char *argv[]) +{ + int rv; + int opt; + extern int optind_av; + extern char *optarg_av; + KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; + char *tokenname = NULL; + char *dir = NULL; + char *prefix = NULL; + char *keytype = "AES"; + char *keylenstr = NULL; + int keylen = 0; + char *keylabel = NULL; + char *outkey = NULL; + char *senstr = NULL; + char *extstr = NULL; + char *printstr = NULL; + KMF_HANDLE_T kmfhandle = NULL; + KMF_KEY_ALG keyAlg = KMF_AES; + boolean_t print_hex = B_FALSE; + KMF_CREDENTIAL tokencred = {NULL, 0}; + + while ((opt = getopt_av(argc, argv, + "k:(keystore)l:(label)T:(token)d:(dir)p:(prefix)" + "t:(keytype)y:(keylen)K:(outkey)P:(print)" + "s:(sensitive)e:(extractable)")) != EOF) { + if (EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); + switch (opt) { + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 'l': + if (keylabel) + return (PK_ERR_USAGE); + keylabel = optarg_av; + break; + case 'T': + if (tokenname) + return (PK_ERR_USAGE); + tokenname = optarg_av; + break; + case 'd': + if (dir) + return (PK_ERR_USAGE); + dir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + case 't': + keytype = optarg_av; + break; + case 'y': + if (keylenstr) + return (PK_ERR_USAGE); + keylenstr = optarg_av; + break; + case 'K': + if (outkey) + return (PK_ERR_USAGE); + outkey = optarg_av; + break; + case 'P': + if (printstr) + return (PK_ERR_USAGE); + printstr = optarg_av; + break; + case 's': + if (senstr) + return (PK_ERR_USAGE); + senstr = optarg_av; + break; + case 'e': + if (extstr) + return (PK_ERR_USAGE); + extstr = optarg_av; + break; + default: + return (PK_ERR_USAGE); + } + } + + /* No additional args allowed. */ + argc -= optind_av; + argv += optind_av; + if (argc) { + return (PK_ERR_USAGE); + } + + /* Check keytype. If not specified, default to AES */ + if (keytype != NULL && Str2SymKeyType(keytype, &keyAlg) != 0) { + cryptoerror(LOG_STDERR, gettext("Unrecognized keytype(%s).\n"), + keytype); + return (PK_ERR_USAGE); + } + + /* + * Check and set the key length. + * - For DES and 3DES, the key size are fixed. Ingore the keylen + * option, even if it is specified. + * - For AES and ARCFOUR, if keylen is not specified, default to + * 128 bits. + */ + if (keyAlg == KMF_DES) + keylen = 64; /* fixed size; ignore input */ + else if (keyAlg == KMF_DES3) + keylen = 192; /* fixed size; ignore input */ + else /* AES or ARCFOUR */ { + if (keylenstr == NULL) { + cryptoerror(LOG_STDERR, + gettext("Key length must be specified " + "for AES and ARCFOUR symmetric keys.\n")); + return (PK_ERR_USAGE); + } + if (sscanf(keylenstr, "%d", &keylen) != 1) { + cryptoerror(LOG_STDERR, + gettext("Unrecognized key length (%s).\n"), + keytype); + return (PK_ERR_USAGE); + } + if (keylen == 0 || (keylen % 8) != 0) { + cryptoerror(LOG_STDERR, + gettext("Key length bitlength must be a " + "multiple of 8.\n")); + return (PK_ERR_USAGE); + } + } + + /* check the print option */ + if (printstr != NULL) { + if (kstype == KMF_KEYSTORE_NSS) { + cryptoerror(LOG_STDERR, + gettext("The print option does not apply " + "to the NSS keystore.\n")); + return (PK_ERR_USAGE); + } + + if (tolower(printstr[0]) == 'y') + print_hex = B_TRUE; + else if (tolower(printstr[0]) == 'n') + print_hex = B_FALSE; + else { + cryptoerror(LOG_STDERR, + gettext("Incorrect print option value.\n")); + return (PK_ERR_USAGE); + } + } + + /* check the sensitive and extractable options */ + if ((senstr != NULL || extstr != NULL) && + (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_OPENSSL)) { + cryptoerror(LOG_STDERR, + gettext("The sensitive or extractable option applies " + "to the PKCS11 keystore only.\n")); + return (PK_ERR_USAGE); + } + + if (kstype == KMF_KEYSTORE_PK11TOKEN && tokenname == NULL) { + tokenname = PK_DEFAULT_PK11TOKEN; + } else if (kstype == KMF_KEYSTORE_NSS && tokenname == NULL) { + tokenname = DEFAULT_NSS_TOKEN; + } + + if (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) + (void) get_token_password(kstype, tokenname, &tokencred); + + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); + goto end; + } + + if (kstype == KMF_KEYSTORE_NSS) { + rv = genkey_nss(kmfhandle, tokenname, dir, prefix, + keylabel, keyAlg, keylen, &tokencred); + } else if (kstype == KMF_KEYSTORE_OPENSSL) { + rv = genkey_file(kmfhandle, keyAlg, keylen, dir, outkey, + print_hex); + } else { + rv = genkey_pkcs11(kmfhandle, tokenname, keylabel, keyAlg, + keylen, senstr, extstr, print_hex, &tokencred); + } + +end: + if (rv != KMF_OK) + display_error(kmfhandle, rv, + gettext("Error generating key")); + + if (tokencred.cred != NULL) + free(tokencred.cred); + + (void) KMF_Finalize(kmfhandle); + if (rv != KMF_OK) + return (PK_ERR_USAGE); + + return (0); +} diff --git a/usr/src/cmd/cmd-crypto/pktool/import.c b/usr/src/cmd/cmd-crypto/pktool/import.c index 0afba0ef2e..ac706b82ab 100644 --- a/usr/src/cmd/cmd-crypto/pktool/import.c +++ b/usr/src/cmd/cmd-crypto/pktool/import.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,754 +36,354 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> -#include <cryptoutil.h> -#include <security/cryptoki.h> #include "common.h" -#include "biginteger.h" -#include "osslcommon.h" -#include "p12common.h" -#include <openssl/pkcs12.h> -#include <openssl/err.h> -/* - * Helper function decrypt and parse PKCS#12 import file. - */ -static CK_RV -extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen, - EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca) -/* ARGSUSED */ +#include <kmfapi.h> + +static KMF_RETURN +pk_import_pk12_files(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred, + char *outfile, char *certfile, char *keyfile, + char *dir, char *keydir, KMF_ENCODE_FORMAT outformat) { - PKCS12 *pk12, *pk12_tmp; - EVP_PKEY *temp_pkey = NULL; - X509 *temp_cert = NULL; - STACK_OF(X509) *temp_ca = NULL; - - cryptodebug("inside extract_pkcs12"); - - cryptodebug("calling PKCS12_new"); - if ((pk12 = PKCS12_new()) == NULL) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create PKCS#12 context.")); - return (CKR_GENERAL_ERROR); + KMF_RETURN rv = KMF_OK; + KMF_DATA *certs = NULL; + KMF_RAW_KEY_DATA *keys = NULL; + int ncerts = 0; + int nkeys = 0; + int i; + + rv = KMF_ImportPK12(kmfhandle, outfile, cred, + &certs, &ncerts, &keys, &nkeys); + + if (rv == KMF_OK) { + (void) printf(gettext("Found %d certificate(s) and %d " + "key(s) in %s\n"), ncerts, nkeys, outfile); + } + + if (rv == KMF_OK && ncerts > 0) { + KMF_STORECERT_PARAMS params; + char newcertfile[MAXPATHLEN]; + + (void) memset(¶ms, 0, sizeof (KMF_STORECERT_PARAMS)); + params.kstype = KMF_KEYSTORE_OPENSSL; + params.sslparms.dirpath = dir; + params.sslparms.format = outformat; + + for (i = 0; rv == KMF_OK && i < ncerts; i++) { + /* + * If storing more than 1 cert, gotta change + * the name so we don't overwrite the previous one. + * Just append a _# to the name. + */ + if (i > 0) { + (void) snprintf(newcertfile, + sizeof (newcertfile), + "%s_%d", certfile, i); + params.sslparms.certfile = newcertfile; + } else { + params.sslparms.certfile = certfile; + } + rv = KMF_StoreCert(kmfhandle, ¶ms, &certs[i]); + } } - - cryptodebug("calling d2i_PKCS12_bio"); - if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) { - /* This is ok; it seems to mean there is no more to read. */ - if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 && - ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG) - goto end_extract_pkcs12; - - cryptoerror(LOG_STDERR, gettext( - "Unable to populate PKCS#12 context.")); - PKCS12_free(pk12); - return (CKR_GENERAL_ERROR); + if (rv == KMF_OK && nkeys > 0) { + KMF_STOREKEY_PARAMS skparms; + char newkeyfile[MAXPATHLEN]; + + (void) memset(&skparms, 0, sizeof (skparms)); + + /* The order of certificates and keys should match */ + for (i = 0; rv == KMF_OK && i < nkeys; i++) { + skparms.kstype = KMF_KEYSTORE_OPENSSL; + skparms.sslparms.dirpath = keydir; + skparms.sslparms.format = outformat; + skparms.cred = *cred; + skparms.certificate = &certs[i]; + + if (i > 0) { + (void) snprintf(newkeyfile, + sizeof (newkeyfile), + "%s_%d", keyfile, i); + skparms.sslparms.keyfile = newkeyfile; + } else { + skparms.sslparms.keyfile = keyfile; + } + + rv = KMF_StorePrivateKey(kmfhandle, &skparms, + &keys[i]); + } } - pk12 = pk12_tmp; - - cryptodebug("calling PKCS12_parse"); - if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert, - &temp_ca) <= 0) { - cryptoerror(LOG_STDERR, - gettext("Unable to parse import file.")); - PKCS12_free(pk12); - return (CKR_GENERAL_ERROR); + /* + * Cleanup memory. + */ + if (certs) { + for (i = 0; i < ncerts; i++) + KMF_FreeData(&certs[i]); + free(certs); + } + if (keys) { + for (i = 0; i < nkeys; i++) + KMF_FreeRawKey(&keys[i]); + free(keys); } -end_extract_pkcs12: - - *priv_key = temp_pkey; - *cert = temp_cert; - *ca = temp_ca; - PKCS12_free(pk12); - return (CKR_OK); + return (rv); } -/* - * Converts OpenSSL BIGNUM into PKCS#11 biginteger_t format. - */ -static CK_RV -cvt_bn2bigint(BIGNUM *from, biginteger_t *to) + +static KMF_RETURN +pk_import_pk12_nss( + KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *kmfcred, + KMF_CREDENTIAL *tokencred, + char *token_spec, char *dir, char *prefix, + char *nickname, char *trustflags, char *filename) { - CK_BYTE *temp; - CK_ULONG temp_alloc_sz, temp_cvt_sz; + KMF_RETURN rv = KMF_OK; + KMF_DATA *certs = NULL; + KMF_RAW_KEY_DATA *keys = NULL; + int ncerts = 0; + int nkeys = 0; + int i; + + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) + return (rv); - cryptodebug("inside cvt_bn2bigint"); + rv = KMF_ImportPK12(kmfhandle, filename, kmfcred, + &certs, &ncerts, &keys, &nkeys); - if (from == NULL || to == NULL) - return (CKR_ARGUMENTS_BAD); + if (rv == KMF_OK) + (void) printf(gettext("Found %d certificate(s) and %d " + "key(s) in %s\n"), ncerts, nkeys, filename); - cryptodebug("calling BN_num_bytes"); - temp_alloc_sz = BN_num_bytes(from); - if ((temp = malloc(temp_alloc_sz)) == NULL) - return (CKR_HOST_MEMORY); + if (rv == KMF_OK) { + KMF_STORECERT_PARAMS params; - cryptodebug("calling BN_bn2bin"); - temp_cvt_sz = BN_bn2bin(from, (unsigned char *)temp); - if (temp_cvt_sz != temp_alloc_sz) - return (CKR_GENERAL_ERROR); + (void) memset(¶ms, 0, sizeof (KMF_STORECERT_PARAMS)); + params.kstype = KMF_KEYSTORE_NSS; + params.nssparms.slotlabel = token_spec; + params.nssparms.trustflag = trustflags; - to->big_value = temp; - to->big_value_len = temp_cvt_sz; - return (CKR_OK); -} + for (i = 0; rv == KMF_OK && i < ncerts; i++) { + if (i == 0) + params.certLabel = nickname; + else + params.certLabel = NULL; -/* - * Write RSA private key to token. - */ -static CK_RV -write_rsa_private(CK_SESSION_HANDLE sess, RSA *rsa, X509 *cert) -{ - CK_RV rv = CKR_OK; - int i = 0; - static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY; - static CK_KEY_TYPE keytype = CKK_RSA; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_DATE startdate = { "", "", "" }; - CK_DATE enddate = { "", "", "" }; - char tmpdate[8]; - biginteger_t mod = { NULL, 0 }; /* required */ - biginteger_t pubexp = { NULL, 0 }; /* required */ - biginteger_t priexp = { NULL, 0 }; /* optional */ - biginteger_t prime1 = { NULL, 0 }; /* optional */ - biginteger_t prime2 = { NULL, 0 }; /* optional */ - biginteger_t exp1 = { NULL, 0 }; /* optional */ - biginteger_t exp2 = { NULL, 0 }; /* optional */ - biginteger_t coef = { NULL, 0 }; /* optional */ - CK_ATTRIBUTE rsa_pri_attrs[16] = { - { CKA_CLASS, &objclass, sizeof (objclass) }, - { CKA_KEY_TYPE, &keytype, sizeof (keytype) }, - { CKA_PRIVATE, &pk_true, sizeof (pk_true) }, - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { CKA_LABEL, NULL, 0 }, - { CKA_ID, NULL, 0 }, - { CKA_START_DATE, NULL, 0 }, - { CKA_END_DATE, NULL, 0 }, - { CKA_MODULUS, NULL, 0 }, - { CKA_PUBLIC_EXPONENT, NULL, 0 }, - { 0 /* CKA_PRIVATE_EXPONENT */, NULL, 0 }, /* optional */ - { 0 /* CKA_PRIME_1 */, NULL, 0 }, /* | */ - { 0 /* CKA_PRIME_2 */, NULL, 0 }, /* | */ - { 0 /* CKA_EXPONENT_1 */, NULL, 0 }, /* | */ - { 0 /* CKA_EXPONENT_2 */, NULL, 0 }, /* | */ - { 0 /* CKA_COEFFICIENT */, NULL, 0 } /* V */ - }; - CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE); - CK_OBJECT_HANDLE obj; - - cryptodebug("inside write_rsa_private"); - - /* Attributes start at array index 4. */ - i = 4; - - /* Recycle the certificate label for the private key label. */ - cryptodebug("calling X509_alias_get0"); - if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) { - label = (CK_BYTE *)gettext("no label"); - label_len = strlen((char *)label); - } - copy_string_to_attr(label, label_len, &(rsa_pri_attrs[i++])); - - /* Recycle the certificate id for the private key id. */ - cryptodebug("calling PKTOOL_X509_keyid_get0"); - if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) { - id = (CK_BYTE *)gettext("no id"); - id_len = strlen((char *)id); - } - copy_string_to_attr(id, id_len, &(rsa_pri_attrs[i++])); - - /* Recycle the certificate start and end dates for private key. */ - cryptodebug("calling X509_get_notBefore"); - if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) { - (void) memcpy(&startdate, tmpdate, sizeof (startdate)); - copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate), - &(rsa_pri_attrs[i++])); - } - - cryptodebug("calling X509_get_notAfter"); - if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) { - (void) memcpy(&enddate, tmpdate, sizeof (enddate)); - copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate), - &(rsa_pri_attrs[i++])); - } - - /* Modulus n */ - cryptodebug("converting RSA private key modulus"); - if ((rv = cvt_bn2bigint(rsa->n, &mod)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key modulus.")); - return (rv); - } - copy_bigint_to_attr(mod, &(rsa_pri_attrs[i++])); - - /* Public exponent e */ - cryptodebug("converting RSA private key public exponent"); - if ((rv = cvt_bn2bigint(rsa->e, &pubexp)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key public exponent.")); - return (rv); - } - copy_bigint_to_attr(pubexp, &(rsa_pri_attrs[i++])); - - /* Private exponent d */ - if (rsa->d != NULL) { - cryptodebug("converting RSA private key private exponent"); - if ((rv = cvt_bn2bigint(rsa->d, &priexp)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext("Unable to convert " - "RSA private key private exponent.")); - return (rv); - } - rsa_pri_attrs[i].type = CKA_PRIVATE_EXPONENT; - copy_bigint_to_attr(priexp, &(rsa_pri_attrs[i++])); - } else - cryptodebug("no RSA private key private exponent"); - - /* Prime p */ - if (rsa->p != NULL) { - cryptodebug("converting RSA private key prime 1"); - if ((rv = cvt_bn2bigint(rsa->p, &prime1)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key prime 1.")); - return (rv); - } - rsa_pri_attrs[i].type = CKA_PRIME_1; - copy_bigint_to_attr(prime1, &(rsa_pri_attrs[i++])); - } else - cryptodebug("no RSA private key prime 1"); - - /* Prime q */ - if (rsa->q != NULL) { - cryptodebug("converting RSA private key prime 2"); - if ((rv = cvt_bn2bigint(rsa->q, &prime2)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key prime 2.")); - return (rv); - } - rsa_pri_attrs[i].type = CKA_PRIME_2; - copy_bigint_to_attr(prime2, &(rsa_pri_attrs[i++])); - } else - cryptodebug("no RSA private key prime 2"); - - /* Private exponent d modulo p-1 */ - if (rsa->dmp1 != NULL) { - cryptodebug("converting RSA private key exponent 1"); - if ((rv = cvt_bn2bigint(rsa->dmp1, &exp1)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key exponent 1.")); - return (rv); - } - rsa_pri_attrs[i].type = CKA_EXPONENT_1; - copy_bigint_to_attr(exp1, &(rsa_pri_attrs[i++])); - } else - cryptodebug("no RSA private key exponent 1"); - - /* Private exponent d modulo q-1 */ - if (rsa->dmq1 != NULL) { - cryptodebug("converting RSA private key exponent 2"); - if ((rv = cvt_bn2bigint(rsa->dmq1, &exp2)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key exponent 2.")); - return (rv); + rv = KMF_StoreCert(kmfhandle, ¶ms, &certs[i]); } - rsa_pri_attrs[i].type = CKA_EXPONENT_2; - copy_bigint_to_attr(exp2, &(rsa_pri_attrs[i++])); - } else - cryptodebug("no RSA private key exponent 2"); - - /* CRT coefficient q-inverse mod p */ - if (rsa->iqmp != NULL) { - cryptodebug("converting RSA private key coefficient"); - if ((rv = cvt_bn2bigint(rsa->iqmp, &coef)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert RSA private key coefficient.")); - return (rv); + if (rv != KMF_OK) { + display_error(kmfhandle, rv, + gettext("Error storing certificate " + "in PKCS11 token")); } - rsa_pri_attrs[i].type = CKA_COEFFICIENT; - copy_bigint_to_attr(coef, &(rsa_pri_attrs[i++])); - } else - cryptodebug("no RSA private key coefficient"); - - /* Indicates programming error: attributes overran the template */ - if (i > count) { - cryptodebug("error: more attributes found than accounted for"); - i = count; } - cryptodebug("calling C_CreateObject"); - if ((rv = C_CreateObject(sess, rsa_pri_attrs, i, &obj)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create RSA private key object.")); - return (rv); - } + if (rv == KMF_OK) { + KMF_STOREKEY_PARAMS skparms; - return (CKR_OK); -} + /* The order of certificates and keys should match */ + for (i = 0; i < nkeys; i++) { + (void) memset(&skparms, 0, + sizeof (KMF_STOREKEY_PARAMS)); + skparms.kstype = KMF_KEYSTORE_NSS; + skparms.cred = *tokencred; + skparms.label = nickname; + skparms.certificate = &certs[i]; + skparms.nssparms.slotlabel = token_spec; -/* - * Write DSA private key to token. - */ -static CK_RV -write_dsa_private(CK_SESSION_HANDLE sess, DSA *dsa, X509 *cert) -{ - CK_RV rv = CKR_OK; - int i = 0; - static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY; - static CK_KEY_TYPE keytype = CKK_DSA; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_DATE startdate = { "", "", "" }; - CK_DATE enddate = { "", "", "" }; - char tmpdate[8]; - biginteger_t prime = { NULL, 0 }; /* required */ - biginteger_t subprime = { NULL, 0 }; /* required */ - biginteger_t base = { NULL, 0 }; /* required */ - biginteger_t value = { NULL, 0 }; /* required */ - CK_ATTRIBUTE dsa_pri_attrs[12] = { - { CKA_CLASS, &objclass, sizeof (objclass) }, - { CKA_KEY_TYPE, &keytype, sizeof (keytype) }, - { CKA_PRIVATE, &pk_true, sizeof (pk_true) }, - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { CKA_LABEL, NULL, 0 }, - { CKA_ID, NULL, 0 }, - { CKA_START_DATE, NULL, 0 }, - { CKA_END_DATE, NULL, 0 }, - { CKA_PRIME, NULL, 0 }, - { CKA_SUBPRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE); - CK_OBJECT_HANDLE obj; - - cryptodebug("inside write_dsa_private"); - - /* Attributes start at array index 4. */ - i = 4; - - /* Recycle the certificate label for the private key label. */ - cryptodebug("calling X509_alias_get0"); - if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) { - label = (CK_BYTE *)gettext("no label"); - label_len = strlen((char *)label); + rv = KMF_StorePrivateKey(kmfhandle, &skparms, &keys[i]); + } } - copy_string_to_attr(label, label_len, &(dsa_pri_attrs[i++])); - /* Recycle the certificate id for the private key id. */ - cryptodebug("calling PKTOOL_X509_keyid_get0"); - if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) { - id = (CK_BYTE *)gettext("no id"); - id_len = strlen((char *)id); + /* + * Cleanup memory. + */ + if (certs) { + for (i = 0; i < ncerts; i++) + KMF_FreeData(&certs[i]); + free(certs); } - copy_string_to_attr(id, id_len, &(dsa_pri_attrs[i++])); - - /* Recycle the certificate start and end dates for private key. */ - cryptodebug("calling X509_get_notBefore"); - if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) { - (void) memcpy(&startdate, tmpdate, sizeof (startdate)); - copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate), - &(dsa_pri_attrs[i++])); + if (keys) { + for (i = 0; i < nkeys; i++) + KMF_FreeRawKey(&keys[i]); + free(keys); } - cryptodebug("calling X509_get_notAfter"); - if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) { - (void) memcpy(&enddate, tmpdate, sizeof (enddate)); - copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate), - &(dsa_pri_attrs[i++])); - } + return (rv); +} - /* Prime p */ - cryptodebug("converting DSA private key prime"); - if ((rv = cvt_bn2bigint(dsa->p, &prime)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key prime.")); - return (rv); - } - copy_bigint_to_attr(prime, &(dsa_pri_attrs[i++])); +static KMF_RETURN +pk_import_cert( + KMF_HANDLE_T kmfhandle, + KMF_KEYSTORE_TYPE kstype, + char *label, char *token_spec, char *filename, + char *dir, char *prefix, char *trustflags) +{ + KMF_RETURN rv = KMF_OK; + KMF_IMPORTCERT_PARAMS params; - /* Subprime q */ - cryptodebug("converting DSA private key subprime"); - if ((rv = cvt_bn2bigint(dsa->q, &subprime)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key subprime.")); - return (rv); - } - copy_bigint_to_attr(subprime, &(dsa_pri_attrs[i++])); + if (kstype == KMF_KEYSTORE_PK11TOKEN) { + rv = select_token(kmfhandle, token_spec, FALSE); - /* Base g */ - cryptodebug("converting DSA private key base"); - if ((rv = cvt_bn2bigint(dsa->g, &base)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key base.")); - return (rv); + if (rv != KMF_OK) { + return (rv); + } } - copy_bigint_to_attr(base, &(dsa_pri_attrs[i++])); - /* Private key x */ - cryptodebug("converting DSA private key value"); - if ((rv = cvt_bn2bigint(dsa->priv_key, &value)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DSA private key value.")); - return (rv); - } - copy_bigint_to_attr(value, &(dsa_pri_attrs[i++])); + (void) memset(¶ms, 0, sizeof (params)); + params.kstype = kstype; + params.certfile = filename; + params.certLabel = label; - /* Indicates programming error: attributes overran the template */ - if (i > count) { - cryptodebug("error: more attributes found than accounted for"); - i = count; + if (kstype == KMF_KEYSTORE_NSS) { + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) + return (rv); + params.nssparms.trustflag = trustflags; + params.nssparms.slotlabel = token_spec; } - cryptodebug("calling C_CreateObject"); - if ((rv = C_CreateObject(sess, dsa_pri_attrs, i, &obj)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create DSA private key object.")); - return (rv); - } + rv = KMF_ImportCert(kmfhandle, ¶ms); - return (CKR_OK); + return (rv); } -/* - * Write DH private key to token. - */ -static CK_RV -write_dh_private(CK_SESSION_HANDLE sess, DH *dh, X509 *cert) +static KMF_RETURN +pk_import_file_crl(void *kmfhandle, + char *infile, + char *outfile, + char *outdir, + KMF_ENCODE_FORMAT outfmt) { - CK_RV rv = CKR_OK; - int i = 0; - static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY; - static CK_KEY_TYPE keytype = CKK_DH; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_DATE startdate = { "", "", "" }; - CK_DATE enddate = { "", "", "" }; - char tmpdate[8]; - biginteger_t prime = { NULL, 0 }; /* required */ - biginteger_t base = { NULL, 0 }; /* required */ - biginteger_t value = { NULL, 0 }; /* required */ - CK_ATTRIBUTE dh_pri_attrs[11] = { - { CKA_CLASS, &objclass, sizeof (objclass) }, - { CKA_KEY_TYPE, &keytype, sizeof (keytype) }, - { CKA_PRIVATE, &pk_true, sizeof (pk_true) }, - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { CKA_LABEL, NULL, 0 }, - { CKA_ID, NULL, 0 }, - { CKA_START_DATE, NULL, 0 }, - { CKA_END_DATE, NULL, 0 }, - { CKA_PRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE); - CK_OBJECT_HANDLE obj; - - cryptodebug("inside write_dh_private"); - - /* Attributes start at array index 4. */ - i = 4; - - /* Recycle the certificate label for the private key label. */ - cryptodebug("calling X509_alias_get0"); - if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) { - label = (CK_BYTE *)gettext("no label"); - label_len = strlen((char *)label); - } - copy_string_to_attr(label, label_len, &(dh_pri_attrs[i++])); + KMF_IMPORTCRL_PARAMS icrl_params; + KMF_OPENSSL_PARAMS sslparams; - /* Recycle the certificate id for the private key id. */ - cryptodebug("PKTOOL_X509_keyid_get0"); - if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) { - id = (CK_BYTE *)gettext("no id"); - id_len = strlen((char *)id); - } - copy_string_to_attr(id, id_len, &(dh_pri_attrs[i++])); - - /* Recycle the certificate start and end dates for private key. */ - cryptodebug("calling X509_get_notBefore"); - if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) { - (void) memcpy(&startdate, tmpdate, sizeof (startdate)); - copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate), - &(dh_pri_attrs[i++])); - } + sslparams.crlfile = infile; + sslparams.dirpath = outdir; + sslparams.outcrlfile = outfile; + sslparams.format = outfmt; + sslparams.crl_check = B_FALSE; - cryptodebug("calling X509_get_notAfter"); - if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) { - (void) memcpy(&enddate, tmpdate, sizeof (enddate)); - copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate), - &(dh_pri_attrs[i++])); - } + icrl_params.kstype = KMF_KEYSTORE_OPENSSL; + icrl_params.sslparms = sslparams; - /* Prime p */ - cryptodebug("converting DH private key prime"); - if ((rv = cvt_bn2bigint(dh->p, &prime)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DH private key prime.")); - return (rv); - } - copy_bigint_to_attr(prime, &(dh_pri_attrs[i++])); + return (KMF_ImportCRL(kmfhandle, &icrl_params)); - /* Base g */ - cryptodebug("converting DH private key base"); - if ((rv = cvt_bn2bigint(dh->g, &base)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DH private key base.")); - return (rv); - } - copy_bigint_to_attr(base, &(dh_pri_attrs[i++])); +} - /* Private value x */ - cryptodebug("converting DH private key value"); - if ((rv = cvt_bn2bigint(dh->priv_key, &value)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to convert DH private key value.")); +static KMF_RETURN +pk_import_nss_crl(void *kmfhandle, + boolean_t verify_crl_flag, + char *infile, + char *outdir, + char *prefix) +{ + KMF_IMPORTCRL_PARAMS icrl_params; + KMF_RETURN rv; + + rv = configure_nss(kmfhandle, outdir, prefix); + if (rv != KMF_OK) return (rv); - } - copy_bigint_to_attr(value, &(dh_pri_attrs[i++])); - /* Indicates programming error: attributes overran the template */ - if (i > count) { - cryptodebug("error: more attributes found than accounted for"); - i = count; - } + icrl_params.kstype = KMF_KEYSTORE_NSS; + icrl_params.nssparms.slotlabel = NULL; + icrl_params.nssparms.crlfile = infile; + icrl_params.nssparms.crl_check = verify_crl_flag; - cryptodebug("calling C_CreateObject"); - if ((rv = C_CreateObject(sess, dh_pri_attrs, i, &obj)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create DH private key object.")); - return (rv); - } + return (KMF_ImportCRL(kmfhandle, &icrl_params)); - return (CKR_OK); } -/* - * Write certificate to token. - */ -static CK_RV -write_cert(CK_SESSION_HANDLE sess, X509 *cert) +static KMF_RETURN +pk_import_pk12_pk11( + KMF_HANDLE_T kmfhandle, + KMF_CREDENTIAL *p12cred, + KMF_CREDENTIAL *tokencred, + char *label, char *token_spec, + char *filename) { - CK_RV rv = CKR_OK; - int i = 0; - static CK_OBJECT_CLASS objclass = CKO_CERTIFICATE; - static CK_CERTIFICATE_TYPE certtype = CKC_X_509; - CK_BYTE *subject = NULL; - CK_ULONG subject_len = 0; - CK_BYTE *value = NULL; - CK_ULONG value_len = 0; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_BYTE *issuer = NULL; - CK_ULONG issuer_len = 0; - CK_BYTE *serial = NULL; - CK_ULONG serial_len = 0; - CK_ATTRIBUTE cert_attrs[9] = { - { CKA_CLASS, &objclass, sizeof (objclass) }, - { CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) }, - { CKA_TOKEN, &pk_true, sizeof (pk_true) }, - { CKA_SUBJECT, NULL, 0 }, /* required */ - { CKA_VALUE, NULL, 0 }, /* required */ - { 0 /* CKA_LABEL */, NULL, 0 }, /* optional */ - { 0 /* CKA_ID */, NULL, 0 }, /* optional */ - { 0 /* CKA_ISSUER */, NULL, 0 }, /* optional */ - { 0 /* CKA_SERIAL_NUMBER */, NULL, 0 } /* optional */ - }; - CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE); - CK_OBJECT_HANDLE obj; - - cryptodebug("inside write_cert"); - - /* Attributes start at array index 3. */ - i = 3; + KMF_RETURN rv = KMF_OK; + KMF_DATA *certs = NULL; + KMF_RAW_KEY_DATA *keys = NULL; + int ncerts = 0; + int nkeys = 0; + int i; - /* - * OpenSSL subject name and issuer (a little further below) are - * actually stack structures that contain individual ASN.1 - * components. This stack of entries is packed into one DER string. - */ - cryptodebug("calling PKTOOL_X509_subject_name"); - if ((subject = PKTOOL_X509_subject_name(cert, (int *)&subject_len)) == - NULL) { - subject = (CK_BYTE *)gettext("no subject name"); - subject_len = strlen((char *)subject); - } - copy_string_to_attr(subject, subject_len, &(cert_attrs[i++])); + rv = select_token(kmfhandle, token_spec, FALSE); - /* Get cert value, but it has to be reconstructed from cert. */ - cryptodebug("calling PKTOOL_X509_cert_value"); - if ((value = PKTOOL_X509_cert_value(cert, (int *)&value_len)) == NULL) { - value = (CK_BYTE *)gettext("no value"); - value_len = strlen((char *)value); - } - copy_string_to_attr(value, value_len, &(cert_attrs[i++])); - - /* - * Get certificate label which is "friendlyName" Netscape, - * "alias" in OpenSSL. - */ - if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) { - cryptodebug("no certificate label"); - } else { - cert_attrs[i].type = CKA_LABEL; - copy_string_to_attr(label, label_len, &(cert_attrs[i++])); + if (rv != KMF_OK) { + return (rv); } - /* Get the keyid for the cert. */ - if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) { - cryptodebug("no certificate id"); - } else { - cert_attrs[i].type = CKA_ID; - copy_string_to_attr(id, id_len, &(cert_attrs[i++])); - } + rv = KMF_ImportPK12(kmfhandle, filename, p12cred, + &certs, &ncerts, &keys, &nkeys); - /* Get the issuer name for the cert. */ - if ((issuer = PKTOOL_X509_issuer_name(cert, (int *)&issuer_len)) == - NULL) { - cryptodebug("no certificate issuer name"); - } else { - cert_attrs[i].type = CKA_ISSUER; - copy_string_to_attr(issuer, issuer_len, &(cert_attrs[i++])); - } + if (rv == KMF_OK) { + KMF_STOREKEY_PARAMS skparms; - /* Get the cert serial number. */ - if ((serial = PKTOOL_X509_serial_number(cert, (int *)&serial_len)) == - NULL) { - cryptodebug("no certificate serial number"); - } else { - cert_attrs[i].type = CKA_SERIAL_NUMBER; - copy_string_to_attr(serial, serial_len, &(cert_attrs[i++])); - } + /* The order of certificates and keys should match */ + for (i = 0; i < nkeys; i++) { + (void) memset(&skparms, 0, + sizeof (KMF_STOREKEY_PARAMS)); + skparms.kstype = KMF_KEYSTORE_PK11TOKEN; + skparms.certificate = &certs[i]; + if (tokencred != NULL) + skparms.cred = *tokencred; + if (i == 0) + skparms.label = label; + else + skparms.label = NULL; - /* Indicates programming error: attributes overran the template */ - if (i > count) { - cryptodebug("error: more attributes found than accounted for"); - i = count; - } - - cryptodebug("calling C_CreateObject"); - if ((rv = C_CreateObject(sess, cert_attrs, i, &obj)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to create X.509 certificate object.")); - return (rv); + rv = KMF_StorePrivateKey(kmfhandle, &skparms, + &keys[i]); + } } - return (CKR_OK); -} + if (rv == KMF_OK) { + KMF_STORECERT_PARAMS params; -/* - * Helper function to write PKCS#12 items to token. Returns CKR_OK - * or CKR_GENERAL_ERROR - */ -static CK_RV -write_token_objs(CK_SESSION_HANDLE sess, EVP_PKEY *priv_key, X509 *cert, - STACK_OF(X509) *ca, int *successes, int *failures) -{ - int i; - X509 *c; - CK_RV rv = CKR_OK; + (void) printf(gettext("Found %d certificate(s) and %d " + "key(s) in %s\n"), ncerts, nkeys, filename); + (void) memset(¶ms, 0, sizeof (KMF_STORECERT_PARAMS)); - cryptodebug("inside write_token_objs"); + params.kstype = KMF_KEYSTORE_PK11TOKEN; - /* Do not reset *successes or *failures -- keep running totals. */ + for (i = 0; rv == KMF_OK && i < ncerts; i++) { + if (i == 0) + params.certLabel = label; + else + params.certLabel = NULL; - /* Import user key. */ - switch (priv_key->type) { - case EVP_PKEY_RSA: - (void) fprintf(stdout, gettext("Writing RSA private key...\n")); - if ((rv = write_rsa_private(sess, - EVP_PKEY_get1_RSA(priv_key), cert)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write RSA private key (%s)."), - pkcs11_strerror(rv)); - (*failures)++; - } else - (*successes)++; - break; - case EVP_PKEY_DSA: - (void) fprintf(stdout, gettext("Writing DSA private key...\n")); - if ((rv = write_dsa_private(sess, - EVP_PKEY_get1_DSA(priv_key), cert)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write DSA private key (%s)."), - pkcs11_strerror(rv)); - (*failures)++; - } else - (*successes)++; - break; - case EVP_PKEY_DH: - (void) fprintf(stdout, gettext("Writing DH private key...\n")); - if ((rv = write_dh_private(sess, - EVP_PKEY_get1_DH(priv_key), cert)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write DH private key (%s)."), - pkcs11_strerror(rv)); - (*failures)++; - } else - (*successes)++; - break; - - default: - /* - * Note that EVP_PKEY_DH for X9.42 is not implemented - * in the OpenSSL library. - */ - cryptoerror(LOG_STDERR, gettext( - "Private key type 0x%02x import not supported."), - priv_key->type); - (*failures)++; - break; + rv = KMF_StoreCert(kmfhandle, ¶ms, &certs[i]); + } } - /* Import user certificate. */ - (void) fprintf(stdout, gettext("Writing user certificate...\n")); - if ((rv = write_cert(sess, cert)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write user certificate (%s)."), - pkcs11_strerror(rv)); - (*failures)++; - } else - (*successes)++; - - /* Import as many stacks of authority certificates as possible. */ - for (i = 0; i != sk_X509_num(ca); i++) { - /* - * sk_X509_value() is macro that embeds a cast to (X509 *). - * Here it translates into ((X509 *)sk_value((ca), (i))). - * Lint is complaining about the embedded casting, and - * to fix it, you need to fix openssl header files. - */ - /* LINTED E_BAD_PTR_CAST_ALIGN */ - c = sk_X509_value(ca, i); - (void) fprintf(stdout, gettext( - "Writing authority certificate...\n")); - if ((rv = write_cert(sess, c)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write authority certificate (%s)."), - pkcs11_strerror(rv)); - (*failures)++; - } else - (*successes)++; + /* + * Cleanup memory. + */ + if (certs) { + for (i = 0; i < ncerts; i++) + KMF_FreeData(&certs[i]); + free(certs); + } + if (keys) { + for (i = 0; i < nkeys; i++) + KMF_FreeRawKey(&keys[i]); + free(keys); } - (void) fprintf(stdout, gettext("PKCS#12 element scan completed.\n")); - return (*failures != 0 ? CKR_GENERAL_ERROR : CKR_OK); + return (rv); } /* - * Import objects from PKCS#12 file into token. + * Import objects from into KMF repositories. */ int pk_import(int argc, char *argv[]) @@ -793,184 +392,320 @@ pk_import(int argc, char *argv[]) extern int optind_av; extern char *optarg_av; char *token_spec = NULL; - char *token_name = NULL; - char *manuf_id = NULL; - char *serial_no = NULL; - char full_name[FULL_NAME_LEN]; char *filename = NULL; - struct stat statbuf; - CK_SLOT_ID slot_id; - CK_FLAGS pin_state; - CK_UTF8CHAR_PTR pin = NULL; - CK_ULONG pinlen = 0; - CK_UTF8CHAR_PTR pk12pin = NULL; - CK_ULONG pk12pinlen = 0; - CK_SESSION_HANDLE sess; - BIO *fbio = NULL; - EVP_PKEY *priv_key = NULL; - X509 *cert = NULL; - STACK_OF(X509) *ca = NULL; - CK_RV rv = CKR_OK; - int i; - int good_count = 0, bad_count = 0; /* running totals */ - - cryptodebug("inside pk_import"); + char *keyfile = NULL; + char *certfile = NULL; + char *crlfile = NULL; + char *certlabel = NULL; + char *dir = NULL; + char *keydir = NULL; + char *prefix = NULL; + char *trustflags = NULL; + char *verify_crl = NULL; + boolean_t verify_crl_flag = B_FALSE; + int oclass = 0; + KMF_KEYSTORE_TYPE kstype = 0; + KMF_ENCODE_FORMAT kfmt = 0; + KMF_ENCODE_FORMAT okfmt = KMF_FORMAT_ASN1; + KMF_RETURN rv = KMF_OK; + KMF_CREDENTIAL pk12cred = { NULL, 0 }; + KMF_CREDENTIAL tokencred = { NULL, 0 }; + KMF_HANDLE_T kmfhandle = NULL; /* Parse command line options. Do NOT i18n/l10n. */ - while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)")) != EOF) { + while ((opt = getopt_av(argc, argv, + "T:(token)i:(infile)" + "k:(keystore)y:(objtype)" + "d:(dir)p:(prefix)" + "n:(certlabel)N:(label)" + "K:(outkey)c:(outcert)" + "v:(verifycrl)l:(outcrl)" + "t:(trust)D:(keydir)F:(outformat)")) != EOF) { + if (EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; + case 'c': /* output cert file name */ + if (certfile) + return (PK_ERR_USAGE); + certfile = optarg_av; + break; + case 'l': /* output CRL file name */ + if (crlfile) + return (PK_ERR_USAGE); + crlfile = optarg_av; + break; + case 'K': /* output key file name */ + if (keyfile) + return (PK_ERR_USAGE); + keyfile = optarg_av; + break; case 'i': /* input file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 'y': + oclass = OT2Int(optarg_av); + if (oclass == -1) + return (PK_ERR_USAGE); + break; + case 'd': + dir = optarg_av; + break; + case 'D': + keydir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + case 'n': + case 'N': + if (certlabel) + return (PK_ERR_USAGE); + certlabel = optarg_av; + break; + case 'F': + okfmt = Str2Format(optarg_av); + if (okfmt == KMF_FORMAT_UNDEF) + return (PK_ERR_USAGE); + break; + case 't': + if (trustflags) + return (PK_ERR_USAGE); + trustflags = optarg_av; + break; + case 'v': + verify_crl = optarg_av; + if (tolower(verify_crl[0]) == 'y') + verify_crl_flag = B_TRUE; + else if (tolower(verify_crl[0]) == 'n') + verify_crl_flag = B_FALSE; + else + return (PK_ERR_USAGE); + break; default: return (PK_ERR_USAGE); break; } } - /* If nothing is specified, default is to use softtoken. */ - if (token_spec == NULL) { - token_name = SOFT_TOKEN_LABEL; - manuf_id = SOFT_MANUFACTURER_ID; - serial_no = SOFT_TOKEN_SERIAL; - } else { - /* - * Parse token specifier into token_name, manuf_id, serial_no. - * Token_name is required; manuf_id and serial_no are optional. - */ - if (parse_token_spec(token_spec, &token_name, &manuf_id, - &serial_no) < 0) - return (PK_ERR_USAGE); - } + /* Assume keystore = PKCS#11 if not specified */ + if (kstype == 0) + kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ - if (filename == NULL) + if (EMPTYSTRING(filename)) { + cryptoerror(LOG_STDERR, gettext("The 'infile' parameter" + "is required for the import operation.\n")); return (PK_ERR_USAGE); + } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); - /* Done parsing command line options. */ - /* Check that the file exists and is non-empty. */ - if (access(filename, R_OK) < 0) { - cryptoerror(LOG_STDERR, gettext("File \"%s\" is unreadable " - "(%s)."), filename, strerror(errno)); - return (CKR_OK); - } - if (stat(filename, &statbuf) < 0) { - cryptoerror(LOG_STDERR, gettext("Unable to get size of " - "file \"%s\" (%s)."), filename, strerror(errno)); - return (CKR_OK); - } - if (statbuf.st_size == 0) { - cryptoerror(LOG_STDERR, gettext("File \"%s\" is empty."), - filename); - return (CKR_OK); - } + /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ + if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && + kstype != KMF_KEYSTORE_PK11TOKEN) { - full_token_name(token_name, manuf_id, serial_no, full_name); + (void) fprintf(stderr, gettext("The objtype parameter " + "is only relevant if keystore=pkcs11\n")); + return (PK_ERR_USAGE); + } - /* Find the slot with token. */ - if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id, - &pin_state)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to find token %s (%s)."), full_name, - pkcs11_strerror(rv)); - return (PK_ERR_PK11); + /* + * You must specify a certlabel (cert label) when importing + * into NSS or PKCS#11. + */ + if (kstype == KMF_KEYSTORE_NSS && + (oclass != PK_CRL_OBJ) && EMPTYSTRING(certlabel)) { + cryptoerror(LOG_STDERR, gettext("The 'label' argument " + "is required for this operation\n")); + return (PK_ERR_USAGE); } - /* Get the user's PIN. */ - if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin, - &pinlen)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get token passphrase (%s)."), - pkcs11_strerror(rv)); - quick_finish(NULL); - return (PK_ERR_PK11); + /* + * PKCS11 only imports PKCS#12 files or PEM/DER Cert files. + */ + if (kstype == KMF_KEYSTORE_PK11TOKEN) { + /* we do not import private keys except in PKCS12 bundles */ + if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) { + cryptoerror(LOG_STDERR, gettext( + "The PKCS11 keystore only imports PKCS12 " + "files or raw certificate data files " + " or CRL file.\n")); + return (PK_ERR_USAGE); + } } - /* Assume user must be logged in R/W to import objects into token. */ - if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) != - CKR_OK) { + if ((rv = KMF_GetFileFormat(filename, &kfmt)) != KMF_OK) { cryptoerror(LOG_STDERR, - gettext("Unable to log into token (%s)."), - pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); + gettext("File format not recognized.")); + return (rv); } + if (oclass == 0 && (kfmt == KMF_FORMAT_ASN1 || + kfmt == KMF_FORMAT_PEM)) + oclass = PK_CERT_OBJ; - /* Setup OpenSSL context. */ - PKTOOL_setup_openssl(); + if (kstype == KMF_KEYSTORE_NSS) { + if (oclass == PK_CRL_OBJ && + (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { + cryptoerror(LOG_STDERR, gettext( + "CRL data can only be imported as DER or " + "PEM format")); + return (PK_ERR_USAGE); + } - /* Open PKCS#12 file. */ - if ((open_pkcs12(filename, &fbio)) < 0) { - cryptoerror(LOG_STDERR, gettext("Unable to open import file.")); - quick_finish(sess); - return (PK_ERR_SYSTEM); - } + if (oclass == PK_CERT_OBJ && + (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { + cryptoerror(LOG_STDERR, gettext( + "Certificates can only be imported as DER or " + "PEM format")); + return (PK_ERR_USAGE); + } - /* Get the PIN for the PKCS#12 import file. */ - if ((rv = get_pin(gettext("Enter import file passphrase:"), NULL, - &pk12pin, &pk12pinlen)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get import file passphrase (%s)."), - pkcs11_strerror(rv)); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_PK11); + /* we do not import private keys except in PKCS12 bundles */ + if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) { + cryptoerror(LOG_STDERR, gettext( + "Private key data can only be imported as part " + "of a PKCS12 file.\n")); + return (PK_ERR_USAGE); + } } - /* PKCS#12 import file may have multiple elements, loop until done. */ - for (i = 0; /* */; i++) { - /* Extract the contents of the PKCS#12 import file. */ - if ((rv = extract_pkcs12(fbio, pk12pin, pk12pinlen, &priv_key, - &cert, &ca)) != CKR_OK) { + if (kstype == KMF_KEYSTORE_OPENSSL && oclass != PK_CRL_OBJ) { + if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { cryptoerror(LOG_STDERR, gettext( - "Unable to parse PKCS#12 element #%d " - "in import file (%s)."), i+1, pkcs11_strerror(rv)); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_OPENSSL); + "The 'outkey' and 'outcert' parameters " + "are required for the import operation " + "when the 'file' keystore is used.\n")); + return (PK_ERR_USAGE); } + } - /* Reached end of import file? */ - if (rv == CKR_OK && priv_key == NULL && cert == NULL && - ca == NULL) + if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) + token_spec = PK_DEFAULT_PK11TOKEN; + else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) + token_spec = DEFAULT_NSS_TOKEN; + + if (kfmt == KMF_FORMAT_PKCS12) { + (void) get_pk12_password(&pk12cred); + + if (kstype == KMF_KEYSTORE_PK11TOKEN || + kstype == KMF_KEYSTORE_NSS) + (void) get_token_password(kstype, token_spec, + &tokencred); + } + + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + cryptoerror(LOG_STDERR, gettext("Error initializing " + "KMF: 0x%02x\n"), rv); + goto end; + } + + switch (kstype) { + case KMF_KEYSTORE_PK11TOKEN: + if (kfmt == KMF_FORMAT_PKCS12) + rv = pk_import_pk12_pk11( + kmfhandle, + &pk12cred, + &tokencred, + certlabel, + token_spec, + filename); + else if (oclass == PK_CERT_OBJ) + rv = pk_import_cert( + kmfhandle, + kstype, + certlabel, + token_spec, + filename, + NULL, NULL, NULL); + else if (oclass == PK_CRL_OBJ) + rv = pk_import_file_crl( + kmfhandle, + filename, + crlfile, + dir, + okfmt); break; + case KMF_KEYSTORE_NSS: + if (dir == NULL) + dir = PK_DEFAULT_DIRECTORY; + if (kfmt == KMF_FORMAT_PKCS12) + rv = pk_import_pk12_nss( + kmfhandle, &pk12cred, + &tokencred, + token_spec, dir, prefix, + certlabel, trustflags, filename); + else if (oclass == PK_CERT_OBJ) { + rv = pk_import_cert( + kmfhandle, kstype, + certlabel, token_spec, + filename, dir, prefix, trustflags); + } else if (oclass == PK_CRL_OBJ) { + rv = pk_import_nss_crl( + kmfhandle, + verify_crl_flag, + filename, + dir, + prefix); + } + break; + case KMF_KEYSTORE_OPENSSL: + if (kfmt == KMF_FORMAT_PKCS12) + rv = pk_import_pk12_files( + kmfhandle, &pk12cred, + filename, certfile, keyfile, + dir, keydir, okfmt); + else if (oclass == PK_CRL_OBJ) { + rv = pk_import_file_crl( + kmfhandle, + filename, + crlfile, + dir, + okfmt); + } else + /* + * It doesn't make sense to import anything + * else for the files plugin. + */ + return (PK_ERR_USAGE); + break; + default: + rv = PK_ERR_USAGE; + break; + } - (void) fprintf(stdout, gettext( - "Scanning PKCS#12 element #%d for objects...\n"), i+1); +end: + if (rv != KMF_OK) + display_error(kmfhandle, rv, + gettext("Error importing objects")); - /* Write the objects to the token. */ - if ((rv = write_token_objs(sess, priv_key, cert, ca, - &good_count, &bad_count)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to write PKCS#12 element #%d to token %s."), - i+1, full_name); - close_pkcs12(fbio); - quick_finish(sess); - return (PK_ERR_PK11); - } - } + if (tokencred.cred != NULL) + free(tokencred.cred); - (void) fprintf(stdout, gettext("%d PKCS#12 elements scanned: " - "%d objects imported, %d errors occurred.\n"), i, - good_count, bad_count); + if (pk12cred.cred != NULL) + free(pk12cred.cred); - /* Close PKCS#12 file. */ - close_pkcs12(fbio); + (void) KMF_Finalize(kmfhandle); + + if (rv != KMF_OK) + return (PK_ERR_USAGE); - /* Clean up. */ - quick_finish(sess); return (0); } diff --git a/usr/src/cmd/cmd-crypto/pktool/list.c b/usr/src/cmd/cmd-crypto/pktool/list.c index 496642c8da..2a427dfc36 100644 --- a/usr/src/cmd/cmd-crypto/pktool/list.c +++ b/usr/src/cmd/cmd-crypto/pktool/list.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,794 +38,482 @@ #include <cryptoutil.h> #include <security/cryptoki.h> #include "common.h" -#include "derparse.h" -/* - * Get key size based on the key type. - */ -static CK_ULONG -get_key_size(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, CK_KEY_TYPE key_type) +#include <kmfapi.h> + +static void +pk_show_certs(KMF_HANDLE_T kmfhandle, KMF_X509_DER_CERT *certs, int num_certs) { - CK_RV rv = CKR_OK; - CK_ULONG key_size; - CK_ATTRIBUTE modulus_sz = - { CKA_MODULUS, NULL, 0 }; /* RSA */ - CK_ATTRIBUTE prime_sz = - { CKA_PRIME, NULL, 0 }; /* DSA, DH X9.42 */ - CK_ATTRIBUTE value_sz = - { CKA_VALUE, NULL_PTR, 0 }; /* DH, DES/DES3, AES, GENERIC */ - - cryptodebug("inside get_key_size"); - - switch (key_type) { - case CKK_RSA: - if ((rv = C_GetAttributeValue(sess, obj, &modulus_sz, 1)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get modulus attribute size (%s)."), - pkcs11_strerror(rv)); - } else - /* Convert key size to bits. */ - key_size = modulus_sz.ulValueLen * 8; - break; - case CKK_DH: - if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get value attribute size (%s)."), - pkcs11_strerror(rv)); - } else - /* Convert key size to bits. */ - key_size = value_sz.ulValueLen * 8; - break; - case CKK_X9_42_DH: - case CKK_DSA: - if ((rv = C_GetAttributeValue(sess, obj, &prime_sz, 1)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get prime attribute size (%s)."), - pkcs11_strerror(rv)); - } else - /* Convert key size to bits. */ - key_size = prime_sz.ulValueLen * 8; - break; - case CKK_DES: - case CKK_DES3: - if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get value attribute size (%s)."), - pkcs11_strerror(rv)); - } else - /* Convert key size to bits -- omitting parity bit. */ - key_size = value_sz.ulValueLen * 7; - break; - case CKK_AES: - case CKK_GENERIC_SECRET: - if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get value attribute size (%s)."), - pkcs11_strerror(rv)); - } else - /* Convert key size to bits. */ - key_size = value_sz.ulValueLen * 8; - break; - default: - cryptoerror(LOG_STDERR, gettext( - "Unknown object key type (0x%02x)."), key_type); - break; - } + int i; + char *subject, *issuer, *serial, *id, *altname; + + for (i = 0; i < num_certs; i++) { + subject = NULL; + issuer = NULL; + serial = NULL; + id = NULL; + altname = NULL; + + (void) fprintf(stdout, + gettext("%d. (X.509 certificate)\n"), i + 1); + if (certs[i].kmf_private.label != NULL) + (void) fprintf(stdout, gettext("\t%s: %s\n"), + (certs[i].kmf_private.keystore_type == + KMF_KEYSTORE_OPENSSL ? "Filename" : "Label"), + certs[i].kmf_private.label); + if (KMF_GetCertIDString(&certs[i].certificate, + &id) == KMF_OK) + (void) fprintf(stdout, gettext("\tID: %s\n"), id); + if (KMF_GetCertSubjectNameString(kmfhandle, + &certs[i].certificate, &subject) == KMF_OK) + (void) fprintf(stdout, gettext("\tSubject: %s\n"), + subject); + if (KMF_GetCertIssuerNameString(kmfhandle, + &certs[i].certificate, &issuer) == KMF_OK) + (void) fprintf(stdout, gettext("\tIssuer: %s\n"), + issuer); + if (KMF_GetCertSerialNumberString(kmfhandle, + &certs[i].certificate, &serial) == KMF_OK) + (void) fprintf(stdout, gettext("\tSerial: %s\n"), + serial); + + if (KMF_GetCertExtensionString(kmfhandle, + &certs[i].certificate, KMF_X509_EXT_SUBJ_ALTNAME, + &altname) == KMF_OK) { + (void) fprintf(stdout, gettext("\t%s\n"), + altname); + } - return (key_size); + KMF_FreeString(subject); + KMF_FreeString(issuer); + KMF_FreeString(serial); + KMF_FreeString(id); + KMF_FreeString(altname); + (void) fprintf(stdout, "\n"); + } } -/* - * Display private key. - */ -static CK_RV -display_prikey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter) +static char * +describeKey(KMF_KEY_HANDLE *key) { - CK_RV rv = CKR_OK; - static CK_BBOOL private; - static CK_BBOOL modifiable; - static CK_KEY_TYPE key_type; - CK_ULONG key_size; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_BYTE *subject = NULL; - CK_ULONG subject_len = 0; - CK_DATE *start_date = NULL; - CK_ULONG start_date_len = 0; - CK_DATE *end_date = NULL; - CK_ULONG end_date_len = 0; - CK_ATTRIBUTE attrs[18] = { - /* 0 to 2 */ - { CKA_PRIVATE, &private, sizeof (private) }, - { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) }, - { CKA_KEY_TYPE, &key_type, sizeof (key_type) }, - /* 3 to 12 */ - { CKA_DERIVE, NULL, 0 }, - { CKA_LOCAL, NULL, 0 }, - { CKA_DECRYPT, NULL, 0 }, - { CKA_SIGN, NULL, 0 }, - { CKA_SIGN_RECOVER, NULL, 0 }, - { CKA_UNWRAP, NULL, 0 }, - { CKA_SENSITIVE, NULL, 0 }, - { CKA_ALWAYS_SENSITIVE, NULL, 0 }, - { CKA_EXTRACTABLE, NULL, 0 }, - { CKA_NEVER_EXTRACTABLE, NULL, 0 }, - /* 13 to 17 */ - { CKA_LABEL, NULL, 0 }, /* optional */ - { CKA_ID, NULL, 0 }, /* optional */ - { CKA_SUBJECT, NULL, 0 }, /* optional */ - { CKA_START_DATE, NULL, 0 }, /* optional */ - { CKA_END_DATE, NULL, 0 } /* optional */ - /* not displaying CKA_KEY_GEN_MECHANISM */ - }; - CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); - int i; - char *hex_id = NULL; - int hex_id_len = 0; - char *hex_subject = NULL; - int hex_subject_len = 0; - - cryptodebug("inside display_prikey"); - - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get private key attribute sizes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } - - /* Allocate memory for each variable-length attribute. */ - for (i = 3; i < n_attrs; i++) { - if (attrs[i].ulValueLen == (CK_ULONG)-1 || - attrs[i].ulValueLen == 0) { - cryptodebug("display_prikey: *** should not happen"); - attrs[i].ulValueLen = 0; - continue; - } - if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_prikey; + if (key->keyclass == KMF_ASYM_PUB) { + if (key->keyalg == KMF_RSA) + return (gettext("RSA public key")); + if (key->keyalg == KMF_DSA) + return (gettext("DSA public key")); + } + if (key->keyclass == KMF_ASYM_PRI) { + if (key->keyalg == KMF_RSA) + return ("RSA private key"); + if (key->keyalg == KMF_DSA) + return ("DSA private key"); + } + if (key->keyclass == KMF_SYMMETRIC) { + switch (key->keyalg) { + case KMF_AES: + return (gettext("AES")); + break; + case KMF_RC4: + return (gettext("ARCFOUR")); + break; + case KMF_DES: + return (gettext("DES")); + break; + case KMF_DES3: + return (gettext("Triple-DES")); + break; + default: + return (gettext("symmetric")); + break; } } - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get private key attributes (%s)."), - pkcs11_strerror(rv)); - goto free_display_prikey; + return (gettext("unrecognized key object")); + +} + +static char * +keybitstr(KMF_KEY_HANDLE *key) +{ + KMF_RAW_SYM_KEY *rkey; + char keystr[256]; + char *p; + + if (key == NULL || (key->keyclass != KMF_SYMMETRIC)) + return (""); + + rkey = (KMF_RAW_SYM_KEY *)key->keyp; + (void) memset(keystr, 0, sizeof (keystr)); + if (rkey != NULL) { + (void) snprintf(keystr, sizeof (keystr), + " (%d bits)", rkey->keydata.len * 8); + p = keystr; + } else { + return (""); } - /* Fill in all the optional temp variables. */ - i = 13; - copy_attr_to_string(&(attrs[i++]), &label, &label_len); - copy_attr_to_string(&(attrs[i++]), &id, &id_len); - copy_attr_to_string(&(attrs[i++]), &subject, &subject_len); - copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len); - copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len); - - /* Get the key size for the object. */ - key_size = get_key_size(sess, obj, key_type); - - /* Display the object ... */ - /* ... the label and what it is (and key size in bits) ... */ - (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"), - counter, label_len, label_len > 0 ? (char *)label : - gettext("<no label>"), key_size, keytype_str(key_type), - class_str(CKO_PRIVATE_KEY)); - - /* ... the id ... */ - if (id_len == (CK_ULONG)-1 || id_len == 0) - (void) fprintf(stdout, gettext("\tId: --\n")); - else { - hex_id_len = 3 * id_len + 1; - if ((hex_id = malloc(hex_id_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_prikey; + return (p); +} + +static void +pk_show_keys(void *handle, KMF_KEY_HANDLE *keys, int numkeys) +{ + int i; + + for (i = 0; i < numkeys; i++) { + (void) fprintf(stdout, gettext("Key #%d - %s: %s%s"), + i+1, describeKey(&keys[i]), + keys[i].keylabel ? keys[i].keylabel : + gettext("No label"), + (keys[i].keyclass == KMF_SYMMETRIC ? + keybitstr(&keys[i]) : "")); + + if (keys[i].keyclass == KMF_SYMMETRIC) { + KMF_RETURN rv; + KMF_RAW_SYM_KEY rkey; + rv = KMF_GetSymKeyValue(handle, &keys[i], + &rkey); + if (rv == KMF_OK) { + (void) fprintf(stdout, "\t %d bits", + rkey.keydata.len * 8); + KMF_FreeRawSymKey(&rkey); + } } - octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60, - "\n\t\t", ""); - (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id); - free(hex_id); + (void) fprintf(stdout, "\n"); } +} - /* ... the subject name ... */ - if (subject_len == (CK_ULONG)-1 || subject_len == 0) - (void) fprintf(stdout, gettext("\tSubject: --\n")); - else { - hex_subject_len = 2 * subject_len + 1; /* best guesstimate */ - if ((hex_subject = malloc(hex_subject_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_prikey; +/* + * Generic routine used by all "list cert" operations to find + * all matching certificates. + */ +static KMF_RETURN +pk_find_certs(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_X509_DER_CERT *certlist = NULL; + uint32_t numcerts = 0; + + numcerts = 0; + rv = KMF_FindCert(kmfhandle, params, NULL, &numcerts); + if (rv == KMF_OK && numcerts > 0) { + (void) printf(gettext("Found %d certificates.\n"), + numcerts); + certlist = (KMF_X509_DER_CERT *)malloc(numcerts * + sizeof (KMF_X509_DER_CERT)); + if (certlist == NULL) + return (KMF_ERR_MEMORY); + (void) memset(certlist, 0, numcerts * + sizeof (KMF_X509_DER_CERT)); + + rv = KMF_FindCert(kmfhandle, params, certlist, &numcerts); + if (rv == KMF_OK) { + int i; + (void) pk_show_certs(kmfhandle, certlist, + numcerts); + for (i = 0; i < numcerts; i++) + KMF_FreeKMFCert(kmfhandle, &certlist[i]); } - rdnseq_to_str(subject, subject_len, hex_subject, - hex_subject_len); - (void) fprintf(stdout, gettext("\tSubject: %.*s\n"), - hex_subject_len, hex_subject); - free(hex_subject); + free(certlist); } + if (rv == KMF_ERR_CERT_NOT_FOUND && + params->kstype != KMF_KEYSTORE_OPENSSL) + rv = KMF_OK; - /* ... the start date ... */ - if (start_date_len == (CK_ULONG)-1 || start_date_len == 0) - (void) fprintf(stdout, gettext("\tStart Date: --\n")); - else - (void) fprintf(stdout, gettext( - "\tStart Date: %02.2s/%02.2s/%04.4s\n"), - start_date->month, start_date->day, start_date->year); - - /* ... the end date ... */ - if (end_date_len == (CK_ULONG)-1 || end_date_len == 0) - (void) fprintf(stdout, gettext("\tEnd Date: --\n")); - else - (void) fprintf(stdout, gettext( - "\tEnd Date: %02.2s/%02.2s/%04.4s\n"), - end_date->month, end_date->day, end_date->year); - - /* ... and its capabilities */ - (void) fprintf(stdout, "\t(%s, %s", - private != pk_false ? gettext("private") : gettext("public"), - modifiable == B_TRUE ? gettext("modifiable") : - gettext("not modifiable")); - for (i = 3; i <= 12; i++) { - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0 && - *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE) - (void) fprintf(stdout, ", %s", attr_str(attrs[i].type)); - } - (void) fprintf(stdout, ")\n"); + return (rv); +} -free_display_prikey: - for (i = 3; i < n_attrs; i++) - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0) - free(attrs[i].pValue); +static KMF_RETURN +pk_list_keys(void *handle, KMF_FINDKEY_PARAMS *parms) +{ + KMF_RETURN rv; + KMF_KEY_HANDLE *keys; + uint32_t numkeys = 0; + + numkeys = 0; + rv = KMF_FindKey(handle, parms, NULL, &numkeys); + if (rv == KMF_OK && numkeys > 0) { + int i; + (void) printf(gettext("Found %d keys.\n"), numkeys); + keys = (KMF_KEY_HANDLE *)malloc(numkeys * + sizeof (KMF_KEY_HANDLE)); + if (keys == NULL) + return (KMF_ERR_MEMORY); + (void) memset(keys, 0, numkeys * + sizeof (KMF_KEY_HANDLE)); + + rv = KMF_FindKey(handle, parms, keys, &numkeys); + if (rv == KMF_OK) + pk_show_keys(handle, keys, numkeys); + for (i = 0; i < numkeys; i++) + KMF_FreeKMFKey(handle, &keys[i]); + free(keys); + } + if (rv == KMF_ERR_KEY_NOT_FOUND && + parms->kstype != KMF_KEYSTORE_OPENSSL) + rv = KMF_OK; return (rv); } -/* - * Display public key. - */ -static CK_RV -display_pubkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter) +static KMF_RETURN +list_pk11_objects(KMF_HANDLE_T kmfhandle, char *token, int oclass, + char *objlabel, KMF_BIGINT *serial, char *issuer, char *subject, + char *dir, char *filename, KMF_CREDENTIAL *tokencred, + KMF_CERT_VALIDITY find_criteria_flag) { - CK_RV rv = CKR_OK; - static CK_BBOOL private; - static CK_BBOOL modifiable; - static CK_BBOOL trusted; - static CK_KEY_TYPE key_type; - CK_ULONG key_size; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_BYTE *subject = NULL; - CK_ULONG subject_len = 0; - CK_DATE *start_date = NULL; - CK_ULONG start_date_len = 0; - CK_DATE *end_date = NULL; - CK_ULONG end_date_len = 0; - CK_ATTRIBUTE attrs[15] = { - /* 0 to 3 */ - { CKA_PRIVATE, &private, sizeof (private) }, - { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) }, - { CKA_TRUSTED, &trusted, sizeof (trusted) }, - { CKA_KEY_TYPE, &key_type, sizeof (key_type) }, - /* 4 to 9 */ - { CKA_DERIVE, NULL, 0 }, - { CKA_LOCAL, NULL, 0 }, - { CKA_ENCRYPT, NULL, 0 }, - { CKA_VERIFY, NULL, 0 }, - { CKA_VERIFY_RECOVER, NULL, 0 }, - { CKA_WRAP, NULL, 0 }, - /* 10 to 14 */ - { CKA_LABEL, NULL, 0 }, /* optional */ - { CKA_ID, NULL, 0 }, /* optional */ - { CKA_SUBJECT, NULL, 0 }, /* optional */ - { CKA_START_DATE, NULL, 0 }, /* optional */ - { CKA_END_DATE, NULL, 0 } /* optional */ - /* not displaying CKA_KEY_GEN_MECHANISM */ - }; - CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); - int i; - char *hex_id = NULL; - int hex_id_len = 0; - char *hex_subject = NULL; - int hex_subject_len = 0; - - cryptodebug("inside display_pubkey"); - - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get public key attribute sizes (%s)."), - pkcs11_strerror(rv)); + KMF_RETURN rv; + KMF_LISTCRL_PARAMS lcrlargs; + + /* + * Symmetric keys and RSA/DSA private keys are always + * created with the "CKA_PRIVATE" field == TRUE, so + * make sure we search for them with it also set. + */ + if (oclass & (PK_SYMKEY_OBJ | PK_PRIKEY_OBJ)) + oclass |= PK_PRIVATE_OBJ; + + rv = select_token(kmfhandle, token, + !(oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ))); + + if (rv != KMF_OK) { return (rv); } - /* Allocate memory for each variable-length attribute. */ - for (i = 4; i < n_attrs; i++) { - if (attrs[i].ulValueLen == (CK_ULONG)-1 || - attrs[i].ulValueLen == 0) { - cryptodebug("display_pubkey: *** should not happen"); - attrs[i].ulValueLen = 0; - continue; + if (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ)) { + KMF_FINDKEY_PARAMS parms; + + (void) memset(&parms, 0, sizeof (parms)); + parms.kstype = KMF_KEYSTORE_PK11TOKEN; + + if (oclass & PK_PRIKEY_OBJ) { + parms.keyclass = KMF_ASYM_PRI; + parms.findLabel = objlabel; + parms.cred = *tokencred; + parms.pkcs11parms.private = + ((oclass & PK_PRIVATE_OBJ) > 0); + + /* list asymmetric private keys */ + rv = pk_list_keys(kmfhandle, &parms); } - if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_pubkey; + + if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { + parms.keyclass = KMF_SYMMETRIC; + parms.findLabel = objlabel; + parms.cred = *tokencred; + parms.format = KMF_FORMAT_RAWKEY; + parms.pkcs11parms.private = + ((oclass & PK_PRIVATE_OBJ) > 0); + + /* list symmetric keys */ + rv = pk_list_keys(kmfhandle, &parms); } - } - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get public key attributes (%s)."), - pkcs11_strerror(rv)); - goto free_display_pubkey; - } + if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { + parms.keyclass = KMF_ASYM_PUB; + parms.findLabel = objlabel; + parms.pkcs11parms.private = + ((oclass & PK_PRIVATE_OBJ) > 0); - /* Fill in all the optional temp variables. */ - i = 10; - copy_attr_to_string(&(attrs[i++]), &label, &label_len); - copy_attr_to_string(&(attrs[i++]), &id, &id_len); - copy_attr_to_string(&(attrs[i++]), &subject, &subject_len); - copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len); - copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len); - - /* Get the key size for the object. */ - key_size = get_key_size(sess, obj, key_type); - - /* Display the object ... */ - /* ... the label and what it is (and key size in bits) ... */ - (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"), - counter, label_len, label_len > 0 ? (char *)label : - gettext("<no label>"), key_size, keytype_str(key_type), - class_str(CKO_PUBLIC_KEY)); - - /* ... the id ... */ - if (id_len == (CK_ULONG)-1 || id_len == 0) - (void) fprintf(stdout, gettext("\tId: --\n")); - else { - hex_id_len = 3 * id_len + 1; - if ((hex_id = malloc(hex_id_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_pubkey; + /* list asymmetric public keys (if any) */ + rv = pk_list_keys(kmfhandle, &parms); } - octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60, - "\n\t\t", ""); - (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id); - free(hex_id); + + if (rv != KMF_OK) + return (rv); } - /* ... the subject name ... */ - if (subject_len == (CK_ULONG)-1 || subject_len == 0) - (void) fprintf(stdout, gettext("\tSubject: --\n")); - else { - hex_subject_len = 2 * subject_len + 1; /* best guesstimate */ - if ((hex_subject = malloc(hex_subject_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_pubkey; - } - rdnseq_to_str(subject, subject_len, hex_subject, - hex_subject_len); - (void) fprintf(stdout, gettext("\tSubject: %.*s\n"), - hex_subject_len, hex_subject); - free(hex_subject); + if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { + KMF_FINDCERT_PARAMS parms; + + (void) memset(&parms, 0, sizeof (parms)); + parms.kstype = KMF_KEYSTORE_PK11TOKEN; + parms.certLabel = objlabel; + parms.issuer = issuer; + parms.subject = subject; + parms.serial = serial; + parms.pkcs11parms.private = FALSE; + parms.find_cert_validity = find_criteria_flag; + + rv = pk_find_certs(kmfhandle, &parms); + if (rv != KMF_OK) + return (rv); } - /* ... the start date ... */ - if (start_date_len == (CK_ULONG)-1 || start_date_len == 0) - (void) fprintf(stdout, gettext("\tStart Date: --\n")); - else - (void) fprintf(stdout, gettext( - "\tStart Date: %02.2s/%02.2s/%04.4s\n"), - start_date->month, start_date->day, start_date->year); - - /* ... the end date ... */ - if (end_date_len == (CK_ULONG)-1 || end_date_len == 0) - (void) fprintf(stdout, gettext("\tEnd Date: --\n")); - else - (void) fprintf(stdout, gettext( - "\tEnd Date: %02.2s/%02.2s/%04.4s\n"), - end_date->month, end_date->day, end_date->year); - - /* ... and its capabilities */ - (void) fprintf(stdout, "\t(%s, %s, %s", - private == B_TRUE ? gettext("private") : gettext("public"), - modifiable == B_TRUE ? gettext("modifiable") : - gettext("not modifiable"), - trusted == B_TRUE ? gettext("trusted") : gettext("untrusted")); - for (i = 4; i <= 9; i++) { - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0 && - *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE) - (void) fprintf(stdout, ", %s", attr_str(attrs[i].type)); + if (oclass & PK_CRL_OBJ) { + char *crldata; + + (void) memset(&lcrlargs, 0, sizeof (lcrlargs)); + lcrlargs.kstype = KMF_KEYSTORE_OPENSSL; + lcrlargs.sslparms.dirpath = dir; + lcrlargs.sslparms.crlfile = filename; + + rv = KMF_ListCRL(kmfhandle, &lcrlargs, &crldata); + if (rv == KMF_OK) { + (void) printf("%s\n", crldata); + free(crldata); + } } - (void) fprintf(stdout, ")\n"); -free_display_pubkey: - for (i = 4; i < n_attrs; i++) - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0) - free(attrs[i].pValue); return (rv); } -/* - * Display secret key. - */ -static CK_RV -display_seckey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter) +static int +list_file_objects(KMF_HANDLE_T kmfhandle, int oclass, + char *dir, char *filename, KMF_BIGINT *serial, + char *issuer, char *subject, + KMF_CERT_VALIDITY find_criteria_flag) { - CK_RV rv = CKR_OK; - static CK_BBOOL private; - static CK_BBOOL modifiable; - static CK_KEY_TYPE key_type; - static CK_ULONG key_size; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_DATE *start_date = NULL; - CK_ULONG start_date_len = 0; - CK_DATE *end_date = NULL; - CK_ULONG end_date_len = 0; - CK_ATTRIBUTE attrs[19] = { - /* 0 to 2 */ - { CKA_PRIVATE, &private, sizeof (private) }, - { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) }, - { CKA_KEY_TYPE, &key_type, sizeof (key_type) }, - /* 3 to 14 */ - { CKA_DERIVE, NULL, 0 }, - { CKA_LOCAL, NULL, 0 }, - { CKA_ENCRYPT, NULL, 0 }, - { CKA_DECRYPT, NULL, 0 }, - { CKA_SIGN, NULL, 0 }, - { CKA_VERIFY, NULL, 0 }, - { CKA_WRAP, NULL, 0 }, - { CKA_UNWRAP, NULL, 0 }, - { CKA_SENSITIVE, NULL, 0 }, - { CKA_ALWAYS_SENSITIVE, NULL, 0 }, - { CKA_EXTRACTABLE, NULL, 0 }, - { CKA_NEVER_EXTRACTABLE, 0 }, - /* 15 to 18 */ - { CKA_LABEL, NULL, 0 }, /* optional */ - { CKA_ID, NULL, 0 }, /* optional */ - { CKA_START_DATE, NULL, 0 }, /* optional */ - { CKA_END_DATE, NULL, 0 } /* optional */ - /* not displaying CKA_KEY_GEN_MECHANISM */ - }; - CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); - int i; - char *hex_id = NULL; - int hex_id_len = 0; - - cryptodebug("inside display_seckey"); - - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get secret key attribute sizes (%s)."), - pkcs11_strerror(rv)); - return (rv); - } - - /* Allocate memory for each variable-length attribute. */ - for (i = 3; i < n_attrs; i++) { - if (attrs[i].ulValueLen == (CK_ULONG)-1 || - attrs[i].ulValueLen == 0) { - cryptodebug("display_seckey: *** should not happen"); - attrs[i].ulValueLen = 0; - continue; + int rv; + KMF_FINDCERT_PARAMS fcargs; + KMF_FINDKEY_PARAMS fkargs; + KMF_LISTCRL_PARAMS lcrlargs; + + if (oclass & PK_KEY_OBJ) { + (void) memset(&fkargs, 0, sizeof (fkargs)); + fkargs.kstype = KMF_KEYSTORE_OPENSSL; + fkargs.sslparms.dirpath = dir; + fkargs.sslparms.keyfile = filename; + if (oclass & PK_PRIKEY_OBJ) { + fkargs.keyclass = KMF_ASYM_PRI; + + rv = pk_list_keys(kmfhandle, &fkargs); } - if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_seckey; - } - } + if (rv == KMF_ERR_KEY_NOT_FOUND) + rv = KMF_OK; - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get secret key attributes (%s)."), - pkcs11_strerror(rv)); - goto free_display_seckey; - } + if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { + fkargs.keyclass = KMF_SYMMETRIC; + fkargs.format = KMF_FORMAT_RAWKEY; - /* Fill in all the optional temp variables. */ - i = 15; - copy_attr_to_string(&(attrs[i++]), &label, &label_len); - copy_attr_to_string(&(attrs[i++]), &id, &id_len); - copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len); - copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len); - - /* Get the key size for the object. */ - key_size = get_key_size(sess, obj, key_type); - - /* Display the object ... */ - /* ... the label and what it is (and key size in bytes) ... */ - (void) fprintf(stdout, gettext("%d. \"%.*s\" (%d-bit %s %s)\n"), - counter, label_len, label_len > 0 ? (char *)label : - gettext("<no label>"), key_size, keytype_str(key_type), - class_str(CKO_SECRET_KEY)); - - /* ... the id ... */ - if (id_len == (CK_ULONG)-1 || id_len == 0) - (void) fprintf(stdout, gettext("\tId: --\n")); - else { - hex_id_len = 3 * id_len + 1; - if ((hex_id = malloc(hex_id_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_seckey; + rv = pk_list_keys(kmfhandle, &fkargs); + } + if (rv == KMF_ERR_KEY_NOT_FOUND) + rv = KMF_OK; + if (rv != KMF_OK) + return (rv); + } + + if (oclass & PK_CERT_OBJ) { + (void) memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = KMF_KEYSTORE_OPENSSL; + fcargs.certLabel = NULL; + fcargs.issuer = issuer; + fcargs.subject = subject; + fcargs.serial = serial; + fcargs.sslparms.dirpath = dir; + fcargs.sslparms.certfile = filename; + fcargs.find_cert_validity = find_criteria_flag; + + rv = pk_find_certs(kmfhandle, &fcargs); + if (rv != KMF_OK) + return (rv); + } + + if (oclass & PK_CRL_OBJ) { + char *crldata; + + (void) memset(&lcrlargs, 0, sizeof (lcrlargs)); + lcrlargs.kstype = KMF_KEYSTORE_OPENSSL; + lcrlargs.sslparms.dirpath = dir; + lcrlargs.sslparms.crlfile = filename; + + rv = KMF_ListCRL(kmfhandle, &lcrlargs, &crldata); + if (rv == KMF_OK) { + (void) printf("%s\n", crldata); + free(crldata); } - octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60, - "\n\t\t", ""); - (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id); - free(hex_id); - } - - /* ... the start date ... */ - if (start_date_len == (CK_ULONG)-1 || start_date_len == 0) - (void) fprintf(stdout, gettext("\tStart Date: --\n")); - else - (void) fprintf(stdout, gettext( - "\tStart Date: %02.2s/%02.2s/%04.4s\n"), - start_date->month, start_date->day, start_date->year); - - /* ... the end date ... */ - if (end_date_len == (CK_ULONG)-1 || end_date_len == 0) - (void) fprintf(stdout, gettext("\tEnd Date: --\n")); - else - (void) fprintf(stdout, gettext( - "\tEnd Date: %02.2s/%02.2s/%04.4s\n"), - end_date->month, end_date->day, end_date->year); - - /* ... and its capabilities */ - (void) fprintf(stdout, "\t(%s, %s", - private == B_TRUE ? gettext("private") : gettext("public"), - modifiable == B_TRUE ? gettext("modifiable") : - gettext("not modifiable")); - for (i = 3; i <= 14; i++) { - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0 && - *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE) - (void) fprintf(stdout, ", %s", attr_str(attrs[i].type)); } - (void) fprintf(stdout, ")\n"); -free_display_seckey: - for (i = 3; i < n_attrs; i++) - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0) - free(attrs[i].pValue); return (rv); } -/* - * Display certificate. - */ -static CK_RV -display_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter) +static int +list_nss_objects(KMF_HANDLE_T kmfhandle, + int oclass, char *token_spec, char *dir, char *prefix, + char *nickname, KMF_BIGINT *serial, char *issuer, char *subject, + KMF_CREDENTIAL *tokencred, + KMF_CERT_VALIDITY find_criteria_flag) { - CK_RV rv = CKR_OK; - static CK_BBOOL private; - static CK_BBOOL modifiable; - static CK_BBOOL trusted; - CK_BYTE *subject = NULL; - CK_ULONG subject_len = 0; - CK_BYTE *value = NULL; - CK_ULONG value_len = 0; - CK_BYTE *label = NULL; - CK_ULONG label_len = 0; - CK_BYTE *id = NULL; - CK_ULONG id_len = 0; - CK_BYTE *issuer = NULL; - CK_ULONG issuer_len = 0; - CK_BYTE *serial = NULL; - CK_ULONG serial_len = 0; - CK_ATTRIBUTE attrs[9] = { - { CKA_PRIVATE, &private, sizeof (private) }, - { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) }, - { CKA_TRUSTED, &trusted, sizeof (trusted) }, - { CKA_SUBJECT, NULL, 0 }, /* required */ - { CKA_VALUE, NULL, 0 }, /* required */ - { CKA_LABEL, NULL, 0 }, /* optional */ - { CKA_ID, NULL, 0 }, /* optional */ - { CKA_ISSUER, NULL, 0 }, /* optional */ - { CKA_SERIAL_NUMBER, NULL, 0 } /* optional */ - }; - CK_ULONG n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE); - int i; - char *hex_id = NULL; - int hex_id_len = 0; - char *hex_subject = NULL; - int hex_subject_len = 0; - char *hex_issuer = NULL; - int hex_issuer_len = 0; - char *hex_serial = NULL; - int hex_serial_len = NULL; - uint32_t serial_value = 0; - char *hex_value = NULL; - int hex_value_len = 0; - - cryptodebug("inside display_cert"); - - /* Get the sizes of the attributes we need. */ - cryptodebug("calling C_GetAttributeValue for size info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get certificate attribute sizes (%s)."), - pkcs11_strerror(rv)); + KMF_RETURN rv = KMF_OK; + KMF_FINDKEY_PARAMS fkargs; + + rv = configure_nss(kmfhandle, dir, prefix); + if (rv != KMF_OK) return (rv); - } - /* Allocate memory for each variable-length attribute. */ - for (i = 3; i < n_attrs; i++) { - if (attrs[i].ulValueLen == (CK_ULONG)-1 || - attrs[i].ulValueLen == 0) { - cryptodebug("display_cert: *** should not happen"); - attrs[i].ulValueLen = 0; - continue; - } - if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_cert; - } + if (oclass & PK_KEY_OBJ) { + (void) memset(&fkargs, 0, sizeof (fkargs)); + fkargs.kstype = KMF_KEYSTORE_NSS; + fkargs.findLabel = nickname; + fkargs.cred = *tokencred; + fkargs.nssparms.slotlabel = token_spec; } - /* Now really get the attributes. */ - cryptodebug("calling C_GetAttributeValue for attribute info"); - if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get certificate attributes (%s)."), - pkcs11_strerror(rv)); - goto free_display_cert; + if (oclass & PK_PRIKEY_OBJ) { + fkargs.keyclass = KMF_ASYM_PRI; + rv = pk_list_keys(kmfhandle, &fkargs); } - - /* - * Fill in all the temp variables. Subject and value are required. - * The rest are optional. - */ - i = 3; - copy_attr_to_string(&(attrs[i++]), &subject, &subject_len); - copy_attr_to_string(&(attrs[i++]), &value, &value_len); - copy_attr_to_string(&(attrs[i++]), &label, &label_len); - copy_attr_to_string(&(attrs[i++]), &id, &id_len); - copy_attr_to_string(&(attrs[i++]), &issuer, &issuer_len); - copy_attr_to_string(&(attrs[i++]), &serial, &serial_len); - - /* Display the object ... */ - /* ... the label and what it is ... */ - (void) fprintf(stdout, gettext("%d. \"%.*s\" (%s %s)\n"), - counter, label_len, label_len > 0 ? (char *)label : - gettext("<no label>"), "X.509", class_str(CKO_CERTIFICATE)); - - /* ... its capabilities ... */ - (void) fprintf(stdout, gettext("\t(%s, %s, %s)\n"), - private == B_TRUE ? gettext("private") : gettext("public"), - modifiable == B_TRUE ? gettext("modifiable") : - gettext("not modifiable"), - trusted == B_TRUE ? gettext("trusted") : gettext("untrusted")); - - /* ... the id ... */ - if (id_len == (CK_ULONG)-1 || id_len == 0) - (void) fprintf(stdout, gettext("\tId: --\n")); - else { - hex_id_len = 3 * id_len + 1; - if ((hex_id = malloc(hex_id_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_cert; - } - octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60, - "\n\t\t", ""); - (void) fprintf(stdout, gettext("\tId: %s\n"), hex_id); - free(hex_id); + if (rv == KMF_OK && (oclass & PK_SYMKEY_OBJ)) { + fkargs.keyclass = KMF_SYMMETRIC; + fkargs.format = KMF_FORMAT_RAWKEY; + rv = pk_list_keys(kmfhandle, &fkargs); } - - /* ... the subject name ... */ - if (subject_len == (CK_ULONG)-1 || subject_len == 0) - (void) fprintf(stdout, gettext("\tSubject: --\n")); - else { - hex_subject_len = 2 * subject_len + 1; /* best guesstimate */ - if ((hex_subject = malloc(hex_subject_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_cert; - } - rdnseq_to_str(subject, subject_len, hex_subject, - hex_subject_len); - (void) fprintf(stdout, gettext("\tSubject: %.*s\n"), - hex_subject_len, hex_subject); - free(hex_subject); + if (rv == KMF_OK && (oclass & PK_PUBKEY_OBJ)) { + fkargs.keyclass = KMF_ASYM_PUB; + rv = pk_list_keys(kmfhandle, &fkargs); } - /* ... the issuer name ... */ - if (issuer_len == (CK_ULONG)-1 || issuer_len == 0) - (void) fprintf(stdout, gettext("\tIssuer: --\n")); - else { - hex_issuer_len = 2 * issuer_len + 1; /* best guesstimate */ - if ((hex_issuer = malloc(hex_issuer_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_cert; - } - rdnseq_to_str(issuer, issuer_len, hex_issuer, hex_issuer_len); - (void) fprintf(stdout, gettext("\tIssuer: %.*s\n"), - hex_issuer_len, hex_issuer); - free(hex_issuer); - } + /* If searching for public objects or certificates, find certs now */ + if (rv == KMF_OK && (oclass & PK_CERT_OBJ)) { + KMF_FINDCERT_PARAMS fcargs; - /* ... the serial number ... */ - if (serial_len == (CK_ULONG)-1 || serial_len == 0) - (void) fprintf(stdout, gettext("\tSerial: --\n")); - else { - hex_serial_len = 3 * serial_len + 1; - if ((hex_serial = malloc(hex_serial_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_cert; - } - octetify(serial, serial_len, hex_serial, hex_serial_len, - B_FALSE, B_FALSE, 60, "\n\t\t", ""); - if (serial_len > 4) - (void) fprintf(stdout, gettext("\tSerial: %s\n"), - hex_serial); - else { - for (i = 0; i < serial_len; i++) { - serial_value <<= 8; - serial_value |= (serial[i] & 0xff); - } - (void) fprintf(stdout, gettext("\tSerial: %s (%d)\n"), - hex_serial, serial_value); - } - free(hex_serial); + (void) memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = KMF_KEYSTORE_NSS; + fcargs.certLabel = nickname; + fcargs.issuer = issuer; + fcargs.subject = subject; + fcargs.serial = serial; + fcargs.nssparms.slotlabel = token_spec; + fcargs.find_cert_validity = find_criteria_flag; + + rv = pk_find_certs(kmfhandle, &fcargs); } - /* ... and the value */ - if (value_len == (CK_ULONG)-1 || value_len == 0) - (void) fprintf(stdout, gettext("\tValue: --\n")); - else { - hex_value_len = 3 * value_len + 1; - if ((hex_value = malloc(hex_value_len)) == NULL) { - cryptoerror(LOG_STDERR, "%s.", strerror(errno)); - rv = CKR_HOST_MEMORY; - goto free_display_cert; + if (rv == KMF_OK && (oclass & PK_CRL_OBJ)) { + int numcrls; + KMF_FINDCRL_PARAMS fcrlargs; + + (void) memset(&fcrlargs, 0, sizeof (fcrlargs)); + fcrlargs.kstype = KMF_KEYSTORE_NSS; + fcrlargs.nssparms.slotlabel = token_spec; + + rv = KMF_FindCRL(kmfhandle, &fcrlargs, NULL, &numcrls); + if (rv == KMF_OK) { + char **p; + if (numcrls == 0) { + (void) printf(gettext("No CRLs found in " + "NSS keystore.\n")); + + return (KMF_OK); + } + p = malloc(numcrls * sizeof (char *)); + if (p == NULL) { + return (KMF_ERR_MEMORY); + } + (void) memset(p, 0, numcrls * sizeof (char *)); + rv = KMF_FindCRL(kmfhandle, &fcrlargs, + p, &numcrls); + if (rv == KMF_OK) { + int i; + for (i = 0; i < numcrls; i++) { + (void) printf("%d. Name = %s\n", + i + 1, p[i]); + free(p[i]); + } + } + free(p); } - octetify(value, value_len, hex_value, hex_value_len, - B_FALSE, B_FALSE, 60, "\n\t\t", ""); - (void) fprintf(stdout, gettext("\tValue: %s\n"), hex_value); - free(hex_value); } - -free_display_cert: - for (i = 3; i < n_attrs; i++) - if (attrs[i].ulValueLen != (CK_ULONG)-1 && - attrs[i].ulValueLen != 0) - free(attrs[i].pValue); return (rv); } @@ -840,207 +527,189 @@ pk_list(int argc, char *argv[]) extern int optind_av; extern char *optarg_av; char *token_spec = NULL; - char *token_name = NULL; - char *manuf_id = NULL; - char *serial_no = NULL; - char *type_spec = NULL; - char full_name[FULL_NAME_LEN]; - boolean_t public_objs = B_FALSE; - boolean_t private_objs = B_FALSE; - CK_BYTE *list_label = NULL; - int obj_type = 0x00; - CK_SLOT_ID slot_id; - CK_FLAGS pin_state; - CK_UTF8CHAR_PTR pin = NULL; - CK_ULONG pinlen = 0; - CK_SESSION_HANDLE sess; - CK_OBJECT_HANDLE *objs; - CK_ULONG num_objs; - CK_RV rv = CKR_OK; - int i; - static CK_OBJECT_CLASS objclass; - CK_ATTRIBUTE class_attr = - { CKA_CLASS, &objclass, sizeof (objclass) }; - - cryptodebug("inside pk_list"); + char *subject = NULL; + char *issuer = NULL; + char *dir = NULL; + char *prefix = NULL; + char *filename = NULL; + char *serstr = NULL; + KMF_BIGINT serial = { NULL, 0 }; + + char *list_label = NULL; + int oclass = 0; + KMF_KEYSTORE_TYPE kstype = 0; + KMF_RETURN rv = KMF_OK; + KMF_HANDLE_T kmfhandle = NULL; + char *find_criteria = NULL; + KMF_CERT_VALIDITY find_criteria_flag = KMF_ALL_CERTS; + KMF_CREDENTIAL tokencred = {NULL, 0}; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, - "T:(token)y:(objtype)l:(label)")) != EOF) { + "k:(keystore)t:(objtype)T:(token)d:(dir)" + "p:(prefix)n:(nickname)S:(serial)s:(subject)" + "c:(criteria)" + "i:(issuer)l:(label)f:(infile)")) != EOF) { + if (EMPTYSTRING(optarg_av)) + return (PK_ERR_USAGE); switch (opt) { - case 'T': /* token specifier */ - if (token_spec) + case 'k': + if (kstype != 0) + return (PK_ERR_USAGE); + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 't': + if (oclass != 0) + return (PK_ERR_USAGE); + oclass = OT2Int(optarg_av); + if (oclass == -1) + return (PK_ERR_USAGE); + break; + case 's': + if (subject) + return (PK_ERR_USAGE); + subject = optarg_av; + break; + case 'i': + if (issuer) + return (PK_ERR_USAGE); + issuer = optarg_av; + break; + case 'd': + if (dir) + return (PK_ERR_USAGE); + dir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + case 'S': + serstr = optarg_av; + break; + case 'f': + if (filename) + return (PK_ERR_USAGE); + filename = optarg_av; + break; + case 'T': /* token specifier */ + if (token_spec) + return (PK_ERR_USAGE); + token_spec = optarg_av; + break; + case 'n': + case 'l': /* object with specific label */ + if (list_label) + return (PK_ERR_USAGE); + list_label = optarg_av; + break; + case 'c': + find_criteria = optarg_av; + if (!strcasecmp(find_criteria, "valid")) + find_criteria_flag = + KMF_NONEXPIRED_CERTS; + else if (!strcasecmp(find_criteria, "expired")) + find_criteria_flag = KMF_EXPIRED_CERTS; + else if (!strcasecmp(find_criteria, "both")) + find_criteria_flag = KMF_ALL_CERTS; + else + return (PK_ERR_USAGE); + break; + default: return (PK_ERR_USAGE); - token_spec = optarg_av; - break; - case 'y': /* object type: public, private, both */ - if (type_spec) - return (PK_ERR_USAGE); - type_spec = optarg_av; - break; - case 'l': /* object with specific label */ - if (list_label) - return (PK_ERR_USAGE); - list_label = (CK_BYTE *)optarg_av; - break; - default: - return (PK_ERR_USAGE); - break; } } + /* No additional args allowed. */ + argc -= optind_av; + argv += optind_av; + if (argc) + return (PK_ERR_USAGE); - /* If no token is specified, default is to use softtoken. */ - if (token_spec == NULL) { - token_name = SOFT_TOKEN_LABEL; - manuf_id = SOFT_MANUFACTURER_ID; - serial_no = SOFT_TOKEN_SERIAL; - } else { - /* - * Parse token specifier into token_name, manuf_id, serial_no. - * Token_name is required; manuf_id and serial_no are optional. - */ - if (parse_token_spec(token_spec, &token_name, &manuf_id, - &serial_no) < 0) - return (PK_ERR_USAGE); + if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { + /* Error message ? */ + return (rv); } - /* If no object type specified, default is public objects. */ - if (!type_spec) { - public_objs = B_TRUE; - } else { - /* - * Otherwise, the object type must be "public", "private", - * or "both". - */ - if (strcmp(type_spec, "private") == 0) { - private_objs = B_TRUE; - } else if (strcmp(type_spec, "public") == 0) { - public_objs = B_TRUE; - } else if (strcmp(type_spec, "both") == 0) { - private_objs = B_TRUE; - public_objs = B_TRUE; - } else - return (PK_ERR_USAGE); - } + /* Assume keystore = PKCS#11 if not specified. */ + if (kstype == 0) + kstype = KMF_KEYSTORE_PK11TOKEN; - if (private_objs) - obj_type |= PK_PRIVATE_OBJ; - if (public_objs) - obj_type |= PK_PUBLIC_OBJ; + /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ + if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && + kstype != KMF_KEYSTORE_PK11TOKEN) { - /* No additional args allowed. */ - argc -= optind_av; - argv += optind_av; - if (argc) + (void) fprintf(stderr, gettext("The objtype parameter " + "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); - /* Done parsing command line options. */ + } - full_token_name(token_name, manuf_id, serial_no, full_name); + /* If no object class specified, list certificate objects. */ + if (oclass == 0) + oclass = PK_CERT_OBJ; - /* Find the slot with token. */ - if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id, - &pin_state)) != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to find token %s (%s)."), full_name, - pkcs11_strerror(rv)); - return (PK_ERR_PK11); + if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { + token_spec = PK_DEFAULT_PK11TOKEN; + } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { + token_spec = DEFAULT_NSS_TOKEN; } - /* If private objects are to be listed, user must be logged in. */ - if (private_objs) { - /* Get the user's PIN. */ - if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, - &pin, &pinlen)) != CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to get token passphrase (%s)."), - pkcs11_strerror(rv)); - quick_finish(NULL); - return (PK_ERR_PK11); - } + if (serstr != NULL) { + uchar_t *bytes = NULL; + size_t bytelen; - /* Logging in user R/O into the token is sufficient. */ - cryptodebug("logging in with readonly session"); - if ((rv = quick_start(slot_id, 0, pin, pinlen, &sess)) != - CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to log into token (%s)."), - pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); - } - /* Otherwise, just create a session. */ - } else { - cryptodebug("opening a readonly session"); - if ((rv = open_sess(slot_id, 0, &sess)) != CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to open token session (%s)."), - pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); + rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen); + if (rv != KMF_OK || bytes == NULL) { + (void) fprintf(stderr, gettext("serial number " + "must be specified as a hex number " + "(ex: 0x0102030405ffeeddee)\n")); + return (PK_ERR_USAGE); } + serial.val = bytes; + serial.len = bytelen; } - /* Find the object(s) with the given label and/or type. */ - if ((rv = find_objs(sess, obj_type, list_label, &objs, &num_objs)) != - CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to find token objects (%s)."), pkcs11_strerror(rv)); - quick_finish(sess); - return (PK_ERR_PK11); - } + if ((kstype == KMF_KEYSTORE_PK11TOKEN || + kstype == KMF_KEYSTORE_NSS) && + (oclass & (PK_PRIKEY_OBJ | PK_PRIVATE_OBJ))) { - if (num_objs == 0) { - cryptoerror(LOG_STDERR, gettext("No objects found.")); - quick_finish(sess); - return (0); + (void) get_token_password(kstype, token_spec, + &tokencred); } + if (kstype == KMF_KEYSTORE_PK11TOKEN) { + rv = list_pk11_objects(kmfhandle, token_spec, + oclass, list_label, &serial, + issuer, subject, dir, filename, + &tokencred, find_criteria_flag); - /* List the objects found. */ - for (i = 0; i < num_objs; i++) { - /* Get object class first, then decide what is next. */ - cryptodebug("calling C_GetAttributeValue for object class"); - if ((rv = C_GetAttributeValue(sess, objs[i], &class_attr, 1)) - != CKR_OK) { - cryptoerror(LOG_STDERR, gettext( - "Unable to get object #%d class attribute (%s)."), - i+1, pkcs11_strerror(rv)); - continue; - } + } else if (kstype == KMF_KEYSTORE_NSS) { + if (dir == NULL) + dir = PK_DEFAULT_DIRECTORY; + rv = list_nss_objects(kmfhandle, + oclass, token_spec, dir, prefix, + list_label, &serial, issuer, subject, + &tokencred, find_criteria_flag); - /* Display based on the type of object. */ - switch (objclass) { - case CKO_CERTIFICATE: - if ((rv = display_cert(sess, objs[i], i+1)) != CKR_OK) - cryptoerror(LOG_STDERR, - gettext("Unable to display certificate.")); - break; - case CKO_PUBLIC_KEY: - if ((rv = display_pubkey(sess, objs[i], i+1)) != CKR_OK) - cryptoerror(LOG_STDERR, - gettext("Unable to display public key.")); - break; - case CKO_PRIVATE_KEY: - if ((rv = display_prikey(sess, objs[i], i+1)) != CKR_OK) - cryptoerror(LOG_STDERR, - gettext("Unable to display private key.")); - break; - case CKO_SECRET_KEY: - if ((rv = display_seckey(sess, objs[i], i+1)) != CKR_OK) - cryptoerror(LOG_STDERR, - gettext("Unable to display secret key.")); - break; - case CKO_DATA: - cryptoerror(LOG_STDERR, - gettext("Data object display not implemented.")); - break; - default: - cryptoerror(LOG_STDERR, gettext( - "Unknown token object class (0x%02x)."), objclass); - break; - } + } else if (kstype == KMF_KEYSTORE_OPENSSL) { + + rv = list_file_objects(kmfhandle, + oclass, dir, filename, + &serial, issuer, subject, find_criteria_flag); + } + + if (rv != KMF_OK) { + display_error(kmfhandle, rv, + gettext("Error listing objects")); } - /* Clean up. */ - quick_finish(sess); - return (0); + if (serial.val != NULL) + free(serial.val); + + if (tokencred.cred != NULL) + free(tokencred.cred); + + (void) KMF_Finalize(kmfhandle); + return (rv); } diff --git a/usr/src/cmd/cmd-crypto/pktool/osslcommon.c b/usr/src/cmd/cmd-crypto/pktool/osslcommon.c deleted file mode 100644 index 84b4fdbdce..0000000000 --- a/usr/src/cmd/cmd-crypto/pktool/osslcommon.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file implements some "missing" routines that should - * be part of the OpenSSL library but are not there yet. - */ - -#include <cryptoutil.h> -#include "osslcommon.h" -#include <openssl/pkcs12.h> -#include <openssl/engine.h> - -/* - * OpenSSL usage needs algorithms (ciphers and digests), strings, - * and engines loaded first to be useful. - */ -void -PKTOOL_setup_openssl(void) -{ - cryptodebug("inside PKTOOL_setup_openssl"); - - /* Add all ciphers and digests. */ - OpenSSL_add_all_algorithms(); - - /* Load up error message strings. */ - ERR_load_crypto_strings(); - - /* Load up PKCS#11 engine. */ - /* ENGINE_load_pk11(); */ - - /* Load up builtin crypto engines. */ - /* - * This function is actually defined in OpenSSL libcrypto - * library. However it doesn't make its lint library correctly - * which is why this lint error occurs. OpenSSL needs fixing. - * Do not put a LINTED comment here because lint will complain - * that the directive is ununsed. - */ - ENGINE_load_builtin_engines(); - - /* U/I methods are not necessary here. */ - /* setup_ui_method(); */ -} - -/* - * This should be an OpenSSL function, but they haven't added it yet. - * See <openssl>/crypto/asn1/x_x509a.c:X509_alias_get0() for the model. - */ -unsigned char * -PKTOOL_X509_keyid_get0(X509 *x, int *len) -{ - cryptodebug("inside PKTOOL_setup_openssl"); - - if (x->aux == NULL || x->aux->keyid == NULL) { - cryptodebug("certificate aux or aux->keyid is null"); - return (NULL); - } - if (len) - *len = x->aux->keyid->length; - return (x->aux->keyid->data); -} - -/* - * This should be an OpenSSL function, but couldn't find it yet. - * It gets the subject name safely without dereferencing null pointers. - * If it is ever found in OpenSSL, this should be removed and all - * calls to it need to be replaced with right OpenSSL function. - */ -unsigned char * -PKTOOL_X509_subject_name(X509 *x, int *len) -{ - X509_NAME *temp; - - cryptodebug("inside PKTOOL_X509_subject_name"); - - if ((temp = X509_get_subject_name(x)) == NULL) { - cryptodebug("certificate subject name stack is null"); - return (NULL); - } - if (temp->bytes == NULL) { - cryptodebug("certificate subject name stack bytes is null"); - return (NULL); - } - if (len) - *len = temp->bytes->length; - return ((unsigned char *)temp->bytes->data); -} - -/* - * This should be an OpenSSL function, but couldn't find it yet. - * It gets the issuer name safely without dereferencing null pointers. - * If it is ever found in OpenSSL, this should be removed and all - * calls to it need to be replaced with right OpenSSL function. - */ -unsigned char * -PKTOOL_X509_issuer_name(X509 *x, int *len) -{ - X509_NAME *temp; - - cryptodebug("inside PKTOOL_X509_issuer_name"); - - if ((temp = X509_get_issuer_name(x)) == NULL) { - cryptodebug("certificate issuer name stack is null"); - return (NULL); - } - if (temp->bytes == NULL) { - cryptodebug("certificate issuer name stack bytes is null"); - return (NULL); - } - if (len) - *len = temp->bytes->length; - return ((unsigned char *)temp->bytes->data); -} - -/* - * This should be an OpenSSL function, but couldn't find it yet. - * It gets the serial number safely without dereferencing null pointers. - * If it is ever found in OpenSSL, this should be removed and all - * calls to it need to be replaced with right OpenSSL function. - */ -unsigned char * -PKTOOL_X509_serial_number(X509 *x, int *len) -{ - ASN1_INTEGER *temp; - - cryptodebug("inside PKTOOL_X509_serial_number"); - - if ((temp = X509_get_serialNumber(x)) == NULL) { - cryptodebug("certificate serial number is null"); - return (NULL); - } - if (len) - *len = temp->length; - return (temp->data); -} - -/* - * This should be an OpenSSL function, but couldn't find it yet. - * It gets the cert value safely without dereferencing null pointers. - * If it is ever found in OpenSSL, this should be removed and all - * calls to it need to be replaced with right OpenSSL function. - */ -unsigned char * -PKTOOL_X509_cert_value(X509 *x, int *len) -{ - PKCS12_SAFEBAG *bag; - - cryptodebug("inside PKTOOL_X509_cert_value"); - - if ((bag = PKCS12_x5092certbag(x)) == NULL) { - cryptodebug("unable to convert cert to PKCS#12 bag"); - return (NULL); - } - if (bag->value.bag == NULL || bag->value.bag->value.x509cert == NULL) { - cryptodebug("PKCS#12 bag value or cert inside it is null"); - return (NULL); - } - if (len) - *len = bag->value.bag->value.x509cert->length; - return (bag->value.bag->value.x509cert->data); -} - -/* - * Convert OpenSSL's ASN1_TIME format into a character buffer that - * can then be converted into PKCS#11 format. The buffer must be - * at least 8 bytes long. The length of the result will be 8 bytes. - * Return value of 0 indicates failure, 1 indicates success. - */ -int -PKTOOL_cvt_ossltime(ASN1_TIME *t, char *buf) -{ - cryptodebug("inside PKTOOL_cvt_ossltime"); - - if (t == NULL) { - cryptodebug("time string is empty"); - buf[0] = '\0'; - return (0); - } - - if (t->length == 15) { /* generalized time: YYYYMMDDmmhhssZ */ - cryptodebug("time string is in generalized format"); - (void) snprintf(buf, 8, "%08.8s", t->data); - return (1); - } - - if (t->length == 13) { /* UTC time: YYMMDDmmhhssZ */ - cryptodebug("time string is in UTC format"); - /* Guess whether its a 197x to 199x date, or a 20xx date. */ - (void) snprintf(buf, 8, "%s%06.6s", - ('7' <= t->data[0] && t->data[0] <= '9') ? "19" : "20", - t->data); - return (1); - } - - cryptodebug("time string is in unknown format"); - buf[0] = '\0'; - return (0); -} diff --git a/usr/src/cmd/cmd-crypto/pktool/osslcommon.h b/usr/src/cmd/cmd-crypto/pktool/osslcommon.h deleted file mode 100644 index 098d0e1f6a..0000000000 --- a/usr/src/cmd/cmd-crypto/pktool/osslcommon.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _PKTOOL_OSSLCOMMON_H -#define _PKTOOL_OSSLCOMMON_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <openssl/x509.h> - -extern void PKTOOL_setup_openssl(void); -extern unsigned char *PKTOOL_X509_keyid_get0(X509 *x, int *len); -extern unsigned char *PKTOOL_X509_subject_name(X509 *x, int *len); -extern unsigned char *PKTOOL_X509_issuer_name(X509 *x, int *len); -extern unsigned char *PKTOOL_X509_serial_number(X509 *x, int *len); -extern unsigned char *PKTOOL_X509_cert_value(X509 *x, int *len); -extern int PKTOOL_cvt_ossltime(ASN1_TIME *t, char *buf); - -#ifdef __cplusplus -} -#endif - -#endif /* _PKTOOL_OSSLCOMMON_H */ diff --git a/usr/src/cmd/cmd-crypto/pktool/p12common.c b/usr/src/cmd/cmd-crypto/pktool/p12common.c deleted file mode 100644 index 4e164ea911..0000000000 --- a/usr/src/cmd/cmd-crypto/pktool/p12common.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file implements some of the common PKCS#12 routines. - */ - -#include <errno.h> -#include <string.h> -#include <cryptoutil.h> -#include "p12common.h" -#include <openssl/pkcs12.h> - -/* I18N helpers. */ -#include <libintl.h> -#include <locale.h> - -/* - * Common function to create/open PKCS#12 files. - */ -static int -pkcs12_file(char *filename, boolean_t create, BIO **fbio) -{ - cryptodebug("inside pkcs12_file"); - - if (fbio == NULL) { - cryptoerror(LOG_STDERR, create ? - gettext("Error creating file \"%s\", invalid input.") : - gettext("Error opening file \"%s\", invalid input."), - filename); - return (-1); - } - - cryptodebug(create ? "creating %s for binary writes" : - "opening %s for binary reads", filename); - if ((*fbio = BIO_new_file(filename, create ? "wb" : "rb")) == NULL) { - cryptoerror(LOG_STDERR, create ? - gettext("Error creating file \"%s\" (%s).") : - gettext("Error opening file \"%s\" (%s)."), - filename, strerror(errno)); - return (-1); - } - - return (0); -} - -/* - * Create PKCS#12 export file. - */ -int -create_pkcs12(char *filename, BIO **fbio) -{ - cryptodebug("inside create_pkcs12"); - - return (pkcs12_file(filename, B_TRUE, fbio)); -} - -/* - * Opens PKCS#12 import file. - */ -int -open_pkcs12(char *filename, BIO **fbio) -{ - cryptodebug("inside open_pkcs12"); - - return (pkcs12_file(filename, B_FALSE, fbio)); -} - -/* - * Closes PKCS#12 export file. - */ -void -close_pkcs12(BIO *fbio) -{ - cryptodebug("inside close_pkcs12"); - - BIO_free_all(fbio); -} diff --git a/usr/src/cmd/cmd-crypto/pktool/pktool.c b/usr/src/cmd/cmd-crypto/pktool/pktool.c index ce7a26235c..c97cf80063 100644 --- a/usr/src/cmd/cmd-crypto/pktool/pktool.c +++ b/usr/src/cmd/cmd-crypto/pktool/pktool.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -62,6 +61,10 @@ extern int pk_delete(int argc, char *argv[]); extern int pk_import(int argc, char *argv[]); extern int pk_export(int argc, char *argv[]); extern int pk_tokens(int argc, char *argv[]); +extern int pk_gencert(int argc, char *argv[]); +extern int pk_gencsr(int argc, char *argv[]); +extern int pk_download(int argc, char *argv[]); +extern int pk_genkey(int argc, char *argv[]); /* Forward declarations for "built-in" verb actions. */ static int pk_help(int argc, char *argv[]); @@ -70,45 +73,353 @@ static int pk_help(int argc, char *argv[]); static verbcmd cmds[] = { { "tokens", pk_tokens, 0, "tokens" }, { "setpin", pk_setpin, 0, - "setpin [token=<token>[:<manuf>[:<serial>]]]" }, + "setpin [ keystore=pkcs11 ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t" + + "setpin keystore=nss\n\t\t" + "[ token=token ]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t" + }, { "list", pk_list, 0, - "list [token=<token>[:<manuf>[:<serial>]]] " - "[objtype=private|public|both] [label=<label>]" }, + + "list [ token=token[:manuf[:serial]]]\n\t\t" + "[ objtype=private|public|both ]\n\t\t" + "[ label=label ]\n\t" + + "list objtype=cert[:[public | private | both ]]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ keystore=pkcs11 ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ label=cert-label ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ criteria=valid|expired|both ]\n\t" + + "list objtype=key[:[public | private | both ]]\n\t\t" + "[ keystore=pkcs11 ]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ label=key-label ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t" + + "list keystore=pkcs11 objtype=crl\n\t\t" + "infile=crl-fn\n\t\t" + "[ dir=directory-path ]\n\t" + + "list keystore=nss objtype=cert\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ nickname=cert-nickname ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ criteria=valid|expired|both ]\n\t" + + "list keystore=nss objtype=key\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ nickname=key-nickname ]\n\t" + + "list keystore=file objtype=cert\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ infile=cert-fn ]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ criteria=valid|expired|both ]\n\t" + + "list keystore=file objtype=key\n\t\t" + "[ infile=key-fn ]\n\t\t" + "[ dir=directory-path ]\n\t" + + "list keystore=file objtype=crl\n\t\t" + "infile=crl-fn\n\t\t" + "[ dir=directory-path ]\n\t" + }, + { "delete", pk_delete, 0, - "delete [token=<token>[:<manuf>[:<serial>]]] " - "{ [objtype=private|public|both] [label=<label>] }" }, + + "delete [ token=token[:manuf[:serial]]]\n\t\t" + "[ objtype=private|public|both ]\n\t\t" + "[ label=object-label ]\n\t" + + "delete keystore=nss objtype=cert\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ nickname=cert-nickname ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ criteria=valid|expired|both ]\n\t" + + "delete keystore=nss objtype=key\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ nickname=key-nickname ]\n\t\t" + + "delete keystore=nss objtype=crl\n\t\t" + "[ nickname=issuer-nickname ]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t" + + "delete keystore=pkcs11 objtype=cert[:[public | private | both]]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ label=cert-label ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ criteria=valid|expired|both ]\n\t" + + "delete keystore=pkcs11 objtype=key[:[public | private | both]]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ label=key-label ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t" + + "delete keystore=pkcs11 objtype=crl\n\t\t" + "infile=crl-fn\n\t\t" + "[ dir=directory-path ]\n\t" + + "delete keystore=file objtype=cert\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ infile=cert-fn ]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ criteria=valid|expired|both ]\n\t" + + "delete keystore=file objtype=key\n\t\t" + "[ infile=key-fn ]\n\t\t" + "[ dir=directory-path ]\n\t" + + "delete keystore=file objtype=crl\n\t\t" + "infile=crl-fn\n\t\t" + "[ dir=directory-path ]\n\t" + }, { "import", pk_import, 0, - "import [token=<token>[:<manuf>[:<serial>]]] infile=<file>" }, + + "import [token=token[:manuf[:serial]]]\n\t\t" + "infile=input-fn\n\t" + + "import keystore=nss objtype=cert\n\t\t" + "infile=input-fn\n\t\t" + "nickname=cert-nickname\n\t\t" + "[ trust=trust-value ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t" + + "import keystore=nss objtype=crl\n\t\t" + "infile=input-fn\n\t\t" + "[ verifycrl=y|n ]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t" + + "import keystore=pkcs11\n\t\t" + "infile=input-fn\n\t\t" + "label=cert-label\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t" + + "import keystore=pkcs11 objtype=crl\n\t\t" + "infile=input-crl-fn\n\t\t" + "outcrl=output-crl-fn\n\t\t" + "outformat=pem|der\n\t\t" + "[ dir=output-crl-directory-path ]\n\t" + + "import keystore=file\n\t\t" + "infile=input-fn\n\t\t" + "outkey=output-key-fn\n\t\t" + "outcert=output-cert-fn\n\t\t" + "[ dir=output-cert-dir-path ]\n\t\t" + "[ keydir=output-key-dir-path ]\n\t\t" + "[ outformat=pem|der|pkcs12 ]\n\t" + + "import keystore=file objtype=crl\n\t\t" + "infile=input-crl-fn\n\t\t" + "outcrl=output-crl-fn\n\t\t" + "outformat=pem|der\n\t\t" + "[ dir=output-crl-directory-path ]\n\t" + }, + { "export", pk_export, 0, - "export [token=<token>[:<manuf>[:<serial>]]] outfile=<file>" }, - { "-?", pk_help, 0, "help\t(help and usage)" }, + + "export [token=token[:manuf[:serial]]]\n\t\t" + "outfile=output-fn\n\t" + + "export keystore=nss\n\t\t" + "outfile=output-fn\n\t\t" + "[ objtype=cert|key ]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ nickname=cert-nickname]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBPrefix ]\n\t\t" + "[ outformat=pem|der|pkcs12 ]\n\t" + + "export keystore=pkcs11\n\t\t" + "outfile=output-fn\n\t\t" + "[ label=cert-label]\n\t\t" + "[ subject=subject-DN ]\n\t\t" + "[ issuer=issuer-DN ]\n\t\t" + "[ serial=serial number]\n\t\t" + "[ outformat=pem|der|pkcs12]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t" + + "export keystore=file\n\t\t" + "certfile=cert-input-fn\n\t\t" + "keyfile=key-input-fn\n\t\t" + "outfile=output-pkcs12-fn\n\t\t" + "[ dir=directory-path ]\n\t" + }, + + { "gencert", pk_gencert, 0, + "gencert [-i] keystore=nss\n\t\t" + "label=cert-nickname\n\t\t" + "serial=serial number hex string]\n\t\t" + "subject=subject-DN\n\t\t" + "[ altname=[critical:]SubjectAltName ]\n\t\t" + "[ keyusage=[critical:]usage,usage,...]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ keytype=rsa|dsa ]\n\t\t" + "[ keylen=key-size ]\n\t\t" + "[ trust=trust-value ]\n\t\t" + "[ lifetime=number-hour|number-day|number-year ]\n\t" + + "gencert [-i] [ keystore=pkcs11 ]\n\t\t" + "label=key/cert-label\n\t\t" + "subject=subject-DN\n\t\t" + "serial=serial number hex string\n\t\t" + "[ altname=[critical:]SubjectAltName ]\n\t\t" + "[ keyusage=[critical:]usage,usage,...]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ keytype=rsa|dsa ]\n\t\t" + "[ keylen=key-size ]\n\t\t" + "[ lifetime=number-hour|number-day|number-year ]\n\t" + + "gencert [-i] keystore=file\n\t\t" + "outcert=cert_filename\n\t\t" + "outkey=key_filename\n\t\t" + "subject=subject-DN\n\t\t" + "serial=serial number hex string\n\t\t" + "[ altname=[critical:]SubjectAltName ]\n\t\t" + "[ keyusage=[critical:]usage,usage,...]\n\t\t" + "[ format=der|pem ]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ keytype=rsa|dsa ]\n\t\t" + "[ keylen=key-size ]\n\t\t" + "[ lifetime=number-hour|number-day|number-year ]\n\t" + }, + { "gencsr", pk_gencsr, 0, + "gencsr [-i] keystore=nss \n\t\t" + "nickname=cert-nickname\n\t\t" + "outcsr=csr-fn\n\t\t" + "subject=subject-DN\n\t\t" + "[ altname=[critical:]SubjectAltName ]\n\t\t" + "[ keyusage=[critical:]usage,usage,...]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t\t" + "[ keytype=rsa|dsa ]\n\t\t" + "[ keylen=key-size ]\n\t\t" + "[ format=pem|der]\n\t" + "gencsr [-i] [ keystore=pkcs11 ]\n\t\t" + "label=key-label\n\t\t" + "outcsr=csr-fn\n\t\t" + "subject=subject-DN\n\t\t" + "[ altname=[critical:]SubjectAltName ]\n\t\t" + "[ keyusage=[critical:]usage,usage,...]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ keytype=rsa|dsa ]\n\t\t" + "[ keylen=key-size ]\n\t\t" + "[ format=pem|der]\n\t" + "gencsr [-i] keystore=file\n\t\t" + "outcsr=csr-fn\n\t\t" + "outkey=key-fn\n\t\t" + "subject=subject-DN\n\t\t" + "[ altname=[critical:]SubjectAltName ]\n\t\t" + "[ keyusage=[critical:]usage,usage,...]\n\t\t" + "[ keytype=rsa|dsa ]\n\t\t" + "[ keylen=key-size ]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ format=pem|der]\n\t" + }, + + { "download", pk_download, 0, + "download url=url_str\n\t\t" + "[ objtype=crl|cert ]\n\t\t" + "[ http_proxy=proxy_str ]\n\t\t" + "[ outfile = outfile ]\n\t\t" + }, + + { "genkey", pk_genkey, 0, + "genkey [ keystore=pkcs11 ]\n\t\t" + "label=key-label\n\t\t" + "[ keytype=aes|arcfour|des|3des ]\n\t\t" + "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ sensitive=y|n ]\n\t\t" + "[ extractable=y|n ]\n\t\t" + "[ print=y|n ]\n\t" + + "genkey keystore=nss\n\t\t" + "label=key-label\n\t\t" + "[ keytype=aes|arcfour|des|3des ]\n\t\t" + "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t" + "[ token=token[:manuf[:serial]]]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ prefix=DBprefix ]\n\t" + + "genkey keystore=file\n\t\t" + "outkey=key-fn\n\t\t" + "[ keytype=aes|arcfour|des|3des ]\n\t\t" + "[ keylen=key-size (AES or ARCFOUR only)]\n\t\t" + "[ dir=directory-path ]\n\t\t" + "[ print=y|n ]\n\t" + }, + + { "-?", pk_help, 0, "help\t(help and usage)" }, + { "-f", pk_help, 0, "-f option_file" } }; static int num_cmds = sizeof (cmds) / sizeof (verbcmd); static char *prog; -static void usage(void); +static void usage(int); /* * Usage information. This function must be updated when new verbs or * options are added. */ static void -usage(void) +usage(int idx) { int i; - cryptodebug("inside usage"); - /* Display this block only in command-line mode. */ (void) fprintf(stdout, gettext("Usage:\n")); (void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog); + (void) fprintf(stdout, gettext("\t%s -f option_file\n"), prog); (void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog); (void) fprintf(stdout, gettext("where subcommands may be:\n")); /* Display only those verbs that match the current tool mode. */ - for (i = 0; i < num_cmds; i++) { - /* Do NOT i18n/l10n. */ - (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis); + if (idx == -1) { + for (i = 0; i < num_cmds; i++) { + /* Do NOT i18n/l10n. */ + (void) fprintf(stdout, "\t%s\n", cmds[i].synopsis); + } + } else { + (void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis); } } @@ -119,9 +430,59 @@ static int pk_help(int argc, char *argv[]) /* ARGSUSED */ { - cryptodebug("inside pk_help"); + usage(-1); + return (0); +} + +/* + * Process arguments from the argfile and create a new + * argv/argc list to be processed later. + */ +static int +process_arg_file(char *argfile, char ***argv, int *argc) +{ + FILE *fp; + char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */ + char *p; + int nargs = 0; + + if ((fp = fopen(argfile, "rF")) == NULL) { + (void) fprintf(stderr, + gettext("Cannot read argfile %s: %s\n"), + argfile, strerror(errno)); + return (errno); + } - usage(); + while (fgets(argline, sizeof (argline), fp) != NULL) { + int j; + /* remove trailing whitespace */ + j = strlen(argline) - 1; + while (j >= 0 && isspace(argline[j])) { + argline[j] = 0; + j--; + } + /* If it was a blank line, get the next one. */ + if (!strlen(argline)) + continue; + + (*argv) = realloc((*argv), + (nargs + 1) * sizeof (char *)); + if ((*argv) == NULL) { + perror("memory error"); + (void) fclose(fp); + return (errno); + } + p = (char *)strdup(argline); + if (p == NULL) { + perror("memory error"); + (void) fclose(fp); + return (errno); + } + (*argv)[nargs] = p; + nargs++; + } + *argc = nargs; + (void) fclose(fp); return (0); } @@ -150,26 +511,24 @@ main(int argc, char *argv[], char *envp[]) argv++, argc--; /* Set up for debug and error output. */ - cryptodebug_init(prog); - if (argc == 0) { - usage(); + usage(-1); return (1); } /* Check for help options. For CLIP-compliance. */ - if (argc == 1 && argv[0][0] == '-') { - switch (argv[0][1]) { - case '?': - return (pk_help(argc, argv)); - default: - usage(); - return (1); - } + if (strcmp(argv[0], "-?") == 0) { + return (pk_help(argc, argv)); + } else if (strcmp(argv[0], "-f") == 0 && argc == 2) { + rv = process_arg_file(argv[1], &pk_argv, &pk_argc); + if (rv) + return (rv); + } else if (argc >= 1 && argv[0][0] == '-') { + usage(-1); + return (1); } /* Always turns off Metaslot so that we can see softtoken. */ - cryptodebug("disabling Metaslot"); if (setenv("METASLOT_ENABLED", "false", 1) < 0) { save_errno = errno; cryptoerror(LOG_STDERR, @@ -179,21 +538,18 @@ main(int argc, char *argv[], char *envp[]) } /* Begin parsing command line. */ - cryptodebug("begin parsing command line"); - pk_argc = argc; - pk_argv = argv; + if (pk_argc == 0 && pk_argv == NULL) { + pk_argc = argc; + pk_argv = argv; + } /* Check for valid verb (or an abbreviation of it). */ found = -1; for (i = 0; i < num_cmds; i++) { if (strcmp(cmds[i].verb, pk_argv[0]) == 0) { if (found < 0) { - cryptodebug("found cmd %s", cmds[i].verb); found = i; break; - } else { - cryptodebug("also found cmd %s, skipping", - cmds[i].verb); } } } @@ -205,36 +561,21 @@ main(int argc, char *argv[], char *envp[]) } /* Get to work! */ - cryptodebug("begin executing cmd action"); rv = (*cmds[found].action)(pk_argc, pk_argv); - cryptodebug("end executing cmd action"); switch (rv) { case PK_ERR_NONE: - cryptodebug("subcommand succeeded"); break; /* Command succeeded, do nothing. */ case PK_ERR_USAGE: - cryptodebug("usage error detected"); - usage(); + usage(found); break; case PK_ERR_QUIT: - cryptodebug("quit command received"); exit(0); /* NOTREACHED */ case PK_ERR_PK11: - cryptoerror(LOG_STDERR, "%s", - gettext("Command failed due to PKCS#11 error.")); - break; case PK_ERR_SYSTEM: - cryptoerror(LOG_STDERR, "%s", - gettext("Command failed due to system error.")); - break; case PK_ERR_OPENSSL: - cryptoerror(LOG_STDERR, "%s", - gettext("Command failed due to OpenSSL error.")); - break; + case PK_ERR_NSS: default: - cryptoerror(LOG_STDERR, "%s (%d).", - gettext("Unknown error value"), rv); break; } return (rv); diff --git a/usr/src/cmd/cmd-crypto/pktool/setpin.c b/usr/src/cmd/cmd-crypto/pktool/setpin.c index 038f57169e..62416e8c7d 100644 --- a/usr/src/cmd/cmd-crypto/pktool/setpin.c +++ b/usr/src/cmd/cmd-crypto/pktool/setpin.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,76 +40,90 @@ #include <security/cryptoki.h> #include "common.h" -/* - * Changes the token's PIN. - */ -int -pk_setpin(int argc, char *argv[]) -/* ARGSUSED */ +static int +setpin_nss(KMF_HANDLE_T handle, + char *token_spec, char *dir, char *prefix) { - int opt; - extern int optind_av; - extern char *optarg_av; - char *token_spec = NULL; - char *token_name = NULL; - char *manuf_id = NULL; - char *serial_no = NULL; - CK_SLOT_ID slot_id; - CK_FLAGS pin_state; - CK_SESSION_HANDLE sess; + int rv = 0; + KMF_SETPIN_PARAMS params; + KMF_CREDENTIAL newpincred = { NULL, 0 }; CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; CK_ULONG old_pinlen = 0, new_pinlen = 0; - CK_RV rv = CKR_OK; - char full_name[FULL_NAME_LEN]; - cryptodebug("inside pk_setpin"); + rv = configure_nss(handle, dir, prefix); + if (rv != KMF_OK) + return (rv); - /* Parse command line options. Do NOT i18n/l10n. */ - while ((opt = getopt_av(argc, argv, "T:(token)")) != EOF) { - switch (opt) { - case 'T': /* token specifier */ - if (token_spec) - return (PK_ERR_USAGE); - token_spec = optarg_av; - break; - default: - return (PK_ERR_USAGE); - break; - } + (void) memset(¶ms, 0, sizeof (params)); + params.kstype = KMF_KEYSTORE_NSS; + params.tokenname = token_spec; + params.nssparms.slotlabel = token_spec; + + if ((rv = get_pin(gettext("Enter current token passphrase " + "(<CR> if not set):"), NULL, &old_pin, &old_pinlen)) != + CKR_OK) { + cryptoerror(LOG_STDERR, + gettext("Unable to get token passphrase.")); + return (PK_ERR_NSS); } + /* Get the user's new PIN. */ + if ((rv = get_pin(gettext("Create new passphrase:"), gettext( + "Re-enter new passphrase:"), &new_pin, &new_pinlen)) != CKR_OK) { + if (rv == CKR_PIN_INCORRECT) + cryptoerror(LOG_STDERR, gettext( + "Passphrases do not match.")); + else + cryptoerror(LOG_STDERR, gettext( + "Unable to get and confirm new passphrase.")); + if (old_pin != NULL) + free(old_pin); + return (PK_ERR_NSS); + } + + params.cred.cred = (char *)old_pin; + params.cred.credlen = old_pinlen; + + newpincred.cred = (char *)new_pin; + newpincred.credlen = new_pinlen; + + rv = KMF_SetTokenPin(handle, ¶ms, &newpincred); + + if (new_pin) + free(new_pin); + if (old_pin) + free(old_pin); + + return (rv); +} + +static int +setpin_pkcs11(KMF_HANDLE_T handle, char *token_spec) +{ + CK_SLOT_ID slot_id; + CK_FLAGS pin_state; + CK_UTF8CHAR_PTR old_pin = NULL, new_pin = NULL; + CK_ULONG old_pinlen = 0, new_pinlen = 0; + CK_RV rv = CKR_OK; + char *token_name = NULL; + KMF_SETPIN_PARAMS params; + CK_TOKEN_INFO token_info; + KMF_CREDENTIAL newpincred = { NULL, 0 }; /* If nothing is specified, default is to use softtoken. */ if (token_spec == NULL) { + token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID; token_name = SOFT_TOKEN_LABEL; - manuf_id = SOFT_MANUFACTURER_ID; - serial_no = SOFT_TOKEN_SERIAL; - } else { - /* - * Parse token specifier into token_name, manuf_id, serial_no. - * Token_name is required; manuf_id and serial_no are optional. - */ - if (parse_token_spec(token_spec, &token_name, &manuf_id, - &serial_no) < 0) - return (PK_ERR_USAGE); } - /* No additional args allowed. */ - argc -= optind_av; - argv += optind_av; - if (argc != 0) - return (PK_ERR_USAGE); - /* Done parsing command line options. */ - - full_token_name(token_name, manuf_id, serial_no, full_name); + rv = KMF_PK11TokenLookup(NULL, token_spec, &slot_id); + if (rv == KMF_OK) { + /* find the pin state for the selected token */ + if (C_GetTokenInfo(slot_id, &token_info) != CKR_OK) + return (PK_ERR_PK11); - /* Find the slot with token. */ - if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id, - &pin_state)) != CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to find token %s (%s)."), full_name, - pkcs11_strerror(rv)); - final_pk11(NULL); - return (PK_ERR_PK11); + pin_state = token_info.flags & CKF_USER_PIN_TO_BE_CHANGED; + if (token_name == NULL) + token_name = (char *)token_info.label; } /* @@ -121,7 +134,6 @@ pk_setpin(int argc, char *argv[]) */ if (pin_state == CKF_USER_PIN_TO_BE_CHANGED && strcmp(token_name, SOFT_TOKEN_LABEL) == 0) { - cryptodebug("pin_state: first time passphrase is being set"); if ((old_pin = (CK_UTF8CHAR_PTR) strdup(SOFT_DEFAULT_PIN)) == NULL) { cryptoerror(LOG_STDERR, "%s.", strerror(errno)); @@ -130,7 +142,6 @@ pk_setpin(int argc, char *argv[]) } old_pinlen = strlen(SOFT_DEFAULT_PIN); } else { - cryptodebug("pin_state: changing an existing pin "); if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &old_pin, &old_pinlen)) != CKR_OK) { cryptoerror(LOG_STDERR, @@ -156,36 +167,117 @@ pk_setpin(int argc, char *argv[]) return (PK_ERR_PK11); } - /* Open a R/W session to the token to change the PIN. */ - if ((rv = open_sess(slot_id, CKF_RW_SESSION, &sess)) != CKR_OK) { - cryptoerror(LOG_STDERR, - gettext("Unable to open token session (%s)."), - pkcs11_strerror(rv)); + (void) memset(¶ms, 0, sizeof (params)); + params.kstype = KMF_KEYSTORE_PK11TOKEN; + params.tokenname = (char *)token_info.label; + params.cred.cred = (char *)old_pin; + params.cred.credlen = old_pinlen; + params.pkcs11parms.slot = slot_id; + + newpincred.cred = (char *)new_pin; + newpincred.credlen = new_pinlen; + + rv = KMF_SetTokenPin(handle, ¶ms, &newpincred); + + /* Clean up. */ + if (old_pin != NULL) free(old_pin); - final_pk11(NULL); - return (PK_ERR_PK11); + if (new_pin != NULL) + free(new_pin); + + return (rv); +} + +/* + * Changes the token's PIN. + */ +int +pk_setpin(int argc, char *argv[]) +/* ARGSUSED */ +{ + int opt; + int rv; + extern int optind_av; + extern char *optarg_av; + char *token_spec = NULL; + char *dir = NULL; + char *prefix = NULL; + KMF_HANDLE_T handle; + KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; + + /* Parse command line options. Do NOT i18n/l10n. */ + while ((opt = getopt_av(argc, argv, + "T:(token)k:(keystore)d:(dir)" + "p:(prefix)")) != EOF) { + switch (opt) { + case 'k': + kstype = KS2Int(optarg_av); + if (kstype == 0) + return (PK_ERR_USAGE); + break; + case 'T': /* token specifier */ + if (token_spec) + return (PK_ERR_USAGE); + token_spec = optarg_av; + break; + case 'd': + if (dir) + return (PK_ERR_USAGE); + dir = optarg_av; + break; + case 'p': + if (prefix) + return (PK_ERR_USAGE); + prefix = optarg_av; + break; + default: + return (PK_ERR_USAGE); + break; + } } - /* Change the PIN if possible. */ - cryptodebug("calling C_SetPIN"); - rv = C_SetPIN(sess, old_pin, old_pinlen, new_pin, new_pinlen); - /* Clean up. */ - free(old_pin); - free(new_pin); - quick_finish(sess); + /* No additional args allowed. */ + argc -= optind_av; + argv += optind_av; + if (argc != 0) + return (PK_ERR_USAGE); - if (rv != CKR_OK) { - if (rv == CKR_PIN_INCORRECT) - cryptoerror(LOG_STDERR, - gettext("Incorrect passphrase.")); - else + /* Done parsing command line options. */ + if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) { + token_spec = PK_DEFAULT_PK11TOKEN; + } else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) { + token_spec = DEFAULT_NSS_TOKEN; + } + + if ((rv = KMF_Initialize(&handle, NULL, NULL)) != KMF_OK) + return (rv); + + switch (kstype) { + case KMF_KEYSTORE_PK11TOKEN: + rv = setpin_pkcs11(handle, token_spec); + break; + case KMF_KEYSTORE_NSS: + rv = setpin_nss(handle, token_spec, dir, prefix); + break; + default: cryptoerror(LOG_STDERR, - gettext("Unable to change passphrase (%s)."), - pkcs11_strerror(rv)); - return (PK_ERR_PK11); + gettext("incorrect keystore.")); + return (PK_ERR_USAGE); } - (void) fprintf(stdout, gettext("Passphrase changed.\n")); + (void) KMF_Finalize(handle); + + if (rv == KMF_ERR_AUTH_FAILED) { + cryptoerror(LOG_STDERR, + gettext("Incorrect passphrase.")); + return (PK_ERR_SYSTEM); + } else if (rv != CKR_OK) { + cryptoerror(LOG_STDERR, + gettext("Unable to change passphrase.")); + return (PK_ERR_SYSTEM); + } else { + (void) fprintf(stdout, gettext("Passphrase changed.\n")); + } return (0); } diff --git a/usr/src/cmd/cmd-crypto/pktool/tokens.c b/usr/src/cmd/cmd-crypto/pktool/tokens.c index e6345c77b8..ea9d556caa 100644 --- a/usr/src/cmd/cmd-crypto/pktool/tokens.c +++ b/usr/src/cmd/cmd-crypto/pktool/tokens.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,7 +50,6 @@ pk_tokens(int argc, char *argv[]) CK_RV rv = CKR_OK; int i; - cryptodebug("inside pk_tokens"); /* Get rid of subcommand word "tokens". */ argc--; @@ -81,13 +79,10 @@ pk_tokens(int argc, char *argv[]) (void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"), gettext("Serial No"), gettext("PIN State")); for (i = 0; i < slot_count; i++) { - cryptodebug("calling C_GetTokenInfo"); if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get slot %d token info (%s)."), i, pkcs11_strerror(rv)); - cryptodebug("token info error, slot %d (%s)", i, - pkcs11_strerror(rv)); continue; } @@ -99,6 +94,6 @@ pk_tokens(int argc, char *argv[]) /* Clean up. */ free(slots); - quick_finish(NULL); + (void) C_Finalize(NULL); return (0); } diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index b08aa23cd9..1515a356cb 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -108,6 +108,7 @@ SUBDIRS += \ libinetcfg \ libinetutil \ libipmp \ + libkmf \ libkstat \ libkvm \ liblaadm \ @@ -466,6 +467,7 @@ libfstyp: libnvpair $(CLOSED_BUILD)$(CLOSED)/lib/libelfsign: \ $(CLOSED)/lib/libike libcryptoutil pkcs11 libinetcfg: libnsl libsocket libdevinfo +libkmf: libcryptoutil pkcs11 openssl libnsl: libmd5 libscf libmapid: libresolv libmacadm: libdevinfo diff --git a/usr/src/lib/libcryptoutil/Makefile.com b/usr/src/lib/libcryptoutil/Makefile.com index 2beda723bb..cffe48fc23 100644 --- a/usr/src/lib/libcryptoutil/Makefile.com +++ b/usr/src/lib/libcryptoutil/Makefile.com @@ -34,7 +34,8 @@ OBJECTS= \ config_parsing.o \ tohexstr.o \ mechkeytype.o\ - pkcserror.o + pkcserror.o \ + util.o include $(SRC)/lib/Makefile.lib diff --git a/usr/src/lib/libcryptoutil/common/config_parsing.c b/usr/src/lib/libcryptoutil/common/config_parsing.c index 1c01db6de5..92eccf35dd 100644 --- a/usr/src/lib/libcryptoutil/common/config_parsing.c +++ b/usr/src/lib/libcryptoutil/common/config_parsing.c @@ -211,7 +211,7 @@ parse_policylist(char *buf, uentry_t *pent) if (value = strpbrk(buf, SEP_EQUAL)) { value++; /* get rid of = */ (void) strlcpy((char *)pent->metaslot_ks_token, value, - TOKEN_LABEL_SIZE); + sizeof (pent->metaslot_ks_token)); return (SUCCESS); } else { cryptoerror(LOG_ERR, "failed to parse %s.\n", @@ -223,7 +223,7 @@ parse_policylist(char *buf, uentry_t *pent) if (value = strpbrk(buf, SEP_EQUAL)) { value++; /* get rid of = */ (void) strlcpy((char *)pent->metaslot_ks_slot, value, - SLOT_DESCRIPTION_SIZE); + sizeof (pent->metaslot_ks_slot)); return (SUCCESS); } else { cryptoerror(LOG_ERR, "failed to parse %s.\n", @@ -376,3 +376,174 @@ free_uentrylist(uentrylist_t *entrylist) entrylist = pnext; } } + + + +/* + * Duplicate an UEF mechanism list. A NULL pointer is returned if out of + * memory or the input argument is NULL. + */ +static umechlist_t * +dup_umechlist(umechlist_t *plist) +{ + umechlist_t *pres = NULL; + umechlist_t *pcur; + umechlist_t *ptmp; + int rc = SUCCESS; + + while (plist != NULL) { + if (!(ptmp = create_umech(plist->name))) { + rc = FAILURE; + break; + } + + if (pres == NULL) { + pres = pcur = ptmp; + } else { + pcur->next = ptmp; + pcur = pcur->next; + } + plist = plist->next; + } + + if (rc != SUCCESS) { + free_umechlist(pres); + return (NULL); + } + + return (pres); +} + + +/* + * Duplicate an uentry. A NULL pointer is returned if out of memory + * or the input argument is NULL. + */ +static uentry_t * +dup_uentry(uentry_t *puent1) +{ + uentry_t *puent2 = NULL; + + if (puent1 == NULL) { + return (NULL); + } + + if ((puent2 = malloc(sizeof (uentry_t))) == NULL) { + cryptoerror(LOG_STDERR, gettext("out of memory.")); + return (NULL); + } else { + (void) strlcpy(puent2->name, puent1->name, + sizeof (puent2->name)); + puent2->flag_norandom = puent1->flag_norandom; + puent2->flag_enabledlist = puent1->flag_enabledlist; + puent2->policylist = dup_umechlist(puent1->policylist); + puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled; + puent2->flag_metaslot_auto_key_migrate + = puent1->flag_metaslot_auto_key_migrate; + (void) memcpy(puent2->metaslot_ks_slot, + puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); + (void) memcpy(puent2->metaslot_ks_token, + puent1->metaslot_ks_token, TOKEN_LABEL_SIZE); + puent2->count = puent1->count; + return (puent2); + } +} + +/* + * Find the entry in the "pkcs11.conf" file with "libname" as the provider + * name. Return the entry if found, otherwise return NULL. + */ +uentry_t * +getent_uef(char *libname) +{ + uentrylist_t *pliblist = NULL; + uentrylist_t *plib = NULL; + uentry_t *puent = NULL; + boolean_t found = B_FALSE; + + if (libname == NULL) { + return (NULL); + } + + if ((get_pkcs11conf_info(&pliblist)) == FAILURE) { + return (NULL); + } + + plib = pliblist; + while (plib) { + if (strcmp(plib->puent->name, libname) == 0) { + found = B_TRUE; + break; + } else { + plib = plib->next; + } + } + + if (found) { + puent = dup_uentry(plib->puent); + } + + free_uentrylist(pliblist); + return (puent); +} + + + +/* + * Retrieve the metaslot information from the pkcs11.conf file. + * This function returns SUCCESS if successfully done; otherwise it returns + * FAILURE. If successful, the caller is responsible to free the space + * allocated for objectstore_slot_info and objectstore_token_info. + */ +int +get_metaslot_info(boolean_t *status_enabled, boolean_t *migrate_enabled, + char **objectstore_slot_info, char **objectstore_token_info) +{ + + int rc = SUCCESS; + uentry_t *puent; + char *buf1 = NULL; + char *buf2 = NULL; + + if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { + /* metaslot entry doesn't exist */ + return (FAILURE); + } + + *status_enabled = puent->flag_metaslot_enabled; + *migrate_enabled = puent->flag_metaslot_auto_key_migrate; + + buf1 = malloc(SLOT_DESCRIPTION_SIZE); + if (buf1 == NULL) { + cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n"); + rc = FAILURE; + goto out; + } + (void) strcpy(buf1, (const char *) puent->metaslot_ks_slot); + *objectstore_slot_info = buf1; + + buf2 = malloc(TOKEN_LABEL_SIZE); + if (objectstore_slot_info == NULL) { + cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n"); + rc = FAILURE; + goto out; + } + (void) strcpy(buf2, (const char *) puent->metaslot_ks_token); + *objectstore_token_info = buf2; + +out: + if (puent != NULL) { + free_uentry(puent); + } + + if (rc == FAILURE) { + if (buf1 != NULL) { + free(buf1); + } + if (buf2 != NULL) { + free(buf2); + } + } + + return (rc); +} diff --git a/usr/src/lib/libcryptoutil/common/cryptoutil.h b/usr/src/lib/libcryptoutil/common/cryptoutil.h index 18a82bcdc0..c322ea76af 100644 --- a/usr/src/lib/libcryptoutil/common/cryptoutil.h +++ b/usr/src/lib/libcryptoutil/common/cryptoutil.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -121,12 +120,20 @@ extern umechlist_t *create_umech(char *); extern void free_umechlist(umechlist_t *); extern void free_uentrylist(uentrylist_t *); extern void free_uentry(uentry_t *); +extern uentry_t *getent_uef(char *); extern void tohexstr(uchar_t *bytes, size_t blen, char *hexstr, size_t hexlen); extern CK_RV pkcs11_mech2keytype(CK_MECHANISM_TYPE mech_type, CK_KEY_TYPE *ktype); extern char *pkcs11_strerror(CK_RV rv); +extern int +get_metaslot_info(boolean_t *status_enabled, boolean_t *migrate_enabled, + char **objectstore_slot_info, char **objectstore_token_info); + +extern char *get_fullpath(char *dir, char *filepath); +extern int str2lifetime(char *ltimestr, uint32_t *ltime); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libcryptoutil/common/mapfile-vers b/usr/src/lib/libcryptoutil/common/mapfile-vers index 92e53197af..9ff8c3eec6 100644 --- a/usr/src/lib/libcryptoutil/common/mapfile-vers +++ b/usr/src/lib/libcryptoutil/common/mapfile-vers @@ -34,11 +34,15 @@ SUNWprivate_1.1 { free_uentry; free_uentrylist; free_umechlist; + getent_uef; + get_fullpath; + get_metaslot_info; get_pkcs11conf_info; pkcs11_mech2keytype; pkcs11_mech2str; pkcs11_str2mech; pkcs11_strerror; + str2lifetime; tohexstr; local: *; diff --git a/usr/src/lib/libcryptoutil/common/util.c b/usr/src/lib/libcryptoutil/common/util.c new file mode 100644 index 0000000000..6fbf175d77 --- /dev/null +++ b/usr/src/lib/libcryptoutil/common/util.c @@ -0,0 +1,116 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <cryptoutil.h> +#include <strings.h> +#include <stdio.h> +#include <tzfile.h> + +/* + * This function returns a fullpath based on the "dir" and "filepath" input + * arugments. + * - If the filepath specified does not start with a "/" and the directory + * is also given, prepend the directory to the filename. + * - If only dir or filepath is given, this function returns a copy of the + * given argument. + * - If the filepath is fully qualified already and the "dir" is also + * given, return NULL to indicate an error. + */ +char * +get_fullpath(char *dir, char *filepath) +{ + char *fullpath = NULL; + int pathlen = 0; + int dirlen = 0; + + if (filepath != NULL) + pathlen = strlen(filepath); + + if (dir != NULL) + dirlen = strlen(dir); + + if (pathlen > 0 && dirlen > 0) { + if (filepath[0] != '/') { + int len = pathlen + dirlen + 2; + fullpath = (char *)malloc(len); + if (fullpath != NULL) + (void) snprintf(fullpath, len, "%s/%s", + dir, filepath); + } else { + return (NULL); + } + } else if (pathlen > 0) { + fullpath = (char *)strdup(filepath); + } else if (dirlen > 0) { + fullpath = (char *)strdup(dir); + } + + return (fullpath); +} + +/* + * This function converts the input string to the value of time + * in seconds. + * - If the input string is NULL, return zero second. + * - The input string needs to be in the form of: + * number-second(s), number-minute(s), number-hour(s) or + * number-day(s). + */ +int +str2lifetime(char *ltimestr, uint32_t *ltime) +{ + int num; + char timetok[10]; + + if (ltimestr == NULL || !strlen(ltimestr)) { + *ltime = 0; + return (0); + } + + (void) memset(timetok, 0, sizeof (timetok)); + if (sscanf(ltimestr, "%d-%08s", &num, timetok) != 2) + return (-1); + + if (!strcasecmp(timetok, "second") || + !strcasecmp(timetok, "seconds")) { + *ltime = num; + } else if (!strcasecmp(timetok, "minute") || + !strcasecmp(timetok, "minutes")) { + *ltime = num * SECSPERMIN; + } else if (!strcasecmp(timetok, "day") || + !strcasecmp(timetok, "days")) { + *ltime = num * SECSPERDAY; + } else if (!strcasecmp(timetok, "hour") || + !strcasecmp(timetok, "hours")) { + *ltime = num * SECSPERHOUR; + } else { + *ltime = 0; + return (-1); + } + + return (0); +} diff --git a/usr/src/lib/libkmf/Makefile b/usr/src/lib/libkmf/Makefile new file mode 100644 index 0000000000..d300caefb5 --- /dev/null +++ b/usr/src/lib/libkmf/Makefile @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# KMF Prototype Makefile +# +include ../Makefile.lib + +LIBRARY= libkmf.a +VERS= 1 + +SUBDIRS = ber_der libkmf plugins + +HDRS= kmfapi.h kmftypes.h +HDRDIR= include + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +install_h := TARGET= install_h + +all clean clobber install lint: $(SUBDIRS) + +install_h: $(ROOTHDRDIR) $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): install_h FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/ber_der/Makefile b/usr/src/lib/libkmf/ber_der/Makefile new file mode 100644 index 0000000000..d81be42e84 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/Makefile @@ -0,0 +1,49 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/ber_der/Makefile.com b/usr/src/lib/libkmf/ber_der/Makefile.com new file mode 100644 index 0000000000..9c8c5657de --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/Makefile.com @@ -0,0 +1,57 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY= libkmfberder.a +VERS= .1 + +OBJECTS=\ + encode.o \ + decode.o \ + io.o \ + clasn1.o + +include $(SRC)/lib/Makefile.lib + +SRCDIR= ../common +INCDIR= ../inc + +LIBS= $(DYNLIB) $(LINTLIB) + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +CFLAGS += $(CCVERBOSE) -xCC +CFLAGS64 += $(CCVERBOSE) -xCC +CPPFLAGS += -I/usr/include/libxml2 -I$(INCDIR) -I../../include +CPPFLAGS64 += -I/usr/include/libxml2 -I$(INCDIR) -I../../include +LDLIBS += -lc + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/ber_der/amd64/Makefile b/usr/src/lib/libkmf/ber_der/amd64/Makefile new file mode 100644 index 0000000000..6093af918f --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/amd64/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libkmf/ber_der/common/clasn1.c b/usr/src/lib/libkmf/ber_der/common/clasn1.c new file mode 100644 index 0000000000..3aa1c7b68d --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/common/clasn1.c @@ -0,0 +1,2452 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * + * File: CLASN1.C + * + * Copyright (c) 1995-1999 Intel Corporation. All rights reserved. + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <strings.h> +#include <kmftypes.h> +#include <ber_der.h> +#include <kmfapi.h> +#include <kmfapiP.h> + +#include <stdio.h> + +#define DSA_RAW_SIG_LEN 40 + +static uint8_t OID_ExtensionRequest[] = { OID_PKCS_9, 14 }; +const KMF_OID extension_request_oid = {OID_PKCS_9_LENGTH + 1, + OID_ExtensionRequest}; + +static KMF_RETURN +encode_algoid(BerElement *asn1, KMF_X509_ALGORITHM_IDENTIFIER *algoid) +{ + KMF_RETURN ret = KMF_OK; + + if (kmfber_printf(asn1, "{D", &algoid->algorithm) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + } + if (algoid->parameters.Data == NULL || + algoid->parameters.Length == 0) { + if (kmfber_printf(asn1, "n}") == -1) + return (KMF_ERR_BAD_CERT_FORMAT); + } else { + /* + * The algorithm data can be anything, so we just write it + * straight into the buffer. It is already DER encoded. + */ + (void) kmfber_write(asn1, (char *)algoid->parameters.Data, + algoid->parameters.Length, 0); + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + } + } + + return (ret); +} + +static void +free_data(KMF_DATA *data) +{ + if (data == NULL || data->Data == NULL) + return; + + free(data->Data); + data->Data = NULL; + data->Length = 0; +} + +static void +free_algoid(KMF_X509_ALGORITHM_IDENTIFIER *algoid) +{ + free_data(&algoid->algorithm); + free_data(&algoid->parameters); +} + +static void +free_decoded_spki(KMF_X509_SPKI *spki) +{ + if (spki != NULL) { + free_algoid(&spki->algorithm); + free_data(&spki->subjectPublicKey); + } +} + +static void +free_rdn_data(KMF_X509_NAME *name) +{ + KMF_X509_RDN *newrdn = NULL; + KMF_X509_TYPE_VALUE_PAIR *av = NULL; + int i, j; + + if (name && name->numberOfRDNs) { + for (i = 0; i < name->numberOfRDNs; i++) { + newrdn = &name->RelativeDistinguishedName[i]; + for (j = 0; j < newrdn->numberOfPairs; j++) { + av = &newrdn->AttributeTypeAndValue[j]; + free_data(&av->type); + free_data(&av->value); + } + free(newrdn->AttributeTypeAndValue); + } + free(name->RelativeDistinguishedName); + name->numberOfRDNs = 0; + name->RelativeDistinguishedName = NULL; + } +} + +static void +free_validity(KMF_X509_VALIDITY *validity) +{ + free_data(&validity->notBefore.time); + free_data(&validity->notAfter.time); +} + +static void +free_one_extension(KMF_X509_EXTENSION *exptr) +{ + free_data(&exptr->extnId); + free_data(&exptr->BERvalue); + + if (exptr->value.tagAndValue) { + free_data(&exptr->value.tagAndValue->value); + free(exptr->value.tagAndValue); + } +} + +static void +free_extensions(KMF_X509_EXTENSIONS *extns) +{ + int i; + KMF_X509_EXTENSION *exptr; + + if (extns && extns->numberOfExtensions > 0) { + for (i = 0; i < extns->numberOfExtensions; i++) { + exptr = &extns->extensions[i]; + free_one_extension(exptr); + } + free(extns->extensions); + extns->numberOfExtensions = 0; + extns->extensions = NULL; + } +} + +static void +free_tbscsr(KMF_TBS_CSR *tbscsr) +{ + if (tbscsr) { + free_data(&tbscsr->version); + + free_rdn_data(&tbscsr->subject); + + free_decoded_spki(&tbscsr->subjectPublicKeyInfo); + + free_extensions(&tbscsr->extensions); + } +} + + +static void +free_bigint(KMF_BIGINT *bn) +{ + if (bn != NULL && bn->val != NULL) { + free(bn->val); + bn->val = NULL; + bn->len = 0; + } +} + +static void +free_tbscert(KMF_X509_TBS_CERT *tbscert) +{ + if (tbscert) { + free_data(&tbscert->version); + free_bigint(&tbscert->serialNumber); + free_algoid(&tbscert->signature); + + free_rdn_data(&tbscert->issuer); + free_rdn_data(&tbscert->subject); + + free_validity(&tbscert->validity); + + free_data(&tbscert->issuerUniqueIdentifier); + free_data(&tbscert->subjectUniqueIdentifier); + free_decoded_spki(&tbscert->subjectPublicKeyInfo); + free_extensions(&tbscert->extensions); + + free_data(&tbscert->issuerUniqueIdentifier); + free_data(&tbscert->subjectUniqueIdentifier); + } +} + +static void +free_decoded_cert(KMF_X509_CERTIFICATE *certptr) +{ + if (!certptr) + return; + + free_tbscert(&certptr->certificate); + + free_algoid(&certptr->signature.algorithmIdentifier); + free_data(&certptr->signature.encrypted); +} + +static KMF_RETURN +get_algoid(BerElement *asn1, KMF_X509_ALGORITHM_IDENTIFIER *algoid) +{ + KMF_RETURN ret = KMF_OK; + ber_tag_t tag, newtag; + ber_len_t size; + BerValue AlgOID = {NULL, 0}; + + tag = kmfber_next_element(asn1, &size, NULL); + if (tag != BER_CONSTRUCTED_SEQUENCE) + return (KMF_ERR_BAD_CERT_FORMAT); + + if ((tag = kmfber_scanf(asn1, "{Dt", &AlgOID, &newtag)) == -1) { + return (KMF_ERR_BAD_CERT_FORMAT); + } + algoid->algorithm.Data = (uchar_t *)AlgOID.bv_val; + algoid->algorithm.Length = AlgOID.bv_len; + + if (newtag == BER_NULL) { + (void) kmfber_scanf(asn1, "n}"); + algoid->parameters.Data = NULL; + algoid->parameters.Length = 0; + } else { + /* Peek at the tag and length bytes */ + if ((kmfber_scanf(asn1, "tl", &tag, &size)) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* + * We need to read the tag and the length bytes too, + * so adjust the size. + */ + size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size); + algoid->parameters.Data = malloc(size); + if (algoid->parameters.Data == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + /* read the raw data into the Algoritm params area. */ + if (kmfber_read(asn1, (char *)algoid->parameters.Data, + size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + algoid->parameters.Length = size; + if ((tag = kmfber_scanf(asn1, "}")) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + } + } +cleanup: + if (ret != KMF_OK) { + free_algoid(algoid); + } + + return (ret); +} + +static KMF_RETURN +CopyData(KMF_DATA *src, KMF_DATA *dst) +{ + if (src && dst && src->Data != NULL && src->Length > 0) { + dst->Length = src->Length; + dst->Data = malloc(sizeof (dst->Length)); + if (dst->Data == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(dst->Data, src->Data, src->Length); + } + return (KMF_OK); +} + +static KMF_RETURN +encode_spki(BerElement *asn1, KMF_X509_SPKI *spki) +{ + KMF_RETURN ret = KMF_OK; + + if (kmfber_printf(asn1, "{") == -1) + return (KMF_ERR_BAD_CERT_FORMAT); + + if ((ret = encode_algoid(asn1, &spki->algorithm)) != KMF_OK) + return (ret); + + if (kmfber_printf(asn1, "B}", spki->subjectPublicKey.Data, + spki->subjectPublicKey.Length * 8) == -1) + return (KMF_ERR_BAD_CERT_FORMAT); + + return (ret); +} + +KMF_RETURN +DerEncodeSPKI(KMF_X509_SPKI *spki, KMF_DATA *EncodedSPKI) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1; + BerValue *result; + + if (spki == NULL || EncodedSPKI == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if ((asn1 = kmfder_alloc()) == NULL) + return (KMF_ERR_MEMORY); + + if ((ret = encode_spki(asn1, spki)) != KMF_OK) { + return (ret); + } + + if (kmfber_flatten(asn1, &result) == -1) { + kmfber_free(asn1, 1); + return (KMF_ERR_ENCODING); + } + + EncodedSPKI->Data = (uchar_t *)result->bv_val; + EncodedSPKI->Length = result->bv_len; + + free(result); + kmfber_free(asn1, 1); + return (KMF_OK); +} + +static KMF_RETURN +get_spki(BerElement *asn1, KMF_X509_SPKI *spki) +{ + KMF_RETURN ret = KMF_OK; + char *bitstr = NULL; + ber_len_t size; + + if (kmfber_scanf(asn1, "{") == -1) + return (KMF_ERR_BAD_CERT_FORMAT); + + if ((ret = get_algoid(asn1, &spki->algorithm)) != KMF_OK) + return (ret); + + if (kmfber_scanf(asn1, "B}", &bitstr, &size) == BER_BIT_STRING) { + spki->subjectPublicKey.Data = (uchar_t *)bitstr; + spki->subjectPublicKey.Length = size / 8; + } else { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } +cleanup: + if (ret != KMF_OK) { + if (bitstr != NULL) + free(bitstr); + spki->subjectPublicKey.Data = NULL; + spki->subjectPublicKey.Length = 0; + + free_algoid(&spki->algorithm); + } + return (ret); +} + +KMF_RETURN +DerEncodeDSASignature(KMF_DATA *rawdata, KMF_DATA *signature) +{ + BerElement *asn1; + BerValue *buf; + int n; + + if (rawdata == NULL || signature == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (rawdata->Data == NULL || rawdata->Length != DSA_RAW_SIG_LEN) + return (KMF_ERR_BAD_PARAMETER); + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + /* + * The DSA signature is the concatenation of 2 SHA-1 hashed + * bignum values. + */ + n = DSA_RAW_SIG_LEN/2; + if (kmfber_printf(asn1, "{II}", + rawdata->Data, n, + &rawdata->Data[n], n) == -1) { + kmfber_free(asn1, 1); + return (KMF_ERR_MEMORY); + } + + if (kmfber_flatten(asn1, &buf) == -1) { + kmfber_free(asn1, 1); + return (KMF_ERR_ENCODING); + } + + signature->Data = (uchar_t *)buf->bv_val; + signature->Length = buf->bv_len; + + kmfber_free(asn1, 1); + free(buf); + + return (KMF_OK); +} + +KMF_RETURN +DerDecodeDSASignature(KMF_DATA *encoded, KMF_DATA *signature) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue buf, *R = NULL, *S = NULL; + + buf.bv_val = (char *)encoded->Data; + buf.bv_len = encoded->Length; + + if (encoded == NULL || encoded->Data == NULL || + signature == NULL) + return (KMF_ERR_BAD_PARAMETER); + + signature->Data = NULL; + signature->Length = 0; + + if ((asn1 = kmfder_init(&buf)) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_scanf(asn1, "{II}", &R, &S) == -1) { + ret = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + signature->Length = R->bv_len + S->bv_len; + signature->Data = malloc(signature->Length); + if (signature->Data == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memcpy(signature->Data, R->bv_val, R->bv_len); + (void) memcpy(&signature->Data[R->bv_len], S->bv_val, S->bv_len); + +cleanup: + if (R && R->bv_val) + free(R->bv_val); + if (S && S->bv_val) + free(S->bv_val); + + if (S) free(S); + if (R) free(R); + + if (asn1) kmfber_free(asn1, 1); + + return (ret); +} + +KMF_RETURN +DerDecodeSPKI(KMF_DATA *EncodedSPKI, KMF_X509_SPKI *spki) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1; + BerValue bv; + + if (EncodedSPKI == NULL || EncodedSPKI->Data == NULL || + spki == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(spki, 0, sizeof (KMF_X509_SPKI)); + + bv.bv_val = (char *)EncodedSPKI->Data; + bv.bv_len = EncodedSPKI->Length; + + if ((asn1 = kmfder_init(&bv)) == NULL) + return (KMF_ERR_MEMORY); + + ret = get_spki(asn1, spki); + +cleanup: + if (ret != KMF_OK) { + free_decoded_spki(spki); + } + kmfber_free(asn1, 1); + + return (ret); +} + +KMF_RETURN +CopySPKI(KMF_X509_SPKI *src, + KMF_X509_SPKI **dest) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_SPKI *newspki; + + *dest = NULL; + + newspki = malloc(sizeof (KMF_X509_SPKI)); + if (newspki == NULL) + return (KMF_ERR_MEMORY); + (void) memset(newspki, 0, sizeof (KMF_X509_SPKI)); + + ret = CopyData(&src->algorithm.algorithm, + &newspki->algorithm.algorithm); + if (ret != KMF_OK) + goto cleanup; + + ret = CopyData(&src->algorithm.parameters, + &newspki->algorithm.parameters); + if (ret != KMF_OK) + goto cleanup; + + ret = CopyData(&src->subjectPublicKey, + &newspki->subjectPublicKey); + if (ret != KMF_OK) + goto cleanup; + + *dest = newspki; +cleanup: + if (ret != KMF_OK) { + if (newspki) + free_decoded_spki(newspki); + } + return (ret); +} + +static KMF_RETURN +encode_validity(BerElement *asn1, KMF_X509_VALIDITY *validity) +{ + int ret; + + ret = kmfber_printf(asn1, "{tsts}", + validity->notBefore.timeType, + validity->notBefore.time.Data, + validity->notAfter.timeType, + validity->notAfter.time.Data); + + if (ret == -1) + return (KMF_ERR_BAD_CERT_FORMAT); + + return (KMF_OK); +} + +static KMF_RETURN +get_validity(BerElement *asn1, KMF_X509_VALIDITY *validity) +{ + KMF_RETURN ret = KMF_OK; + int tag; + int t1, t2; + ber_len_t size; + char *t1str, *t2str; + + (void) memset(validity, 0, sizeof (KMF_X509_VALIDITY)); + + tag = kmfber_next_element(asn1, &size, NULL); + if (tag != BER_CONSTRUCTED_SEQUENCE) { + return (KMF_ERR_BAD_CERT_FORMAT); + } + + if (kmfber_scanf(asn1, "{tata}", &t1, &t1str, &t2, &t2str) == -1) { + return (KMF_ERR_BAD_CERT_FORMAT); + } + + validity->notBefore.timeType = t1; + validity->notBefore.time.Data = (uchar_t *)t1str; + validity->notBefore.time.Length = strlen(t1str); + + validity->notAfter.timeType = t2; + validity->notAfter.time.Data = (uchar_t *)t2str; + validity->notAfter.time.Length = strlen(t2str); + + return (ret); +} + +KMF_RETURN +AddRDN(KMF_X509_NAME *name, KMF_X509_RDN *newrdn) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_RDN *rdnslot = NULL; + + /* Add new RDN record to existing list */ + name->numberOfRDNs++; + name->RelativeDistinguishedName = + realloc(name->RelativeDistinguishedName, + name->numberOfRDNs * sizeof (KMF_X509_RDN)); + + if (name->RelativeDistinguishedName == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + rdnslot = &name->RelativeDistinguishedName[name->numberOfRDNs-1]; + + if (newrdn) { + (void) memcpy(rdnslot, newrdn, sizeof (KMF_X509_RDN)); + } else { + rdnslot->numberOfPairs = 0; + rdnslot->AttributeTypeAndValue = NULL; + } + +cleanup: + /* No cleanup needed here */ + return (ret); +} + +static KMF_RETURN +encode_rdn(BerElement *asn1, KMF_X509_NAME *name) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_TYPE_VALUE_PAIR *attrtvpair = NULL; + int i; + KMF_X509_RDN *rdn; + + if (kmfber_printf(asn1, "{") == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + for (i = 0; i < name->numberOfRDNs; i++) { + if (kmfber_printf(asn1, "[") == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + rdn = &name->RelativeDistinguishedName[i]; + attrtvpair = rdn->AttributeTypeAndValue; + + if (rdn->numberOfPairs > 0) { + if (kmfber_printf(asn1, "{Dto}", + &attrtvpair->type, + attrtvpair->valueType, + attrtvpair->value.Data, + attrtvpair->value.Length) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + } + if (kmfber_printf(asn1, "]") == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + } + + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + +cleanup: + /* No cleanup needed here */ + + return (ret); +} + + +KMF_RETURN +CopyRDN(KMF_X509_NAME *srcname, KMF_X509_NAME **destname) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_NAME *newname = NULL; + KMF_X509_RDN *rdn, *dstrdn; + KMF_X509_TYPE_VALUE_PAIR *av = NULL; + KMF_X509_TYPE_VALUE_PAIR *srcav = NULL; + KMF_X509_TYPE_VALUE_PAIR *dstav = NULL; + int i, j; + + newname = malloc(sizeof (KMF_X509_NAME)); + if (newname == NULL) + return (KMF_ERR_MEMORY); + (void) memset(newname, 0, sizeof (KMF_X509_NAME)); + + newname->numberOfRDNs = srcname->numberOfRDNs; + newname->RelativeDistinguishedName = malloc(newname->numberOfRDNs * + sizeof (KMF_X509_RDN)); + if (newname->RelativeDistinguishedName == NULL) { + free(newname); + return (KMF_ERR_MEMORY); + } + /* Copy each RDN in the list */ + for (i = 0; i < newname->numberOfRDNs; i++) { + rdn = &srcname->RelativeDistinguishedName[i]; + + dstrdn = &newname->RelativeDistinguishedName[i]; + (void) memset(dstrdn, 0, sizeof (KMF_X509_RDN)); + + dstrdn->numberOfPairs = rdn->numberOfPairs; + if (dstrdn->numberOfPairs > 0) { + av = malloc(dstrdn->numberOfPairs * + sizeof (KMF_X509_TYPE_VALUE_PAIR)); + if (av == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memset(av, 0, dstrdn->numberOfPairs * + sizeof (KMF_X509_TYPE_VALUE_PAIR)); + + dstrdn->AttributeTypeAndValue = av; + if (av == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + /* Copy each A/V pair in the list */ + for (j = 0; j < dstrdn->numberOfPairs; j++) { + srcav = &rdn->AttributeTypeAndValue[j]; + dstav = &dstrdn->AttributeTypeAndValue[j]; + if ((ret = CopyData(&srcav->type, + &dstav->type)) != KMF_OK) + goto cleanup; + dstav->valueType = srcav->valueType; + if ((ret = CopyData(&srcav->value, + &dstav->value)) != KMF_OK) + goto cleanup; + } + } else { + dstrdn->AttributeTypeAndValue = NULL; + } + } + *destname = newname; + +cleanup: + if (ret != KMF_OK) { + if (newname) + free_rdn_data(newname); + + free(newname); + *destname = NULL; + } + return (ret); +} + +#define VALID_DIRECTORYSTRING_TAG(t) ( \ + (t == BER_UTF8_STRING) || \ + (t == BER_PRINTABLE_STRING) || \ + (t == BER_IA5STRING) || \ + (t == BER_T61STRING) || \ + (t == BER_BMP_STRING) || \ + (t == BER_UNIVERSAL_STRING)) + +static KMF_RETURN +get_rdn(BerElement *asn1, KMF_X509_NAME *name) +{ + KMF_RETURN ret = KMF_OK; + ber_len_t size; + char *end; + int tag; + BerValue AttrOID; + char *AttrValue = NULL; + KMF_X509_TYPE_VALUE_PAIR *newpair = NULL; + KMF_X509_RDN newrdn; + + /* + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * DistinguishedName ::= RDNSequence + * + * RelativeDistinguishedName ::= + * SET SIZE (1 .. MAX) OF AttributeTypeAndValue + * + */ + + name->numberOfRDNs = 0; + name->RelativeDistinguishedName = NULL; + + /* Get the beginning of the RDN Set and a ptr to the end */ + tag = kmfber_first_element(asn1, &size, &end); + if (tag != BER_CONSTRUCTED_SET) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* Walk through the individual SET items until the "end" is reached */ + while ((tag = kmfber_next_element(asn1, &size, end)) == + BER_CONSTRUCTED_SET) { + /* Skip over the SET tag */ + if (kmfber_scanf(asn1, "T", &tag) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + break; + } + + /* An "empty" set member means we tack on an empty node */ + if (size == 0) { + if ((ret = AddRDN(name, NULL)) != KMF_OK) + goto cleanup; + continue; + } + + /* Attr OID and peek at the next tag and field length */ + if (kmfber_scanf(asn1, "{Dtl", &AttrOID, &tag, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + break; + } + + if (!(VALID_DIRECTORYSTRING_TAG(tag))) { + ret = KMF_ERR_BAD_CERT_FORMAT; + break; + } + + if (kmfber_scanf(asn1, "a}]", &AttrValue) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + break; + } + + /* Allocate a new name/value pair record */ + newpair = malloc(sizeof (KMF_X509_TYPE_VALUE_PAIR)); + if (newpair == NULL) { + ret = KMF_ERR_MEMORY; + break; + } + (void) memset(newpair, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR)); + newpair->type.Data = (uchar_t *)AttrOID.bv_val; + newpair->type.Length = AttrOID.bv_len; + newpair->valueType = tag; /* what kind of string is it? */ + newpair->value.Data = (uchar_t *)AttrValue; + newpair->value.Length = strlen(AttrValue); + + (void) memset(&newrdn, 0, sizeof (KMF_X509_RDN)); + newrdn.numberOfPairs = 1; + newrdn.AttributeTypeAndValue = newpair; + + if ((ret = AddRDN(name, &newrdn)) != KMF_OK) + break; + } + +cleanup: + if (ret != KMF_OK) { + free_rdn_data(name); + } + return (ret); +} + +static KMF_RETURN +set_der_integer(KMF_DATA *data, int value) +{ + if (data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + data->Data = malloc(sizeof (int)); + if (data->Data == NULL) + return (KMF_ERR_MEMORY); + + data->Length = sizeof (int); + (void) memcpy((void *)data->Data, (const void *)&value, sizeof (int)); + + return (KMF_OK); +} + +static KMF_RETURN +set_bigint(KMF_BIGINT *data, KMF_BIGINT *bigint) +{ + if (data == NULL || bigint == NULL) + return (KMF_ERR_BAD_PARAMETER); + + data->val = malloc(bigint->len); + if (data->val == NULL) + return (KMF_ERR_MEMORY); + + data->len = bigint->len; + (void) memcpy((void *)data->val, (const void *)bigint->val, + bigint->len); + + return (KMF_OK); +} + +static KMF_RETURN +encode_uniqueid(BerElement *asn1, int tag, KMF_DATA *id) +{ + KMF_RETURN ret = KMF_OK; + uint32_t len; + + len = kmfber_calc_taglen(BER_BIT_STRING) + + kmfber_calc_lenlen(id->Length * 8) + id->Length; + if (kmfber_printf(asn1, "TlB", tag, len, + id->Data, id->Length * 8) == -1) + return (KMF_ERR_BAD_CERT_FORMAT); + + return (ret); +} + +static KMF_RETURN +encode_extension_list(BerElement *asn1, KMF_X509_EXTENSIONS *extns) +{ + KMF_RETURN ret = KMF_OK; + int i; + + for (i = 0; i < extns->numberOfExtensions; i++) { + BerValue v; + v.bv_val = (char *)extns->extensions[i].extnId.Data; + v.bv_len = extns->extensions[i].extnId.Length; + + if (kmfber_printf(asn1, "{D", &v) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + + if (extns->extensions[i].critical) { + if (kmfber_printf(asn1, "b", + extns->extensions[i].critical) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + } + + if (kmfber_printf(asn1, "o}", + extns->extensions[i].BERvalue.Data, + extns->extensions[i].BERvalue.Length) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + } +cleanup: + return (ret); +} + +static KMF_RETURN +encode_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns) +{ + KMF_RETURN ret = KMF_OK; + BerElement *extn = NULL; + BerValue *extnvalue = NULL; + + extn = kmfder_alloc(); + if (extn == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(extn, "{") == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + + ret = encode_extension_list(extn, extns); + + if (kmfber_printf(extn, "}") == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + + if (kmfber_flatten(extn, &extnvalue) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + if (kmfber_printf(asn1, "Tl", 0xA3, extnvalue->bv_len) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (kmfber_write(asn1, extnvalue->bv_val, extnvalue->bv_len, 0) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + +cleanup: + kmfber_free(extn, 1); + if (extnvalue != NULL) + kmfber_bvfree(extnvalue); + + return (ret); +} + +static KMF_RETURN +get_one_extension(BerElement *asn1, KMF_X509_EXTENSION **retex, char *end) +{ + KMF_RETURN ret = KMF_OK; + ber_len_t size; + int critical, tag; + KMF_X509_EXTENSION *ex = NULL; + BerValue extOID; + BerValue extValue; + BerElement *extnber = NULL; + + if (kmfber_scanf(asn1, "T", &tag) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + tag = kmfber_next_element(asn1, &size, end); + if (tag != BER_OBJECT_IDENTIFIER) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (kmfber_scanf(asn1, "D", &extOID) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + tag = kmfber_next_element(asn1, &size, end); + if (tag != BER_BOOLEAN) { + critical = 0; + if (tag != BER_OCTET_STRING) + goto cleanup; + } else { + if (kmfber_scanf(asn1, "b", &critical) == -1) + goto cleanup; + } + + tag = kmfber_next_element(asn1, &size, end); + if (tag != BER_OCTET_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (kmfber_scanf(asn1, "o", &extValue) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* allocate a new Extension record */ + ex = malloc(sizeof (KMF_X509_EXTENSION)); + if (ex == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memset(ex, 0, sizeof (ex)); + + ex->extnId.Data = (uchar_t *)extOID.bv_val; + ex->extnId.Length = extOID.bv_len; + ex->critical = critical; + ex->format = KMF_X509_DATAFORMAT_ENCODED; + ex->BERvalue.Data = (uchar_t *)extValue.bv_val; + ex->BERvalue.Length = extValue.bv_len; + + /* Tag and value is a little tricky */ + ex->value.tagAndValue = malloc(sizeof (KMF_X509EXT_TAGandVALUE)); + if (ex->value.tagAndValue == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memset(ex->value.tagAndValue, 0, + sizeof (KMF_X509EXT_TAGandVALUE)); + + /* Parse the Extension value field */ + extnber = kmfder_init(&extValue); + if (extnber == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + /* Get the tag and length of the extension field */ + if (kmfber_scanf(extnber, "tl", &tag, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (kmfber_scanf(extnber, "T", &tag) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + ex->value.tagAndValue->value.Data = malloc(size); + ex->value.tagAndValue->value.Length = size; + size = kmfber_read(extnber, + (char *)ex->value.tagAndValue->value.Data, size); + if (size != ex->value.tagAndValue->value.Length) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + kmfber_free(extnber, 1); + ex->value.tagAndValue->type = tag; + + *retex = ex; +cleanup: + if (ret != KMF_OK) { + if (ex != NULL) + free_one_extension(ex); + } + + return (ret); +} + +static KMF_RETURN +get_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns) +{ + KMF_RETURN ret = KMF_OK; + ber_len_t size; + char *end = NULL; + KMF_X509_EXTENSION *ex = NULL; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + * + * { {{D}Bo}, ... } + */ + if (kmfber_first_element(asn1, &size, &end) != + BER_CONSTRUCTED_SEQUENCE) + return (KMF_ERR_BAD_CERT_FORMAT); + + while (kmfber_next_element(asn1, &size, end) == + BER_CONSTRUCTED_SEQUENCE) { + ret = get_one_extension(asn1, &ex, end); + if (ret != KMF_OK) + goto cleanup; + + extns->numberOfExtensions++; + extns->extensions = realloc(extns->extensions, + extns->numberOfExtensions * + sizeof (KMF_X509_EXTENSION)); + if (extns->extensions == NULL) { + ret = KMF_ERR_MEMORY; + break; + } + + extns->extensions[extns->numberOfExtensions-1] = *ex; + free(ex); + } + +cleanup: + if (ret != KMF_OK) + free_extensions(extns); + + return (ret); +} + +KMF_RETURN +decode_tbscert_data(BerElement *asn1, + KMF_X509_TBS_CERT **signed_cert_ptr_ptr) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_TBS_CERT *tbscert = NULL; + int tag, version; + struct berval *bvserno = NULL; + KMF_BIGINT serno; + + if (kmfber_scanf(asn1, "{t", &tag) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* Version number is optional */ + if (tag == 0xA0) { + if (kmfber_scanf(asn1, "Ti", &tag, &version) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + } else { + version = 0; /* DEFAULT v1 (0) */ + } + + /* Now get the serial number, it is not optional */ + if (kmfber_scanf(asn1, "I", &bvserno) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } else { + serno.val = (uchar_t *)bvserno->bv_val; + serno.len = bvserno->bv_len; + } + + tbscert = malloc(sizeof (KMF_X509_TBS_CERT)); + if (!tbscert) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + (void) memset(tbscert, 0, sizeof (KMF_X509_TBS_CERT)); + + if ((ret = set_der_integer(&tbscert->version, version)) != KMF_OK) + goto cleanup; + + if ((ret = set_bigint(&tbscert->serialNumber, &serno)) != KMF_OK) + goto cleanup; + + if ((ret = get_algoid(asn1, &tbscert->signature)) != KMF_OK) + goto cleanup; + + if ((ret = get_rdn(asn1, &tbscert->issuer)) != KMF_OK) + goto cleanup; + + if ((ret = get_validity(asn1, &tbscert->validity)) != KMF_OK) + goto cleanup; + + if ((ret = get_rdn(asn1, &tbscert->subject)) != KMF_OK) + goto cleanup; + + if ((ret = get_spki(asn1, &tbscert->subjectPublicKeyInfo)) != KMF_OK) + goto cleanup; + + /* Check for the optional fields */ + tbscert->extensions.numberOfExtensions = 0; + tbscert->extensions.extensions = NULL; + + while ((kmfber_scanf(asn1, "t", &tag)) != -1 && + (tag == 0xA1 || tag == 0xA2 || tag == 0xA3)) { + char *optfield; + ber_len_t len; + + /* consume the tag and length */ + (void) kmfber_scanf(asn1, "T", &tag); + switch (tag) { + case 0xA1: + if (kmfber_scanf(asn1, "B", &optfield, &len) != + BER_BIT_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + tbscert->issuerUniqueIdentifier.Data = + (uchar_t *)optfield; + tbscert->issuerUniqueIdentifier.Length = + len / 8; + break; + case 0xA2: + if (kmfber_scanf(asn1, "B", &optfield, &len) != + BER_BIT_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + tbscert->subjectUniqueIdentifier.Data = + (uchar_t *)optfield; + tbscert->subjectUniqueIdentifier.Length = + len / 8; + break; + case 0xA3: + ret = get_extensions(asn1, &tbscert->extensions); + break; + } + } + + *signed_cert_ptr_ptr = tbscert; + +cleanup: + if (bvserno != NULL) { + free(bvserno->bv_val); + free(bvserno); + } + if (ret != KMF_OK) { + if (tbscert) { + free_tbscert(tbscert); + free(tbscert); + } + *signed_cert_ptr_ptr = NULL; + } + return (ret); +} + +KMF_RETURN +DerDecodeTbsCertificate(const KMF_DATA *Value, + KMF_X509_TBS_CERT **tbscert) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue rawcert; + KMF_X509_TBS_CERT *newcert = NULL; + + if (!tbscert || !Value || !Value->Data || !Value->Length) + return (KMF_ERR_BAD_PARAMETER); + + rawcert.bv_val = (char *)Value->Data; + rawcert.bv_len = Value->Length; + + if ((asn1 = kmfder_init(&rawcert)) == NULL) + return (KMF_ERR_MEMORY); + + ret = decode_tbscert_data(asn1, &newcert); + if (ret != KMF_OK) + goto cleanup; + + *tbscert = newcert; + +cleanup: + if (ret != KMF_OK) { + if (newcert) + free_tbscert(newcert); + *tbscert = NULL; + } + kmfber_free(asn1, 1); + + return (ret); +} + +/* + * Name: DerDecodeSignedCertificate + * + * Description: + * DER decodes the encoded X509 certificate + * + * Parameters: + * Value (input): DER encoded object that shd be decoded + * + * signed_cert_ptr_ptr (output) : Decoded KMF_X509_CERTIFICATE object + */ +KMF_RETURN +DerDecodeSignedCertificate(const KMF_DATA *Value, + KMF_X509_CERTIFICATE **signed_cert_ptr_ptr) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue rawcert; + ber_tag_t tag; + ber_len_t size; + char *end = NULL; + char *signature; + KMF_X509_TBS_CERT *tbscert = NULL; + KMF_X509_CERTIFICATE *certptr = NULL; + + if (!signed_cert_ptr_ptr || !Value || !Value->Data || !Value->Length) + return (KMF_ERR_BAD_PARAMETER); + + rawcert.bv_val = (char *)Value->Data; + rawcert.bv_len = Value->Length; + + if ((asn1 = kmfder_init(&rawcert)) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_first_element(asn1, &size, &end) != + BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + certptr = malloc(sizeof (KMF_X509_CERTIFICATE)); + if (certptr == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memset(certptr, 0, sizeof (KMF_X509_CERTIFICATE)); + + ret = decode_tbscert_data(asn1, &tbscert); + if (ret != KMF_OK) + goto cleanup; + + certptr->certificate = *tbscert; + free(tbscert); + tbscert = NULL; + + /* + * The signature data my not be present yet. + */ + if ((ret = get_algoid(asn1, + &certptr->signature.algorithmIdentifier)) == KMF_OK) { + + /* Check to see if the cert has a signature yet */ + if (kmfber_next_element(asn1, &size, end) == BER_BIT_STRING) { + /* Finally, get the encrypted signature BITSTRING */ + if (kmfber_scanf(asn1, "tl", &tag, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (tag != BER_BIT_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (kmfber_scanf(asn1, "B}", &signature, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + certptr->signature.encrypted.Data = + (uchar_t *)signature; + certptr->signature.encrypted.Length = size / 8; + } else { + certptr->signature.encrypted.Data = NULL; + certptr->signature.encrypted.Length = 0; + } + } else { + (void) memset(&certptr->signature, 0, + sizeof (certptr->signature)); + ret = KMF_OK; + } + + *signed_cert_ptr_ptr = certptr; +cleanup: + if (ret != KMF_OK) { + if (certptr) { + free_decoded_cert(certptr); + free(certptr); + } + + *signed_cert_ptr_ptr = NULL; + } + if (asn1) + kmfber_free(asn1, 1); + + return (ret); + +} + +KMF_RETURN +DerDecodeExtension(KMF_DATA *Data, KMF_X509_EXTENSION **extn) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue bv; + + bv.bv_val = (char *)Data->Data; + bv.bv_len = Data->Length; + + asn1 = kmfder_init(&bv); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + ret = get_one_extension(asn1, extn, NULL); + +cleanup: + if (ret != KMF_OK) { + if (*extn != NULL) { + free(*extn); + } + *extn = NULL; + } + + kmfber_free(asn1, 1); + return (ret); +} + +KMF_RETURN +DerDecodeName(KMF_DATA *encodedname, KMF_X509_NAME *name) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue bv; + + bv.bv_val = (char *)encodedname->Data; + bv.bv_len = encodedname->Length; + + asn1 = kmfder_init(&bv); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + (void) memset((void *)name, 0, sizeof (KMF_X509_NAME)); + + if ((ret = get_rdn(asn1, name)) != KMF_OK) + goto cleanup; + +cleanup: + if (asn1) + kmfber_free(asn1, 1); + return (ret); +} + +KMF_RETURN +DerEncodeName(KMF_X509_NAME *name, KMF_DATA *encodedname) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue *bv = NULL; + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + if ((ret = encode_rdn(asn1, name)) != KMF_OK) + goto cleanup; + + if (kmfber_flatten(asn1, &bv) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + encodedname->Data = (uchar_t *)bv->bv_val; + encodedname->Length = bv->bv_len; + +cleanup: + if (bv) + free(bv); + + if (asn1) + kmfber_free(asn1, 1); + + return (ret); +} + +static KMF_RETURN +encode_tbs_cert(BerElement *asn1, KMF_X509_TBS_CERT *tbscert) +{ + KMF_RETURN ret = KMF_OK; + uint32_t version; + + /* version should be 4 bytes or less */ + if (tbscert->version.Length > sizeof (int)) + return (KMF_ERR_BAD_CERT_FORMAT); + + (void) memcpy(&version, tbscert->version.Data, + tbscert->version.Length); + + /* Start the sequence and add the version */ + if (kmfber_printf(asn1, "{Tli", 0xA0, 3, version) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + /* Write the serial number */ + if (kmfber_printf(asn1, "I", + (char *)tbscert->serialNumber.val, + (size_t)tbscert->serialNumber.len) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if ((ret = encode_algoid(asn1, &tbscert->signature)) != KMF_OK) + goto cleanup; + + /* Encode the Issuer RDN */ + if ((ret = encode_rdn(asn1, &tbscert->issuer)) != KMF_OK) + goto cleanup; + + /* Encode the Validity fields */ + if ((ret = encode_validity(asn1, &tbscert->validity)) != KMF_OK) + goto cleanup; + + /* Encode the Subject RDN */ + if ((ret = encode_rdn(asn1, &tbscert->subject)) != KMF_OK) + goto cleanup; + + /* Encode the Subject Public Key Info */ + if ((ret = encode_spki(asn1, &tbscert->subjectPublicKeyInfo)) != KMF_OK) + goto cleanup; + + /* Optional field: issuer Unique ID */ + if (tbscert->issuerUniqueIdentifier.Length > 0) { + if ((ret = encode_uniqueid(asn1, 0xA1, + &tbscert->issuerUniqueIdentifier)) != KMF_OK) + goto cleanup; + } + + /* Optional field: Subject Unique ID */ + if (tbscert->subjectUniqueIdentifier.Length > 0) { + if ((ret = encode_uniqueid(asn1, 0xA2, + &tbscert->subjectUniqueIdentifier)) != KMF_OK) + goto cleanup; + } + + /* Optional field: Certificate Extensions */ + if (tbscert->extensions.numberOfExtensions > 0) { + if ((ret = encode_extensions(asn1, + &tbscert->extensions)) != KMF_OK) + goto cleanup; + } + + /* Close out the TBSCert sequence */ + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + +cleanup: + /* + * Memory cleanup is done in the caller or in the individual + * encoding routines. + */ + + return (ret); +} + +KMF_RETURN +DerEncodeTbsCertificate(KMF_X509_TBS_CERT *tbs_cert_ptr, + KMF_DATA *enc_tbs_cert_ptr) +{ + KMF_RETURN ret; + BerElement *asn1 = NULL; + BerValue *tbsdata = NULL; + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + enc_tbs_cert_ptr->Data = NULL; + enc_tbs_cert_ptr->Length = 0; + + ret = encode_tbs_cert(asn1, tbs_cert_ptr); + if (ret != KMF_OK) + goto cleanup; + + if (kmfber_flatten(asn1, &tbsdata) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + enc_tbs_cert_ptr->Data = (uchar_t *)tbsdata->bv_val; + enc_tbs_cert_ptr->Length = tbsdata->bv_len; + +cleanup: + if (ret != KMF_OK) + free_data(enc_tbs_cert_ptr); + + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (tbsdata) + free(tbsdata); + + return (ret); +} + +KMF_RETURN +DerEncodeSignedCertificate(KMF_X509_CERTIFICATE *signed_cert_ptr, + KMF_DATA *encodedcert) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_TBS_CERT *tbscert = NULL; + KMF_X509_SIGNATURE *signature = NULL; + BerElement *asn1 = NULL; + BerValue *tbsdata = NULL; + + if (signed_cert_ptr == NULL || encodedcert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + encodedcert->Data = NULL; + encodedcert->Length = 0; + + tbscert = &signed_cert_ptr->certificate; + signature = &signed_cert_ptr->signature; + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + /* Start outer X509 Certificate SEQUENCE */ + if (kmfber_printf(asn1, "{") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if ((ret = encode_tbs_cert(asn1, tbscert)) != KMF_OK) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* Add the Algorithm & Signature Sequence */ + if ((ret = encode_algoid(asn1, + &signature->algorithmIdentifier)) != KMF_OK) + goto cleanup; + + if (signature->encrypted.Length > 0) { + if (kmfber_printf(asn1, "B", signature->encrypted.Data, + signature->encrypted.Length * 8) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + } + + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (kmfber_flatten(asn1, &tbsdata) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + encodedcert->Data = (uchar_t *)tbsdata->bv_val; + encodedcert->Length = tbsdata->bv_len; + +cleanup: + if (ret != KMF_OK) + free_data(encodedcert); + + if (tbsdata) + free(tbsdata); + + if (asn1) + kmfber_free(asn1, 1); + + return (ret); +} + +KMF_RETURN +ExtractX509CertParts(KMF_DATA *x509cert, KMF_DATA *tbscert, + KMF_DATA *signature) +{ + KMF_RETURN ret = KMF_OK; + BerElement *der = NULL; + BerValue x509; + ber_tag_t tag; + ber_len_t size; + + if (tbscert == NULL || x509cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + x509.bv_val = (char *)x509cert->Data; + x509.bv_len = x509cert->Length; + + der = kmfder_init(&x509); + if (der == NULL) + return (KMF_ERR_MEMORY); + + /* Skip over the overall Sequence tag to get at the TBS Cert data */ + if (kmfber_scanf(der, "Tl", &tag, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (tag != BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* + * Since we are extracting a copy of the ENCODED bytes, we + * must make sure to also include the bytes for the tag and + * the length fields for the CONSTRUCTED SEQUENCE (TBSCert). + */ + size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size); + + tbscert->Data = malloc(size); + if (tbscert->Data == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + tbscert->Length = size; + + /* The der data ptr is now set to the start of the TBS cert sequence */ + size = kmfber_read(der, (char *)tbscert->Data, tbscert->Length); + if (size != tbscert->Length) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (signature != NULL) { + KMF_X509_ALGORITHM_IDENTIFIER algoid; + if ((ret = get_algoid(der, &algoid)) != KMF_OK) + goto cleanup; + free_algoid(&algoid); + + if (kmfber_scanf(der, "tl", &tag, &size) != BER_BIT_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + /* Now get the signature data */ + if (kmfber_scanf(der, "B", (char **)&signature->Data, + (ber_len_t *)&signature->Length) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + /* convert bitstring length to bytes */ + signature->Length = signature->Length / 8; + } + +cleanup: + if (der) + kmfber_free(der, 1); + + if (ret != KMF_OK) + free_data(tbscert); + + return (ret); +} + +/* + * Name: GetKeyFromSpki + * + * Description: + * This function parses the KMF_X509_SPKI into its + * key and parameter components based on the key generation algorithm. + * NOTE: Currently, it only checks for the RSA and DSA algorithms. + * The RSA algorithm is equivalent to the default behavior. + * All other algorithms will default to the parameters = NULL and the + * key data equal to whatever is in the CSSM_KEY structure for the key + * + * Parameters: + * AlgId (input) : Algorithm identifier + * SpkiPtr (input): SPKI structure that contains the key + * key_ptr(output): The output key + * + */ +KMF_RETURN +GetKeyFromSpki(KMF_ALGORITHM_INDEX AlgId, + KMF_X509_SPKI *SpkiPtr, + KMF_DATA **key_ptr) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1; + BerValue *encodedkey = NULL; + + if (!key_ptr || !SpkiPtr) { + return (KMF_ERR_BAD_PARAMETER); + } + *key_ptr = NULL; + + switch (AlgId) { + case KMF_ALGID_DSA: + asn1 = kmfder_alloc(); + if (asn1 == NULL) { + return (KMF_ERR_MEMORY); + } + + if ((ret = encode_spki(asn1, SpkiPtr)) != KMF_OK) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + if (kmfber_flatten(asn1, &encodedkey) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + *key_ptr = malloc(sizeof (KMF_DATA)); + + if (!*key_ptr) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + (*key_ptr)->Length = encodedkey->bv_len; + (*key_ptr)->Data = (uchar_t *)encodedkey->bv_val; +cleanup: + kmfber_free(asn1, 1); + if (encodedkey) + free(encodedkey); + break; + default: /* RSA */ + *key_ptr = malloc(sizeof (KMF_DATA)); + + if (!*key_ptr) { + return (KMF_ERR_MEMORY); + } + (*key_ptr)->Length = SpkiPtr->subjectPublicKey.Length; + (*key_ptr)->Data = malloc((*key_ptr)->Length); + + if (!(*key_ptr)->Data) { + free(*key_ptr); + *key_ptr = NULL; + return (KMF_ERR_MEMORY); + } + (void) memcpy((*key_ptr)->Data, + SpkiPtr->subjectPublicKey.Data, + (*key_ptr)->Length); + return (ret); + } + return (ret); +} + +static KMF_RETURN +decode_csr_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns) +{ + KMF_RETURN ret = KMF_OK; + BerValue oid; + + if (kmfber_scanf(asn1, "{D", &oid) == -1) { + return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE); + } + + /* We only understand extension requests in a CSR */ + if (memcmp(oid.bv_val, extension_request_oid.Data, + oid.bv_len) != 0) { + return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE); + } + + if (kmfber_scanf(asn1, "[") == -1) { + return (KMF_ERR_ENCODING); + } + ret = get_extensions(asn1, extns); + + + return (ret); +} + +static KMF_RETURN +decode_tbscsr_data(BerElement *asn1, + KMF_TBS_CSR **signed_csr_ptr_ptr) +{ + KMF_RETURN ret = KMF_OK; + KMF_TBS_CSR *tbscsr = NULL; + char *end = NULL; + uint32_t version; + ber_tag_t tag; + ber_len_t size; + + /* Now get the version number, it is not optional */ + if (kmfber_scanf(asn1, "{i", &version) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + tbscsr = malloc(sizeof (KMF_TBS_CSR)); + if (!tbscsr) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + (void) memset(tbscsr, 0, sizeof (KMF_TBS_CSR)); + + if ((ret = set_der_integer(&tbscsr->version, version)) != KMF_OK) + goto cleanup; + + if ((ret = get_rdn(asn1, &tbscsr->subject)) != KMF_OK) + goto cleanup; + + if ((ret = get_spki(asn1, &tbscsr->subjectPublicKeyInfo)) != KMF_OK) + goto cleanup; + + /* Check for the optional fields (attributes) */ + if (kmfber_next_element(asn1, &size, end) == 0xA0) { + if (kmfber_scanf(asn1, "Tl", &tag, &size) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + + ret = decode_csr_extensions(asn1, &tbscsr->extensions); + } + if (ret == KMF_OK) + *signed_csr_ptr_ptr = tbscsr; + +cleanup: + if (ret != KMF_OK) { + if (tbscsr) { + free_tbscsr(tbscsr); + free(tbscsr); + } + *signed_csr_ptr_ptr = NULL; + } + return (ret); +} + +KMF_RETURN +DerDecodeTbsCsr(const KMF_DATA *Value, + KMF_TBS_CSR **tbscsr) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue rawcsr; + KMF_TBS_CSR *newcsr = NULL; + + if (!tbscsr || !Value || !Value->Data || !Value->Length) + return (KMF_ERR_BAD_PARAMETER); + + rawcsr.bv_val = (char *)Value->Data; + rawcsr.bv_len = Value->Length; + + if ((asn1 = kmfder_init(&rawcsr)) == NULL) + return (KMF_ERR_MEMORY); + + ret = decode_tbscsr_data(asn1, &newcsr); + if (ret != KMF_OK) + goto cleanup; + + *tbscsr = newcsr; + +cleanup: + if (ret != KMF_OK) { + if (newcsr) + free_tbscsr(newcsr); + *tbscsr = NULL; + } + kmfber_free(asn1, 1); + + return (ret); +} + +KMF_RETURN +DerDecodeSignedCsr(const KMF_DATA *Value, + KMF_CSR_DATA **signed_csr_ptr_ptr) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue rawcsr; + int tag; + ber_len_t size; + char *end = NULL; + char *signature; + KMF_TBS_CSR *tbscsr = NULL; + KMF_CSR_DATA *csrptr = NULL; + + if (!signed_csr_ptr_ptr || !Value || !Value->Data || !Value->Length) + return (KMF_ERR_BAD_PARAMETER); + + rawcsr.bv_val = (char *)Value->Data; + rawcsr.bv_len = Value->Length; + + if ((asn1 = kmfder_init(&rawcsr)) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_first_element(asn1, &size, &end) != + BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + csrptr = malloc(sizeof (KMF_CSR_DATA)); + if (csrptr == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memset(csrptr, 0, sizeof (KMF_CSR_DATA)); + + ret = decode_tbscsr_data(asn1, &tbscsr); + if (ret != KMF_OK) + goto cleanup; + + csrptr->csr = *tbscsr; + free(tbscsr); + tbscsr = NULL; + + if ((ret = get_algoid(asn1, + &csrptr->signature.algorithmIdentifier)) != KMF_OK) + goto cleanup; + + /* Check to see if the cert has a signature yet */ + if (kmfber_next_element(asn1, &size, end) == BER_BIT_STRING) { + /* Finally, get the encrypted signature BITSTRING */ + if (kmfber_scanf(asn1, "tl", &tag, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (tag != BER_BIT_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if (kmfber_scanf(asn1, "B}", &signature, &size) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + csrptr->signature.encrypted.Data = (uchar_t *)signature; + csrptr->signature.encrypted.Length = size / 8; + } else { + csrptr->signature.encrypted.Data = NULL; + csrptr->signature.encrypted.Length = 0; + } + + *signed_csr_ptr_ptr = csrptr; +cleanup: + if (ret != KMF_OK) { + free_tbscsr(&csrptr->csr); + free_algoid(&csrptr->signature.algorithmIdentifier); + if (csrptr->signature.encrypted.Data) + free(csrptr->signature.encrypted.Data); + + if (csrptr) + free(csrptr); + + *signed_csr_ptr_ptr = NULL; + } + if (asn1) + kmfber_free(asn1, 1); + + return (ret); + +} + +static KMF_RETURN +encode_csr_extensions(BerElement *asn1, KMF_TBS_CSR *tbscsr) +{ + KMF_RETURN ret = KMF_OK; + int attlen = 0; + BerElement *extnasn1 = NULL; + BerValue *extnvalue = NULL; + + /* Optional field: CSR attributes and extensions */ + if (tbscsr->extensions.numberOfExtensions > 0) { + if (kmfber_printf(asn1, "T", 0xA0) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + } else { + /* No extensions or attributes to encode */ + return (KMF_OK); + } + + /* + * attributes [0] Attributes + * Attributes := SET OF Attribute + * Attribute := SEQUENCE { + * { ATTRIBUTE ID + * values SET SIZE(1..MAX) of ATTRIBUTE + * } + * + * Ex: { ExtensionRequest OID [ { {extn1 } , {extn2 } } ] } + */ + + /* + * Encode any extensions and add to the attributes section. + */ + if (tbscsr->extensions.numberOfExtensions > 0) { + extnasn1 = kmfder_alloc(); + if (extnasn1 == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + if (kmfber_printf(extnasn1, "{D[{", + &extension_request_oid) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup_1; + } + + if ((ret = encode_extension_list(extnasn1, + &tbscsr->extensions)) != KMF_OK) { + goto cleanup_1; + } + + if (kmfber_printf(extnasn1, "}]}") == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup_1; + } + + if (kmfber_flatten(extnasn1, &extnvalue) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup_1; + } +cleanup_1: + kmfber_free(extnasn1, 1); + + if (ret == KMF_OK) + /* Add 2 bytes to cover the tag and the length */ + attlen = extnvalue->bv_len; + } + if (ret != KMF_OK) + goto cleanup; + + if (kmfber_printf(asn1, "l", attlen) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Write the actual encoded extensions */ + if (extnvalue != NULL && extnvalue->bv_val != NULL) { + if (kmfber_write(asn1, extnvalue->bv_val, + extnvalue->bv_len, 0) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + } + +cleanup: + /* + * Memory cleanup is done in the caller or in the individual + * encoding routines. + */ + if (extnvalue) { + if (extnvalue->bv_val) + free(extnvalue->bv_val); + free(extnvalue); + } + + return (ret); +} + +static KMF_RETURN +encode_tbs_csr(BerElement *asn1, KMF_TBS_CSR *tbscsr) +{ + KMF_RETURN ret = KMF_OK; + uint32_t version; + + /* Start the version */ + (void) memcpy(&version, tbscsr->version.Data, + tbscsr->version.Length); + + if (kmfber_printf(asn1, "{i", &version) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* Encode the Subject RDN */ + if ((ret = encode_rdn(asn1, &tbscsr->subject)) != KMF_OK) + goto cleanup; + + /* Encode the Subject Public Key Info */ + if ((ret = encode_spki(asn1, &tbscsr->subjectPublicKeyInfo)) != KMF_OK) + goto cleanup; + + + if ((ret = encode_csr_extensions(asn1, tbscsr)) != KMF_OK) + goto cleanup; + + /* Close out the TBSCert sequence */ + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + +cleanup: + return (ret); +} + +KMF_RETURN +DerEncodeDSAPrivateKey(KMF_DATA *encodedkey, KMF_RAW_DSA_KEY *dsa) +{ + KMF_RETURN rv = KMF_OK; + BerElement *asn1 = NULL; + BerValue *dsadata = NULL; + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(asn1, "I", + dsa->value.val, dsa->value.len) == -1) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + + if (kmfber_flatten(asn1, &dsadata) == -1) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + + encodedkey->Data = (uchar_t *)dsadata->bv_val; + encodedkey->Length = dsadata->bv_len; + + free(dsadata); +cleanup: + kmfber_free(asn1, 1); + return (rv); +} + +KMF_RETURN +DerEncodeRSAPrivateKey(KMF_DATA *encodedkey, KMF_RAW_RSA_KEY *rsa) +{ + KMF_RETURN rv = KMF_OK; + BerElement *asn1 = NULL; + uchar_t ver = 0; + BerValue *rsadata = NULL; + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(asn1, "{IIIIIIIII}", + &ver, 1, + rsa->mod.val, rsa->mod.len, + rsa->pubexp.val, rsa->pubexp.len, + rsa->priexp.val, rsa->priexp.len, + rsa->prime1.val, rsa->prime1.len, + rsa->prime2.val, rsa->prime2.len, + rsa->exp1.val, rsa->exp1.len, + rsa->exp2.val, rsa->exp2.len, + rsa->coef.val, rsa->coef.len) == -1) + goto cleanup; + + if (kmfber_flatten(asn1, &rsadata) == -1) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + + encodedkey->Data = (uchar_t *)rsadata->bv_val; + encodedkey->Length = rsadata->bv_len; + + free(rsadata); +cleanup: + kmfber_free(asn1, 1); + return (rv); +} + + +KMF_RETURN +DerEncodeTbsCsr(KMF_TBS_CSR *tbs_csr_ptr, + KMF_DATA *enc_tbs_csr_ptr) +{ + KMF_RETURN ret; + BerValue *tbsdata = NULL; + BerElement *asn1 = NULL; + + asn1 = kmfder_alloc(); + + enc_tbs_csr_ptr->Data = NULL; + enc_tbs_csr_ptr->Length = 0; + + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + ret = encode_tbs_csr(asn1, tbs_csr_ptr); + if (ret != KMF_OK) + goto cleanup; + + if (kmfber_flatten(asn1, &tbsdata) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + enc_tbs_csr_ptr->Data = (uchar_t *)tbsdata->bv_val; + enc_tbs_csr_ptr->Length = tbsdata->bv_len; + +cleanup: + if (ret != KMF_OK) + free_data(enc_tbs_csr_ptr); + + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (tbsdata) + free(tbsdata); + + return (ret); +} + +KMF_RETURN +DerEncodeSignedCsr(KMF_CSR_DATA *signed_csr_ptr, + KMF_DATA *encodedcsr) +{ + KMF_RETURN ret = KMF_OK; + KMF_TBS_CSR *tbscsr = NULL; + KMF_X509_SIGNATURE *signature = NULL; + BerElement *asn1 = NULL; + BerValue *tbsdata = NULL; + + if (signed_csr_ptr == NULL) + return (KMF_ERR_BAD_PARAMETER); + + tbscsr = &signed_csr_ptr->csr; + signature = &signed_csr_ptr->signature; + + asn1 = kmfder_alloc(); + if (asn1 == NULL) + return (KMF_ERR_MEMORY); + + /* Start outer CSR SEQUENCE */ + if (kmfber_printf(asn1, "{") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + ret = encode_tbs_csr(asn1, tbscsr); + + /* Add the Algorithm & Signature Sequence */ + if ((ret = encode_algoid(asn1, + &signature->algorithmIdentifier)) != KMF_OK) + goto cleanup; + + if (signature->encrypted.Length > 0) { + if (kmfber_printf(asn1, "B", signature->encrypted.Data, + signature->encrypted.Length * 8) == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + } + + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (kmfber_flatten(asn1, &tbsdata) == -1) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + encodedcsr->Data = (uchar_t *)tbsdata->bv_val; + encodedcsr->Length = tbsdata->bv_len; + +cleanup: + if (ret != KMF_OK) { + free_data(encodedcsr); + } + + if (tbsdata) + free(tbsdata); + + if (asn1) + kmfber_free(asn1, 1); + return (ret); +} + +KMF_RETURN +ExtractSPKIData( + const KMF_X509_SPKI *pKey, + KMF_ALGORITHM_INDEX AlgorithmId, + KMF_DATA *pKeyParts, + uint32_t *uNumKeyParts) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue *P, *Q, *G, *Mod, *Exp, *PubKey; + BerValue PubKeyParams, PubKeyData; + + if (pKeyParts == NULL || uNumKeyParts == NULL || pKey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + switch (AlgorithmId) { + case KMF_ALGID_DSA: + case KMF_ALGID_SHA1WithDSA: + /* First, get the parameters from the algorithm definition */ + PubKeyParams.bv_val = (char *)pKey->algorithm.parameters.Data; + PubKeyParams.bv_len = pKey->algorithm.parameters.Length; + if ((asn1 = kmfder_init(&PubKeyParams)) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_scanf(asn1, "{III}", &P, &Q, &G) == -1) { + kmfber_free(asn1, 1); + return (KMF_ERR_BAD_KEY_FORMAT); + } + pKeyParts[KMF_DSA_PRIME].Data = (uchar_t *)P->bv_val; + pKeyParts[KMF_DSA_PRIME].Length = P->bv_len; + pKeyParts[KMF_DSA_SUB_PRIME].Data = (uchar_t *)Q->bv_val; + pKeyParts[KMF_DSA_SUB_PRIME].Length = Q->bv_len; + pKeyParts[KMF_DSA_BASE].Data = (uchar_t *)G->bv_val; + pKeyParts[KMF_DSA_BASE].Length = G->bv_len; + + free(P); + free(Q); + free(G); + kmfber_free(asn1, 1); + + /* Get the PubKey data */ + PubKeyData.bv_val = (char *)pKey->subjectPublicKey.Data; + PubKeyData.bv_len = pKey->subjectPublicKey.Length; + if ((asn1 = kmfder_init(&PubKeyData)) == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + PubKey = NULL; + if (kmfber_scanf(asn1, "I", &PubKey) == -1) { + ret = KMF_ERR_BAD_KEY_FORMAT; + goto cleanup; + } + pKeyParts[KMF_DSA_PUBLIC_VALUE].Data = + (uchar_t *)PubKey->bv_val; + pKeyParts[KMF_DSA_PUBLIC_VALUE].Length = PubKey->bv_len; + + free(PubKey); + + *uNumKeyParts = KMF_NUMBER_DSA_PUBLIC_KEY_PARTS; + break; + + case KMF_ALGID_RSA: + case KMF_ALGID_MD2WithRSA: + case KMF_ALGID_MD5WithRSA: + case KMF_ALGID_SHA1WithRSA: + PubKeyData.bv_val = (char *)pKey->subjectPublicKey.Data; + PubKeyData.bv_len = pKey->subjectPublicKey.Length; + if ((asn1 = kmfder_init(&PubKeyData)) == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + if (kmfber_scanf(asn1, "{II}", &Mod, &Exp) == -1) { + ret = KMF_ERR_BAD_KEY_FORMAT; + goto cleanup; + } + pKeyParts[KMF_RSA_MODULUS].Data = (uchar_t *)Mod->bv_val; + pKeyParts[KMF_RSA_MODULUS].Length = Mod->bv_len; + pKeyParts[KMF_RSA_PUBLIC_EXPONENT].Data = + (uchar_t *)Exp->bv_val; + pKeyParts[KMF_RSA_PUBLIC_EXPONENT].Length = Exp->bv_len; + *uNumKeyParts = KMF_NUMBER_RSA_PUBLIC_KEY_PARTS; + + free(Mod); + free(Exp); + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } +cleanup: + if (ret != KMF_OK) { + int i; + for (i = 0; i < *uNumKeyParts; i++) + free_data(&pKeyParts[i]); + } + if (asn1 != NULL) { + kmfber_free(asn1, 1); + } + + return (ret); +} diff --git a/usr/src/lib/libkmf/ber_der/common/decode.c b/usr/src/lib/libkmf/ber_der/common/decode.c new file mode 100644 index 0000000000..7d6167fc51 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/common/decode.c @@ -0,0 +1,817 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +/* decode.c - ber input decoding routines */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <strings.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <inttypes.h> + +#include <ber_der.h> +#include "kmfber_int.h" + +static void +ber_svecfree(char **vals) +{ + int i; + + if (vals == NULL) + return; + for (i = 0; vals[i] != NULL; i++) + free(vals[i]); + free((char *)vals); +} + +/* + * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber. + * If that changes, the kmfber_peek_tag() and/or + * kmfkmfber_skip_tag() implementations will need to be changed. + */ +/* return the tag - KMFBER_DEFAULT returned means trouble */ +static ber_tag_t +kmfber_get_tag(BerElement *ber) +{ + unsigned char xbyte; + ber_tag_t tag; + char *tagp; + int i; + + if (kmfber_read(ber, (char *)&xbyte, 1) != 1) + return (KMFBER_DEFAULT); + + if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK) + return ((ber_uint_t)xbyte); + + tagp = (char *)&tag; + tagp[0] = xbyte; + for (i = 1; i < sizeof (ber_int_t); i++) { + if (kmfber_read(ber, (char *)&xbyte, 1) != 1) + return (KMFBER_DEFAULT); + + tagp[i] = xbyte; + + if (! (xbyte & KMFBER_MORE_TAG_MASK)) + break; + } + + /* tag too big! */ + if (i == sizeof (ber_int_t)) + return (KMFBER_DEFAULT); + + /* want leading, not trailing 0's */ + return (tag >> (sizeof (ber_int_t)- i - 1)); +} + +/* + * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber. + * If that changes, the implementation of kmfber_peek_tag() will need to + * be changed. + */ +ber_tag_t +kmfber_skip_tag(BerElement *ber, ber_len_t *len) +{ + ber_tag_t tag; + unsigned char lc; + int noctets, diff; + uint32_t netlen; + + /* + * Any ber element looks like this: tag length contents. + * Assuming everything's ok, we return the tag byte (we + * can assume a single byte), and return the length in len. + * + * Assumptions: + * 1) definite lengths + * 2) primitive encodings used whenever possible + */ + + /* + * First, we read the tag. + */ + + if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT) + return (KMFBER_DEFAULT); + + /* + * Next, read the length. The first byte contains the length of + * the length. If bit 8 is set, the length is the long form, + * otherwise it's the short form. We don't allow a length that's + * greater than what we can hold in an unsigned long. + */ + + *len = 0; + netlen = 0; + if (kmfber_read(ber, (char *)&lc, 1) != 1) + return (KMFBER_DEFAULT); + if (lc & 0x80) { + noctets = (lc & 0x7f); + if (noctets > sizeof (ber_uint_t)) + return (KMFBER_DEFAULT); + diff = sizeof (ber_int_t) - noctets; + if (kmfber_read(ber, (char *)&netlen + diff, noctets) + != noctets) + return (KMFBER_DEFAULT); + *len = ntohl(netlen); + } else { + *len = lc; + } + + return (tag); +} + + +/* + * Note: Previously, we passed the "ber" parameter directly to + * kmfber_skip_tag(), saving and restoring the ber_ptr element only. + * We now take advantage of the fact that the only ber structure + * elements touched by kmfber_skip_tag() are ber_end and ber_ptr. + * If that changes, this code must change too. + */ +static ber_tag_t +kmfber_peek_tag(BerElement *ber, ber_len_t *len) +{ + BerElement bercopy; + + bercopy.ber_end = ber->ber_end; + bercopy.ber_ptr = ber->ber_ptr; + return (kmfber_skip_tag(&bercopy, len)); +} + +static int +ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len) +{ + int i; + ber_int_t value; + unsigned char buffer[sizeof (ber_int_t)]; + /* + * The tag and length have already been stripped off. We should + * be sitting right before len bytes of 2's complement integer, + * ready to be read straight into an int. We may have to sign + * extend after we read it in. + */ + + if (len > sizeof (ber_slen_t)) + return (-1); + + /* read into the low-order bytes of netnum */ + if (kmfber_read(ber, (char *)buffer, len) != len) + return (-1); + + /* This sets the required sign extension */ + if (len != 0) { + value = 0x80 & buffer[0] ? (-1) : 0; + } else { + value = 0; + } + + for (i = 0; i < len; i++) + value = (value << 8) | buffer[i]; + + *num = value; + + return (len); +} + +static ber_tag_t +kmfber_get_int(BerElement *ber, ber_int_t *num) +{ + ber_tag_t tag; + ber_len_t len; + + if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) + return (KMFBER_DEFAULT); + + /* + * len is being demoted to a long here -- possible conversion error + */ + + if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len) + return (KMFBER_DEFAULT); + else + return (tag); +} + +static ber_tag_t +kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len) +{ + ber_len_t datalen; + ber_tag_t tag; +#ifdef STR_TRANSLATION + char *transbuf; +#endif /* STR_TRANSLATION */ + + if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT) + return (KMFBER_DEFAULT); + if (datalen > (*len - 1)) + return (KMFBER_DEFAULT); + + /* + * datalen is being demoted to a long here -- possible conversion error + */ + + if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen) + return (KMFBER_DEFAULT); + + buf[datalen] = '\0'; + +#ifdef STR_TRANSLATION + if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) + != 0 && ber->ber_decode_translate_proc != NULL) { + + transbuf = buf; + ++datalen; + if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen, + 0) != 0) { + return (KMFBER_DEFAULT); + } + if (datalen > *len) { + free(transbuf); + return (KMFBER_DEFAULT); + } + (void) memmove(buf, transbuf, datalen); + free(transbuf); + --datalen; + } +#endif /* STR_TRANSLATION */ + + *len = datalen; + return (tag); +} + +static ber_tag_t +kmfber_get_stringa(BerElement *ber, char **buf) +{ + ber_len_t datalen; + ber_tag_t tag; + + if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT) + return (KMFBER_DEFAULT); + + if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL) + return (KMFBER_DEFAULT); + + /* + * datalen is being demoted to a long here -- possible conversion error + */ + if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen) + return (KMFBER_DEFAULT); + (*buf)[datalen] = '\0'; + + return (tag); +} + +ber_tag_t +ber_get_oid(BerElement *ber, struct berval *oid) +{ + ber_len_t len; + ber_tag_t tag; + + if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) { + return (KMFBER_DEFAULT); + } + + if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) { + return (KMFBER_DEFAULT); + } + oid->bv_len = len; + + if (kmfber_read(ber, oid->bv_val, oid->bv_len) != + (ber_slen_t)oid->bv_len) + return (KMFBER_DEFAULT); + + return (tag); +} + +ber_tag_t +ber_get_bigint(BerElement *ber, struct berval **bv) +{ + ber_len_t len; + ber_tag_t tag; + + if ((*bv = (struct berval *)malloc(sizeof (struct berval))) + == NULL) { + return (KMFBER_DEFAULT); + } + + if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) { + return (KMFBER_DEFAULT); + } + + if (((*bv)->bv_val = (char *)malloc((size_t)len + 1)) + == NULL) { + return (KMFBER_DEFAULT); + } + + /* + * len is being demoted to a long here -- possible conversion error + */ + if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len) + return (KMFBER_DEFAULT); + + (*bv)->bv_len = len; + + /* If DER encoding, strip leading 0's */ + if (ber->ber_options & KMFBER_OPT_USE_DER) { + char *p = (*bv)->bv_val; + while ((*p == 0x00) && ((*bv)->bv_len > 0)) { + p++; + (*bv)->bv_len--; + } + /* + * Shift the buffer to the beginning of the allocated space + * so it can be properly freed later. + */ + if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0)) + (void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len); + } + + return (tag); +} + +static ber_tag_t +kmfber_get_stringal(BerElement *ber, struct berval **bv) +{ + ber_len_t len; + ber_tag_t tag; + + if ((*bv = (struct berval *)malloc(sizeof (struct berval))) + == NULL) { + return (KMFBER_DEFAULT); + } + + if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) { + return (KMFBER_DEFAULT); + } + + if (((*bv)->bv_val = (char *)malloc((size_t)len + 1)) + == NULL) { + return (KMFBER_DEFAULT); + } + + /* + * len is being demoted to a long here -- possible conversion error + */ + if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len) + return (KMFBER_DEFAULT); + ((*bv)->bv_val)[len] = '\0'; + (*bv)->bv_len = len; + + return (tag); +} + +static ber_tag_t +kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen) +{ + ber_len_t datalen; + ber_tag_t tag; + unsigned char unusedbits; + + if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT) + return (KMFBER_DEFAULT); + + if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL) + return (KMFBER_DEFAULT); + + if (kmfber_read(ber, (char *)&unusedbits, 1) != 1) + return (KMFBER_DEFAULT); + + /* Subtract 1 for the unused bits */ + datalen--; + + /* + * datalen is being demoted to a long here -- possible conversion error + */ + if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen) + return (KMFBER_DEFAULT); + + *blen = datalen * 8 - unusedbits; + return (tag); +} + +static ber_tag_t +kmfber_get_null(BerElement *ber) +{ + ber_len_t len; + ber_tag_t tag; + + if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) + return (KMFBER_DEFAULT); + + if (len != 0) + return (KMFBER_DEFAULT); + + return (tag); +} + +static ber_tag_t +kmfber_get_boolean(BerElement *ber, int *boolval) +{ + ber_int_t longbool; + int rc; + + rc = kmfber_get_int(ber, &longbool); + *boolval = longbool; + + return (rc); +} + +ber_tag_t +kmfber_first_element(BerElement *ber, ber_len_t *len, char **last) +{ + /* skip the sequence header, use the len to mark where to stop */ + if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) { + return (KMFBER_ERROR); + } + + *last = ber->ber_ptr + *len; + + if (*last == ber->ber_ptr) { + return (KMFBER_END_OF_SEQORSET); + } + + return (kmfber_peek_tag(ber, len)); +} + +ber_tag_t +kmfber_next_element(BerElement *ber, ber_len_t *len, char *last) +{ + if (ber->ber_ptr == last) { + return (KMFBER_END_OF_SEQORSET); + } + + return (kmfber_peek_tag(ber, len)); +} + +void +kmfber_bvfree(struct berval *bv) +{ + if (bv != NULL) { + if (bv->bv_val != NULL) { + free(bv->bv_val); + } + free((char *)bv); + } +} + +void +kmfber_bvecfree(struct berval **bv) +{ + int i; + + if (bv != NULL) { + for (i = 0; bv[i] != NULL; i++) { + kmfber_bvfree(bv[i]); + } + free((char *)bv); + } +} + +/* VARARGS */ +ber_tag_t +kmfber_scanf(BerElement *ber, const char *fmt, ...) +{ + va_list ap; + char *last, *p; + char *s, **ss, ***sss; + struct berval ***bv, **bvp, *bval; + int *i, j; + ber_slen_t *l; + ber_int_t rc, tag, *b_int; + ber_tag_t *t; + ber_len_t len; + size_t array_size; + + va_start(ap, fmt); + + for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) { + switch (*p) { + case 'a': /* octet string - allocate storage as needed */ + ss = va_arg(ap, char **); + rc = kmfber_get_stringa(ber, ss); + break; + + case 'b': /* boolean */ + i = va_arg(ap, int *); + rc = kmfber_get_boolean(ber, i); + break; + + case 'D': /* Object ID */ + bval = va_arg(ap, struct berval *); + rc = ber_get_oid(ber, bval); + break; + case 'e': /* enumerated */ + case 'i': /* int */ + b_int = va_arg(ap, ber_int_t *); + rc = kmfber_get_int(ber, b_int); + break; + + case 'l': /* length of next item */ + l = va_arg(ap, ber_slen_t *); + rc = kmfber_peek_tag(ber, (ber_len_t *)l); + break; + + case 'n': /* null */ + rc = kmfber_get_null(ber); + break; + + case 's': /* octet string - in a buffer */ + s = va_arg(ap, char *); + l = va_arg(ap, ber_slen_t *); + rc = kmfber_get_stringb(ber, s, (ber_len_t *)l); + break; + + case 'o': /* octet string in a supplied berval */ + bval = va_arg(ap, struct berval *); + (void) kmfber_peek_tag(ber, &bval->bv_len); + rc = kmfber_get_stringa(ber, &bval->bv_val); + break; + + case 'I': /* variable length Integer */ + /* Treat INTEGER same as an OCTET string, but ignore the tag */ + bvp = va_arg(ap, struct berval **); + rc = ber_get_bigint(ber, bvp); + break; + case 'O': /* octet string - allocate & include length */ + bvp = va_arg(ap, struct berval **); + rc = kmfber_get_stringal(ber, bvp); + break; + + case 'B': /* bit string - allocate storage as needed */ + ss = va_arg(ap, char **); + l = va_arg(ap, ber_slen_t *); /* for length, in bits */ + rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l); + break; + + case 't': /* tag of next item */ + t = va_arg(ap, ber_tag_t *); + *t = kmfber_peek_tag(ber, &len); + rc = (ber_int_t)(*t); + break; + + case 'T': /* skip tag of next item */ + t = va_arg(ap, ber_tag_t *); + *t = kmfber_skip_tag(ber, &len); + rc = (ber_int_t)(*t); + break; + + case 'v': /* sequence of strings */ + sss = va_arg(ap, char ***); + *sss = NULL; + j = 0; + array_size = 0; + for (tag = kmfber_first_element(ber, &len, &last); + (tag != KMFBER_DEFAULT && + tag != KMFBER_END_OF_SEQORSET && + rc != KMFBER_DEFAULT); + tag = kmfber_next_element(ber, &len, last)) { + if (*sss == NULL) { + /* Make room for at least 15 strings */ + *sss = (char **)malloc(16 * sizeof (char *)); + array_size = 16; + } else { + if ((size_t)(j+2) > array_size) { + /* We'v overflowed our buffer */ + *sss = (char **)realloc(*sss, + (array_size * 2) * sizeof (char *)); + array_size = array_size * 2; + } + } + rc = kmfber_get_stringa(ber, &((*sss)[j])); + j++; + } + if (rc != KMFBER_DEFAULT && + tag != KMFBER_END_OF_SEQORSET) { + rc = KMFBER_DEFAULT; + } + if (j > 0) + (*sss)[j] = NULL; + break; + + case 'V': /* sequence of strings + lengths */ + bv = va_arg(ap, struct berval ***); + *bv = NULL; + j = 0; + for (tag = kmfber_first_element(ber, &len, &last); + (tag != KMFBER_DEFAULT && + tag != KMFBER_END_OF_SEQORSET && + rc != KMFBER_DEFAULT); + tag = kmfber_next_element(ber, &len, last)) { + if (*bv == NULL) { + *bv = (struct berval **)malloc( + 2 * sizeof (struct berval *)); + } else { + *bv = (struct berval **)realloc(*bv, + (j + 2) * sizeof (struct berval *)); + } + rc = kmfber_get_stringal(ber, &((*bv)[j])); + j++; + } + if (rc != KMFBER_DEFAULT && + tag != KMFBER_END_OF_SEQORSET) { + rc = KMFBER_DEFAULT; + } + if (j > 0) + (*bv)[j] = NULL; + break; + + case 'x': /* skip the next element - whatever it is */ + if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) + break; + ber->ber_ptr += len; + break; + + case '{': /* begin sequence */ + case '[': /* begin set */ + if (*(p + 1) != 'v' && *(p + 1) != 'V') + rc = kmfber_skip_tag(ber, &len); + break; + + case '}': /* end sequence */ + case ']': /* end set */ + break; + + default: +#ifdef KMFBER_DEBUG + { + char msg[80]; + sprintf(msg, "unknown fmt %c\n", *p); + ber_err_print(msg); + } +#endif + rc = KMFBER_DEFAULT; + break; + } + } + + + va_end(ap); + if (rc == KMFBER_DEFAULT) { + va_start(ap, fmt); + for (p--; fmt < p && *fmt; fmt++) { + switch (*fmt) { + case 'a': /* octet string - allocate storage as needed */ + ss = va_arg(ap, char **); + free(*ss); + *ss = NULL; + break; + + case 'b': /* boolean */ + i = va_arg(ap, int *); + break; + + case 'e': /* enumerated */ + case 'i': /* int */ + l = va_arg(ap, ber_slen_t *); + break; + + case 'l': /* length of next item */ + l = va_arg(ap, ber_slen_t *); + break; + + case 'n': /* null */ + break; + + case 's': /* octet string - in a buffer */ + s = va_arg(ap, char *); + l = va_arg(ap, ber_slen_t *); + break; + + case 'o': /* octet string in a supplied berval */ + bval = va_arg(ap, struct berval *); + if (bval->bv_val) free(bval->bv_val); + (void) memset(bval, 0, sizeof (struct berval)); + break; + + case 'O': /* octet string - allocate & include length */ + bvp = va_arg(ap, struct berval **); + kmfber_bvfree(*bvp); + bvp = NULL; + break; + + case 'B': /* bit string - allocate storage as needed */ + ss = va_arg(ap, char **); + l = va_arg(ap, ber_slen_t *); /* for length, in bits */ + if (*ss) free(*ss); + *ss = NULL; + break; + + case 't': /* tag of next item */ + t = va_arg(ap, ber_tag_t *); + break; + case 'T': /* skip tag of next item */ + t = va_arg(ap, ber_tag_t *); + break; + + case 'v': /* sequence of strings */ + sss = va_arg(ap, char ***); + ber_svecfree(*sss); + *sss = NULL; + break; + + case 'V': /* sequence of strings + lengths */ + bv = va_arg(ap, struct berval ***); + kmfber_bvecfree(*bv); + *bv = NULL; + break; + + case 'x': /* skip the next element - whatever it is */ + break; + + case '{': /* begin sequence */ + case '[': /* begin set */ + break; + + case '}': /* end sequence */ + case ']': /* end set */ + break; + + default: + break; + } + } /* for */ + va_end(ap); + } /* if */ + + + return (rc); +} + +struct berval * +kmfber_bvdup(const struct berval *bv) +{ + struct berval *new; + + if ((new = (struct berval *)malloc(sizeof (struct berval))) + == NULL) { + return (NULL); + } + if (bv->bv_val == NULL) { + new->bv_val = NULL; + new->bv_len = 0; + } else { + if ((new->bv_val = (char *)malloc(bv->bv_len + 1)) + == NULL) { + return (NULL); + } + (void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len); + new->bv_val[bv->bv_len] = '\0'; + new->bv_len = bv->bv_len; + } + + return (new); +} diff --git a/usr/src/lib/libkmf/ber_der/common/encode.c b/usr/src/lib/libkmf/ber_der/common/encode.c new file mode 100644 index 0000000000..bf78d8e719 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/common/encode.c @@ -0,0 +1,744 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <netinet/in.h> +#include <inttypes.h> + +#include <ber_der.h> +#include "kmfber_int.h" + +/* the following constants are used in kmfber_calc_lenlen */ + +#define LENMASK1 0xFF +#define LENMASK2 0xFFFF +#define LENMASK3 0xFFFFFF +#define LENMASK4 0xFFFFFFFF +#define _MASK 0x80 + +int +kmfber_calc_taglen(ber_tag_t tag) +{ + int i; + ber_int_t mask; + + /* find the first non-all-zero byte in the tag */ + for (i = sizeof (ber_int_t) - 1; i > 0; i--) { + mask = (LENMASK3 << (i * 8)); + /* not all zero */ + if (tag & mask) + break; + } + + return (i + 1); +} + +static int +ber_put_tag(BerElement *ber, ber_tag_t tag, int nosos) +{ + ber_int_t taglen; + ber_tag_t ntag; + + taglen = kmfber_calc_taglen(tag); + + ntag = htonl(tag); + + return (kmfber_write(ber, + ((char *) &ntag) + sizeof (ber_int_t) - taglen, + taglen, nosos)); +} + +int +kmfber_calc_lenlen(ber_int_t len) +{ + /* + * short len if it's less than 128 - one byte giving the len, + * with bit 8 0. + */ + + if (len <= 0x7F) + return (1); + + /* + * long len otherwise - one byte with bit 8 set, giving the + * length of the length, followed by the length itself. + */ + + if (len <= LENMASK1) + return (2); + if (len <= LENMASK2) + return (3); + if (len <= LENMASK3) + return (4); + + return (5); +} + +int +kmfber_put_len(BerElement *ber, ber_int_t len, int nosos) +{ + int i; + char lenlen; + ber_int_t mask, netlen; + + /* + * short len if it's less than 128 - one byte giving the len, + * with bit 8 0. + */ + if (len <= 127) { + netlen = htonl(len); + return (kmfber_write(ber, + (char *)&netlen + sizeof (ber_int_t) - 1, + 1, nosos)); + } + + /* + * long len otherwise - one byte with bit 8 set, giving the + * length of the length, followed by the length itself. + */ + + /* find the first non-all-zero byte */ + for (i = sizeof (ber_int_t) - 1; i > 0; i--) { + mask = (LENMASK1 << (i * 8)); + /* not all zero */ + if (len & mask) + break; + } + lenlen = ++i; + if (lenlen > 4) + return (-1); + lenlen |= 0x80; + + /* write the length of the length */ + if (kmfber_write(ber, &lenlen, 1, nosos) != 1) + return (-1); + + /* write the length itself */ + netlen = htonl(len); + if (kmfber_write(ber, + (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i) + return (-1); + + return (i + 1); +} + +static int +ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) +{ + int i, sign; + ber_int_t len, lenlen, taglen, netnum, mask; + + sign = (num < 0); + + /* + * high bit is set - look for first non-all-one byte + * high bit is clear - look for first non-all-zero byte + */ + for (i = sizeof (ber_int_t) - 1; i > 0; i--) { + mask = (LENMASK1 << (i * 8)); + + if (sign) { + /* not all ones */ + if ((num & mask) != mask) + break; + } else { + /* not all zero */ + if (num & mask) + break; + } + } + + /* + * we now have the "leading byte". if the high bit on this + * byte matches the sign bit, we need to "back up" a byte. + */ + mask = (num & (_MASK << (i * 8))); + if ((mask && !sign) || (sign && !mask)) + i++; + + len = i + 1; + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + + if ((lenlen = kmfber_put_len(ber, len, 0)) == -1) + return (-1); + i++; + netnum = htonl(num); + if (kmfber_write(ber, + (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i) + /* length of tag + length + contents */ + return (taglen + lenlen + i); + + return (-1); +} + +static int +kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) +{ + if (tag == KMFBER_DEFAULT) + tag = BER_ENUMERATED; + + return (ber_put_int_or_enum(ber, num, tag)); +} + +int +ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag) +{ + if (tag == KMFBER_DEFAULT) + tag = BER_INTEGER; + + return (ber_put_int_or_enum(ber, num, tag)); +} + +int +ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag) +{ + ber_int_t taglen, lenlen, rc, len; + + if (tag == KMFBER_DEFAULT) + tag = 0x06; /* TODO: Add new OID constant to header */ + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + + len = (ber_int_t)oid->bv_len; + if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 || + kmfber_write(ber, oid->bv_val, oid->bv_len, 0) != + (ber_int_t)oid->bv_len) { + rc = -1; + } else { + /* return length of tag + length + contents */ + rc = taglen + lenlen + oid->bv_len; + } + return (rc); +} + +int +ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data, + ber_len_t len) +{ + ber_int_t taglen, lenlen, ilen, rc; + + if (tag == KMFBER_DEFAULT) + tag = BER_INTEGER; + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + + ilen = (ber_int_t)len; + if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || + kmfber_write(ber, data, len, 0) != (ber_int_t)len) { + rc = -1; + } else { + /* return length of tag + length + contents */ + rc = taglen + lenlen + len; + } + return (rc); +} + +static int +kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len, + ber_tag_t tag) +{ + ber_int_t taglen, lenlen, ilen, rc; +#ifdef STR_TRANSLATION + int free_str; +#endif /* STR_TRANSLATION */ + + if (tag == KMFBER_DEFAULT) + tag = BER_OCTET_STRING; + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + +#ifdef STR_TRANSLATION + if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 && + ber->ber_encode_translate_proc != NULL) { + if ((*(ber->ber_encode_translate_proc))(&str, &len, 0) + != 0) { + return (-1); + } + free_str = 1; + } else { + free_str = 0; + } +#endif /* STR_TRANSLATION */ + + /* + * Note: below is a spot where we limit ber_write + * to signed long (instead of unsigned long) + */ + ilen = (ber_int_t)len; + if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || + kmfber_write(ber, str, len, 0) != (ber_int_t)len) { + rc = -1; + } else { + /* return length of tag + length + contents */ + rc = taglen + lenlen + len; + } + +#ifdef STR_TRANSLATION + if (free_str) { + free(str); + } +#endif /* STR_TRANSLATION */ + + return (rc); +} + +static int +kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag) +{ + return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag)); +} + +static int +kmfber_put_bitstring(BerElement *ber, char *str, + ber_len_t blen /* in bits */, ber_tag_t tag) +{ + ber_int_t taglen, lenlen, len; + unsigned char unusedbits; + + if (tag == KMFBER_DEFAULT) + tag = BER_BIT_STRING; + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + + len = (blen + 7) / 8; + unusedbits = (unsigned char) (len * 8 - blen); + if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1) + return (-1); + + if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1) + return (-1); + + if (kmfber_write(ber, str, len, 0) != len) + return (-1); + + /* return length of tag + length + unused bit count + contents */ + return (taglen + 1 + lenlen + len); +} + +static int +kmfber_put_null(BerElement *ber, ber_tag_t tag) +{ + int taglen; + + if (tag == KMFBER_DEFAULT) + tag = BER_NULL; + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + + if (kmfber_put_len(ber, 0, 0) != 1) + return (-1); + + return (taglen + 1); +} + +static int +kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag) +{ + int taglen; + unsigned char trueval = 0xff; + unsigned char falseval = 0x00; + + if (tag == KMFBER_DEFAULT) + tag = BER_BOOLEAN; + + if ((taglen = ber_put_tag(ber, tag, 0)) == -1) + return (-1); + + if (kmfber_put_len(ber, 1, 0) != 1) + return (-1); + + if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0) + != 1) + return (-1); + + return (taglen + 2); +} + +#define FOUR_BYTE_LEN 5 + + +/* + * The idea here is roughly this: we maintain a stack of these Seqorset + * structures. This is pushed when we see the beginning of a new set or + * sequence. It is popped when we see the end of a set or sequence. + * Since we don't want to malloc and free these structures all the time, + * we pre-allocate a small set of them within the ber element structure. + * thus we need to spot when we've overflowed this stack and fall back to + * malloc'ing instead. + */ +static int +ber_start_seqorset(BerElement *ber, ber_tag_t tag) +{ + Seqorset *new_sos; + + /* can we fit into the local stack ? */ + if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { + /* yes */ + new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; + } else { + /* no */ + if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset))) + == NULLSEQORSET) { + return (-1); + } + } + ber->ber_sos_stack_posn++; + + if (ber->ber_sos == NULLSEQORSET) + new_sos->sos_first = ber->ber_ptr; + else + new_sos->sos_first = ber->ber_sos->sos_ptr; + + /* Set aside room for a 4 byte length field */ + new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) + + FOUR_BYTE_LEN; + new_sos->sos_tag = tag; + + new_sos->sos_next = ber->ber_sos; + new_sos->sos_clen = 0; + + ber->ber_sos = new_sos; + if (ber->ber_sos->sos_ptr > ber->ber_end) { + (void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end); + } + return (0); +} + +static int +kmfber_start_seq(BerElement *ber, ber_tag_t tag) +{ + if (tag == KMFBER_DEFAULT) + tag = BER_CONSTRUCTED_SEQUENCE; + + return (ber_start_seqorset(ber, tag)); +} + +static int +kmfber_start_set(BerElement *ber, ber_tag_t tag) +{ + if (tag == KMFBER_DEFAULT) + tag = BER_CONSTRUCTED_SET; + + return (ber_start_seqorset(ber, tag)); +} + +static int +ber_put_seqorset(BerElement *ber) +{ + ber_int_t netlen, len, taglen, lenlen; + unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; + Seqorset *next; + Seqorset **sos = &ber->ber_sos; + + /* + * If this is the toplevel sequence or set, we need to actually + * write the stuff out. Otherwise, it's already been put in + * the appropriate buffer and will be written when the toplevel + * one is written. In this case all we need to do is update the + * length and tag. + */ + + len = (*sos)->sos_clen; + netlen = (ber_len_t)htonl(len); + + if (ber->ber_options & KMFBER_OPT_USE_DER) { + lenlen = kmfber_calc_lenlen(len); + } else { + lenlen = FOUR_BYTE_LEN; + } + + if ((next = (*sos)->sos_next) == NULLSEQORSET) { + /* write the tag */ + if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1) + return (-1); + + if (ber->ber_options & KMFBER_OPT_USE_DER) { + /* Write the length in the minimum # of octets */ + if (kmfber_put_len(ber, len, 1) == -1) + return (-1); + + if (lenlen != FOUR_BYTE_LEN) { + /* + * We set aside FOUR_BYTE_LEN bytes for + * the length field. Move the data if + * we don't actually need that much + */ + (void) memmove((*sos)->sos_first + taglen + + lenlen, (*sos)->sos_first + taglen + + FOUR_BYTE_LEN, len); + } + } else { + /* Fill FOUR_BYTE_LEN bytes for length field */ + /* one byte of length length */ + if (kmfber_write(ber, (char *)<ag, 1, 1) != 1) + return (-1); + + /* the length itself */ + if (kmfber_write(ber, + (char *)&netlen + sizeof (ber_int_t) + - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) != + FOUR_BYTE_LEN - 1) + return (-1); + } + /* The ber_ptr is at the set/seq start - move it to the end */ + ber->ber_ptr += len; + } else { + ber_tag_t ntag; + + /* the tag */ + taglen = kmfber_calc_taglen((*sos)->sos_tag); + ntag = htonl((*sos)->sos_tag); + (void) memmove((*sos)->sos_first, (char *)&ntag + + sizeof (ber_int_t) - taglen, taglen); + + if (ber->ber_options & KMFBER_OPT_USE_DER) { + ltag = (lenlen == 1) ? (unsigned char)len : + (unsigned char) (0x80 + (lenlen - 1)); + } + + /* one byte of length length */ + (void) memmove((*sos)->sos_first + 1, <ag, 1); + + if (ber->ber_options & KMFBER_OPT_USE_DER) { + if (lenlen > 1) { + /* Write the length itself */ + (void) memmove((*sos)->sos_first + 2, + (char *)&netlen + sizeof (ber_uint_t) - + (lenlen - 1), + lenlen - 1); + } + if (lenlen != FOUR_BYTE_LEN) { + /* + * We set aside FOUR_BYTE_LEN bytes for + * the length field. Move the data if + * we don't actually need that much + */ + (void) memmove((*sos)->sos_first + taglen + + lenlen, (*sos)->sos_first + taglen + + FOUR_BYTE_LEN, len); + } + } else { + /* the length itself */ + (void) memmove((*sos)->sos_first + taglen + 1, + (char *) &netlen + sizeof (ber_int_t) - + (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1); + } + + next->sos_clen += (taglen + lenlen + len); + next->sos_ptr += (taglen + lenlen + len); + } + + /* we're done with this seqorset, so free it up */ + /* was this one from the local stack ? */ + if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) { + free((char *)(*sos)); + } + ber->ber_sos_stack_posn--; + *sos = next; + + return (taglen + lenlen + len); +} + +/* VARARGS */ +int +kmfber_printf(BerElement *ber, const char *fmt, ...) +{ + va_list ap; + char *s, **ss; + struct berval **bv, *oid; + int rc, i, t; + ber_int_t len; + + va_start(ap, fmt); + +#ifdef KMFBER_DEBUG + if (lber_debug & 64) { + char msg[80]; + sprintf(msg, "kmfber_printf fmt (%s)\n", fmt); + ber_err_print(msg); + } +#endif + + for (rc = 0; *fmt && rc != -1; fmt++) { + switch (*fmt) { + case 'b': /* boolean */ + i = va_arg(ap, int); + rc = kmfber_put_boolean(ber, i, ber->ber_tag); + break; + + case 'i': /* int */ + i = va_arg(ap, int); + rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag); + break; + + case 'D': /* Object ID */ + if ((oid = va_arg(ap, struct berval *)) == NULL) + break; + rc = ber_put_oid(ber, oid, ber->ber_tag); + break; + case 'I': /* int */ + s = va_arg(ap, char *); + len = va_arg(ap, ber_int_t); + rc = ber_put_big_int(ber, ber->ber_tag, s, len); + break; + + case 'e': /* enumeration */ + i = va_arg(ap, int); + rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag); + break; + + case 'l': + t = va_arg(ap, int); + rc = kmfber_put_len(ber, t, 0); + break; + case 'n': /* null */ + rc = kmfber_put_null(ber, ber->ber_tag); + break; + + case 'o': /* octet string (non-null terminated) */ + s = va_arg(ap, char *); + len = va_arg(ap, int); + rc = kmfber_put_ostring(ber, s, len, ber->ber_tag); + break; + + case 's': /* string */ + s = va_arg(ap, char *); + rc = kmfber_put_string(ber, s, ber->ber_tag); + break; + + case 'B': /* bit string */ + s = va_arg(ap, char *); + len = va_arg(ap, int); /* in bits */ + rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag); + break; + + case 't': /* tag for the next element */ + ber->ber_tag = va_arg(ap, ber_tag_t); + ber->ber_usertag = 1; + break; + + case 'T': /* Write an explicit tag, but don't change current */ + t = va_arg(ap, int); + rc = ber_put_tag(ber, t, 0); + break; + + case 'v': /* vector of strings */ + if ((ss = va_arg(ap, char **)) == NULL) + break; + for (i = 0; ss[i] != NULL; i++) { + if ((rc = kmfber_put_string(ber, ss[i], + ber->ber_tag)) == -1) + break; + } + break; + + case 'V': /* sequences of strings + lengths */ + if ((bv = va_arg(ap, struct berval **)) == NULL) + break; + for (i = 0; bv[i] != NULL; i++) { + if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val, + bv[i]->bv_len, ber->ber_tag)) == -1) + break; + } + break; + + case '{': /* begin sequence */ + rc = kmfber_start_seq(ber, ber->ber_tag); + break; + + case '}': /* end sequence */ + rc = ber_put_seqorset(ber); + break; + + case '[': /* begin set */ + rc = kmfber_start_set(ber, ber->ber_tag); + break; + + case ']': /* end set */ + rc = ber_put_seqorset(ber); + break; + + default: { +#ifdef KMFBER_DEBUG + char msg[80]; + sprintf(msg, "unknown fmt %c\n", *fmt); + ber_err_print(msg); +#endif + rc = -1; + break; + } + } + + if (ber->ber_usertag == 0) + ber->ber_tag = KMFBER_DEFAULT; + else + ber->ber_usertag = 0; + } + + va_end(ap); + + return (rc); +} diff --git a/usr/src/lib/libkmf/ber_der/common/io.c b/usr/src/lib/libkmf/ber_der/common/io.c new file mode 100644 index 0000000000..415bbba9c4 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/common/io.c @@ -0,0 +1,419 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#include <stdlib.h> +#include <ber_der.h> +#include "kmfber_int.h" + +#define EXBUFSIZ 1024 + +/* + * Note: kmfber_read() only uses the ber_end and ber_ptr elements of ber. + * Functions like kmfber_get_tag(), kmfber_skip_tag, and kmfber_peek_tag() + * rely on that fact, so if this code is changed to use any additional + * elements of the ber structure, those functions will need to be changed + * as well. + */ +ber_int_t +kmfber_read(BerElement *ber, char *buf, ber_len_t len) +{ + size_t actuallen; + size_t nleft; + + nleft = ber->ber_end - ber->ber_ptr; + actuallen = nleft < len ? nleft : len; + + (void) memmove(buf, ber->ber_ptr, (size_t)actuallen); + + ber->ber_ptr += actuallen; + + return ((ber_int_t)actuallen); +} + +/* + * enlarge the ber buffer. + * return 0 on success, -1 on error. + */ +static int +kmfber_realloc(BerElement *ber, ber_len_t len) +{ + ber_uint_t need, have, total; + size_t have_bytes; + Seqorset *s; + size_t off; + char *oldbuf; + + have_bytes = ber->ber_end - ber->ber_buf; + have = have_bytes / EXBUFSIZ; + need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ); + total = have * EXBUFSIZ + need * EXBUFSIZ; + + oldbuf = ber->ber_buf; + + if (ber->ber_buf == NULL) { + if ((ber->ber_buf = (char *)malloc((size_t)total)) + == NULL) { + return (-1); + } + ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER; + } else { + if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) { + /* transition to malloc'd buffer */ + if ((ber->ber_buf = (char *)malloc( + (size_t)total)) == NULL) { + return (-1); + } + ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER; + /* copy existing data into new malloc'd buffer */ + (void) memmove(ber->ber_buf, oldbuf, have_bytes); + } else { + if ((ber->ber_buf = (char *)realloc( + ber->ber_buf, (size_t)total)) == NULL) { + return (-1); + } + } + } + + ber->ber_end = ber->ber_buf + total; + + /* + * If the stinking thing was moved, we need to go through and + * reset all the sos and ber pointers. Offsets would've been + * a better idea... oh well. + */ + + if (ber->ber_buf != oldbuf) { + ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf); + + for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) { + off = s->sos_first - oldbuf; + s->sos_first = ber->ber_buf + off; + + off = s->sos_ptr - oldbuf; + s->sos_ptr = ber->ber_buf + off; + } + } + + return (0); +} + +/* + * returns "len" on success and -1 on failure. + */ +ber_int_t +kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos) +{ + if (nosos || ber->ber_sos == NULL) { + if (ber->ber_ptr + len > ber->ber_end) { + if (kmfber_realloc(ber, len) != 0) + return (-1); + } + (void) memmove(ber->ber_ptr, buf, (size_t)len); + ber->ber_ptr += len; + return (len); + } else { + if (ber->ber_sos->sos_ptr + len > ber->ber_end) { + if (kmfber_realloc(ber, len) != 0) + return (-1); + } + (void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len); + ber->ber_sos->sos_ptr += len; + ber->ber_sos->sos_clen += len; + return (len); + } +} + +void +kmfber_free(BerElement *ber, int freebuf) +{ + if (ber != NULL) { + if (freebuf && + !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER)) { + free(ber->ber_buf); + } + free((char *)ber); + } +} + +/* we pre-allocate a buffer to save the extra malloc later */ +BerElement * +kmfber_alloc_t(int options) +{ + BerElement *ber; + + if ((ber = (BerElement*)calloc(1, + sizeof (struct berelement) + EXBUFSIZ)) == NULL) { + return (NULL); + } + + ber->ber_tag = KMFBER_DEFAULT; + ber->ber_options = options; + ber->ber_buf = (char *)ber + sizeof (struct berelement); + ber->ber_ptr = ber->ber_buf; + ber->ber_end = ber->ber_buf + EXBUFSIZ; + ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER; + + return (ber); +} + + +BerElement * +kmfber_alloc() +{ + return (kmfber_alloc_t(0)); +} + +BerElement * +kmfder_alloc() +{ + return (kmfber_alloc_t(KMFBER_OPT_USE_DER)); +} + +BerElement * +kmfber_dup(BerElement *ber) +{ + BerElement *new; + + if ((new = kmfber_alloc()) == NULL) + return (NULL); + + *new = *ber; + + return (new); +} + + +void +ber_init_w_nullchar(BerElement *ber, int options) +{ + (void) memset((char *)ber, '\0', sizeof (struct berelement)); + ber->ber_tag = KMFBER_DEFAULT; + + ber->ber_options = options; +} + + +void +kmfber_reset(BerElement *ber, int was_writing) +{ + if (was_writing) { + ber->ber_end = ber->ber_ptr; + ber->ber_ptr = ber->ber_buf; + } else { + ber->ber_ptr = ber->ber_end; + } + + ber->ber_rwptr = NULL; +} + + +#ifdef KMFBER_DEBUG + +void +ber_dump(BerElement *ber, int inout) +{ + char msg[128]; + sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n", + ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end); + ber_err_print(msg); + if (inout == 1) { + sprintf(msg, " current len %ld, contents:\n", + ber->ber_end - ber->ber_ptr); + ber_err_print(msg); + lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr); + } else { + sprintf(msg, " current len %ld, contents:\n", + ber->ber_ptr - ber->ber_buf); + ber_err_print(msg); + lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf); + } +} + +void +ber_sos_dump(Seqorset *sos) +{ + char msg[80]; + ber_err_print("*** sos dump ***\n"); + while (sos != NULLSEQORSET) { + sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n", + sos->sos_clen, sos->sos_first, sos->sos_ptr); + ber_err_print(msg); + sprintf(msg, " current len %ld contents:\n", + sos->sos_ptr - sos->sos_first); + ber_err_print(msg); + lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first); + + sos = sos->sos_next; + } + ber_err_print("*** end dump ***\n"); +} + +#endif + +/* new dboreham code below: */ +struct byte_buffer { + unsigned char *p; + int offset; + int length; +}; +typedef struct byte_buffer byte_buffer; + +/* + * The kmfber_flatten routine allocates a struct berval whose contents + * are a BER encoding taken from the ber argument. The bvPtr pointer + * points to the returned berval, which must be freed using + * kmfber_bvfree(). This routine returns 0 on success and -1 on error. + * The use of kmfber_flatten on a BerElement in which all '{' and '}' + * format modifiers have not been properly matched can result in a + * berval whose contents are not a valid BER encoding. + * Note that the ber_ptr is not modified. + */ +int +kmfber_flatten(BerElement *ber, struct berval **bvPtr) +{ + struct berval *new; + ber_len_t len; + + /* allocate a struct berval */ + new = (struct berval *)malloc((size_t)(sizeof (struct berval))); + if (new == NULL) { + return (-1); + } + (void) memset(new, 0, sizeof (struct berval)); + + /* + * Copy everything from the BerElement's ber_buf to ber_ptr + * into the berval structure. + */ + if (ber == NULL) { + new->bv_val = NULL; + new->bv_len = 0; + } else { + len = ber->ber_ptr - ber->ber_buf; + new->bv_val = (char *)malloc((size_t)(len + 1)); + if (new->bv_val == NULL) { + kmfber_bvfree(new); + return (-1); + } + (void) memmove(new->bv_val, ber->ber_buf, (size_t)len); + new->bv_val[len] = '\0'; + new->bv_len = len; + } + + /* set bvPtr pointer to point to the returned berval */ + *bvPtr = new; + + return (0); +} + +BerElement * +kmfder_init(const struct berval *bv) +{ + BerElement *ber; + + /* construct BerElement */ + if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) { + /* copy data from the bv argument into BerElement */ + /* XXXmcs: had to cast unsigned long bv_len to long */ + if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) != + (ber_slen_t)bv->bv_len) { + kmfber_free(ber, 1); + return (NULL); + } + } + /* + * reset ber_ptr back to the beginning of buffer so that this new + * and initialized ber element can be READ + */ + kmfber_reset(ber, 1); + + /* + * return a ptr to a new BerElement containing a copy of the data + * in the bv argument or a null pointer on error + */ + return (ber); +} + +BerElement * +kmfber_init(const struct berval *bv) +{ + BerElement *ber; + + /* construct BerElement */ + if ((ber = kmfber_alloc_t(0)) != NULL) { + /* copy data from the bv argument into BerElement */ + /* XXXmcs: had to cast unsigned long bv_len to long */ + if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) != + (ber_slen_t)bv->bv_len) { + kmfber_free(ber, 1); + return (NULL); + } + } + /* + * reset ber_ptr back to the beginning of buffer so that this new + * and initialized ber element can be READ + */ + kmfber_reset(ber, 1); + + /* + * return a ptr to a new BerElement containing a copy of the data + * in the bv argument or a null pointer on error + */ + return (ber); +} diff --git a/usr/src/cmd/cmd-crypto/pktool/p12common.h b/usr/src/lib/libkmf/ber_der/common/llib-lkmfberder index 03a2a6ae5e..44d4dec3b5 100644 --- a/usr/src/cmd/cmd-crypto/pktool/p12common.h +++ b/usr/src/lib/libkmf/ber_der/common/llib-lkmfberder @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,27 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _PKTOOL_P12COMMON_H -#define _PKTOOL_P12COMMON_H - #pragma ident "%Z%%M% %I% %E% SMI" -#ifdef __cplusplus -extern "C" { -#endif - -#include <openssl/bio.h> - -extern int create_pkcs12(char *filename, BIO **fbio); -extern int open_pkcs12(char *filename, BIO **fbio); -extern void close_pkcs12(BIO *fbio); - -#ifdef __cplusplus -} -#endif +/* LINTLIBRARY */ +/* PROTOLIB1 */ -#endif /* _PKTOOL_P12COMMON_H */ +#include <ber_der.h> diff --git a/usr/src/lib/libkmf/ber_der/common/mapfile-vers b/usr/src/lib/libkmf/ber_der/common/mapfile-vers new file mode 100644 index 0000000000..bb8ee5b20e --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/common/mapfile-vers @@ -0,0 +1,67 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + AddRDN; + CopyRDN; + CopySPKI; + DerDecodeDSASignature; + DerDecodeExtension; + DerDecodeName; + DerDecodeSPKI; + DerDecodeSignedCertificate; + DerDecodeSignedCsr; + DerDecodeTbsCertificate; + DerDecodeTbsCsr; + DerEncodeDSAPrivateKey; + DerEncodeDSASignature; + DerEncodeName; + DerEncodeRSAPrivateKey; + DerEncodeSPKI; + DerEncodeSignedCertificate; + DerEncodeSignedCsr; + DerEncodeTbsCertificate; + DerEncodeTbsCsr; + ExtractSPKIData; + ExtractX509CertParts; + GetKeyFromSpki; + kmfber_alloc; + kmfber_first_element; + kmfber_flatten; + kmfber_free; + kmfber_init; + kmfber_next_element; + kmfber_printf; + kmfber_read; + kmfber_scanf; + kmfber_write; + kmfder_alloc; + kmfder_init; + local: + *; +}; diff --git a/usr/src/lib/libkmf/ber_der/i386/Makefile b/usr/src/lib/libkmf/ber_der/i386/Makefile new file mode 100644 index 0000000000..bda92e4278 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/libkmf/ber_der/inc/ber_der.h b/usr/src/lib/libkmf/ber_der/inc/ber_der.h new file mode 100644 index 0000000000..12bd743179 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/inc/ber_der.h @@ -0,0 +1,180 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * File: BER_DER.H + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + * + * Portions: + * (C) COPYRIGHT International Business Machines Corp. 1996, 1997 + * All Rights Reserved + * + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + */ + +/* + * This is the header file for some Basic Encoding Rules and Distinguished + * Encoding Rules (BER/DER) routines. + */ + +#ifndef BER_DER_H +#define BER_DER_H + +#include <kmfapi.h> + +#define BER_BOOLEAN 1 +#define BER_INTEGER 2 +#define BER_BIT_STRING 3 +#define BER_OCTET_STRING 4 +#define BER_NULL 5 +#define BER_OBJECT_IDENTIFIER 6 +#define BER_ENUMERATED 10 +#define BER_UTF8_STRING 12 +#define BER_SEQUENCE 16 +#define BER_SET 17 +#define BER_PRINTABLE_STRING 19 +#define BER_T61STRING 20 +#define BER_IA5STRING 22 +#define BER_UTCTIME 23 +#define BER_GENTIME 24 +#define BER_UNIVERSAL_STRING 28 +#define BER_BMP_STRING 30 + +#define BER_CLASS_MASK 0xc0 +#define BER_CLASS_UNIVERSAL 0x00 +#define BER_CLASS_APPLICATION 0x40 +#define BER_CLASS_CONTEXTSPECIFIC 0x80 +#define BER_CLASS_PRIVATE 0xc0 +#define BER_CONSTRUCTED 0x20 +#define BER_CONSTRUCTED_SEQUENCE (BER_CONSTRUCTED | BER_SEQUENCE) +#define BER_CONSTRUCTED_SET (BER_CONSTRUCTED | BER_SET) + +#define KMFBER_BIG_TAG_MASK 0x1f +#define KMFBER_MORE_TAG_MASK 0x80 + +#define KMFBER_DEFAULT 0xFFFFFFFF +#define KMFBER_ERROR 0xFFFFFFFF +#define KMFBER_END_OF_SEQORSET 0xfffffffe + +/* BerElement set/get options */ +#define KMFBER_OPT_REMAINING_BYTES 0x01 +#define KMFBER_OPT_TOTAL_BYTES 0x02 +#define KMFBER_OPT_USE_DER 0x04 +#define KMFBER_OPT_TRANSLATE_STRINGS 0x08 +#define KMFBER_OPT_BYTES_TO_WRITE 0x10 +#define KMFBER_OPT_DEBUG_LEVEL 0x40 + +typedef size_t ber_len_t; /* for BER len */ +typedef long ber_slen_t; /* signed equivalent of ber_len_t */ +typedef int32_t ber_tag_t; /* for BER tags */ +typedef int32_t ber_int_t; /* for BER ints, enums, and Booleans */ +typedef uint32_t ber_uint_t; /* unsigned equivalent of ber_int_t */ + +typedef struct berelement BerElement; +typedef int (*BERTranslateProc)(char **, ber_uint_t *, int); + +typedef struct berval { + ber_len_t bv_len; + char *bv_val; +} BerValue; + +#define SAFEMEMCPY(d, s, n) memmove(d, s, n) + +BerElement *kmfder_init(const struct berval *bv); +BerElement *kmfber_init(const struct berval *bv); +int kmfber_calc_taglen(ber_tag_t); +int kmfber_calc_lenlen(ber_int_t); +int kmfber_put_len(BerElement *, ber_int_t, int); + +/* + * public decode routines + */ +ber_tag_t kmfber_first_element(BerElement *, ber_len_t *, char **); +ber_tag_t kmfber_next_element(BerElement *, ber_len_t *, char *); +ber_tag_t kmfber_scanf(BerElement *, const char *, ...); + +void kmfber_bvfree(struct berval *); +void kmfber_bvecfree(struct berval **); +struct berval *kmfber_bvdup(const struct berval *); + +/* + * public encoding routines + */ +extern int kmfber_printf(BerElement *, const char *, ...); +extern int kmfber_flatten(BerElement *, struct berval **); + +/* + * miscellaneous public routines + */ +extern void kmfber_free(BerElement *ber, int freebuf); +extern BerElement* kmfber_alloc(void); +extern BerElement* kmfder_alloc(void); +extern BerElement* kmfber_alloc_t(int); +extern BerElement* kmfber_dup(BerElement *); +extern ber_int_t kmfber_read(BerElement *, char *, ber_len_t); +extern ber_int_t kmfber_write(BerElement *, char *, ber_len_t, int); +extern void kmfber_reset(BerElement *, int); + +/* Routines KMF uses to encode/decode Cert objects */ +extern KMF_RETURN DerDecodeSignedCertificate(const KMF_DATA *, + KMF_X509_CERTIFICATE **); +extern KMF_RETURN DerEncodeSignedCertificate(KMF_X509_CERTIFICATE *, + KMF_DATA *); + +KMF_RETURN DerDecodeTbsCertificate(const KMF_DATA *, + KMF_X509_TBS_CERT **); +KMF_RETURN DerEncodeTbsCertificate(KMF_X509_TBS_CERT *, KMF_DATA *); + +KMF_RETURN DerDecodeSignedCsr(const KMF_DATA *, KMF_CSR_DATA **); +extern KMF_RETURN DerEncodeSignedCsr(KMF_CSR_DATA *, KMF_DATA *); +extern KMF_RETURN DerDecodeTbsCsr(const KMF_DATA *, KMF_TBS_CSR **); +extern KMF_RETURN DerEncodeTbsCsr(KMF_TBS_CSR *, KMF_DATA *); + +KMF_RETURN ExtractX509CertParts(KMF_DATA *, KMF_DATA *, KMF_DATA *); +KMF_RETURN GetKeyFromSpki(KMF_ALGORITHM_INDEX, KMF_X509_SPKI *, + KMF_DATA **); +extern KMF_RETURN DerEncodeName(KMF_X509_NAME *, KMF_DATA *); +KMF_RETURN DerDecodeName(KMF_DATA *, KMF_X509_NAME *); +KMF_RETURN DerDecodeExtension(KMF_DATA *, KMF_X509_EXTENSION **); +KMF_RETURN CopyRDN(KMF_X509_NAME *, KMF_X509_NAME **); +KMF_RETURN CopySPKI(KMF_X509_SPKI *, + KMF_X509_SPKI **); +extern KMF_RETURN DerDecodeSPKI(KMF_DATA *, KMF_X509_SPKI *); +extern KMF_RETURN DerDecodeDSASignature(KMF_DATA *, KMF_DATA *); +extern KMF_RETURN DerEncodeDSASignature(KMF_DATA *, KMF_DATA *); +KMF_RETURN DerEncodeAlgoid(KMF_DATA *, KMF_DATA *); +KMF_RETURN DerDecodeSPKI(KMF_DATA *, KMF_X509_SPKI *); +KMF_RETURN DerEncodeSPKI(KMF_X509_SPKI *, KMF_DATA *); +extern KMF_RETURN ExtractSPKIData(const KMF_X509_SPKI *, + KMF_ALGORITHM_INDEX, KMF_DATA *, uint32_t *); +extern KMF_RETURN AddRDN(KMF_X509_NAME *, KMF_X509_RDN *); +KMF_RETURN DerEncodeRSAPrivateKey(KMF_DATA *, KMF_RAW_RSA_KEY *); +KMF_RETURN DerEncodeDSAPrivateKey(KMF_DATA *, KMF_RAW_DSA_KEY *); + +#endif /* BER_DER_H */ diff --git a/usr/src/lib/libkmf/ber_der/inc/kmfber_int.h b/usr/src/lib/libkmf/ber_der/inc/kmfber_int.h new file mode 100644 index 0000000000..735452e433 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/inc/kmfber_int.h @@ -0,0 +1,128 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998-1999 Netscape Communications Corporation. All + * Rights Reserved. + */ + +/* + * Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + + +#ifndef _KMFBER_INT_H +#define _KMFBER_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> + +#include <malloc.h> +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> + +#include <memory.h> +#include <string.h> + +typedef struct seqorset { + ber_len_t sos_clen; + ber_tag_t sos_tag; + char *sos_first; + char *sos_ptr; + struct seqorset *sos_next; +} Seqorset; +#define NULLSEQORSET ((Seqorset *) 0) + +#define SOS_STACK_SIZE 8 /* depth of the pre-allocated sos structure stack */ + +struct berelement { + char *ber_buf; + char *ber_ptr; + char *ber_end; + struct seqorset *ber_sos; + ber_tag_t ber_tag; + ber_len_t ber_len; + int ber_usertag; + char ber_options; + char *ber_rwptr; + BERTranslateProc ber_encode_translate_proc; + BERTranslateProc ber_decode_translate_proc; + int ber_flags; +#define KMFBER_FLAG_NO_FREE_BUFFER 1 /* don't free ber_buf */ + int ber_sos_stack_posn; + Seqorset ber_sos_stack[SOS_STACK_SIZE]; +}; + +/* function prototypes */ +void ber_err_print(char *data); + +#define THEMEMCPY(d, s, n) memmove(d, s, n) + +#ifdef SAFEMEMCPY +#undef SAFEMEMCPY +#define SAFEMEMCPY(d, s, n) memmove(d, s, n); +#endif + +/* allow the library to access the debug variable */ + +#ifdef KMFBER_DEBUG +extern int kmfber_debug; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* _KMFBER_INT_H */ diff --git a/usr/src/lib/libkmf/ber_der/sparc/Makefile b/usr/src/lib/libkmf/ber_der/sparc/Makefile new file mode 100644 index 0000000000..6dd6b42169 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/libkmf/ber_der/sparcv9/Makefile b/usr/src/lib/libkmf/ber_der/sparcv9/Makefile new file mode 100644 index 0000000000..3dfc6b7784 --- /dev/null +++ b/usr/src/lib/libkmf/ber_der/sparcv9/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libkmf/include/algorithm.h b/usr/src/lib/libkmf/include/algorithm.h new file mode 100644 index 0000000000..5353e4e8bc --- /dev/null +++ b/usr/src/lib/libkmf/include/algorithm.h @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * + * File: ALGORITHM.H + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#ifndef _ALGORITHM_H +#define _ALGORITHM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmftypes.h> +#include <security/cryptoki.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkcs_algorithm_map +{ + CK_MECHANISM_TYPE pkcs_mechanism; + uint32_t algorithm; + uint32_t context_type; + uint32_t enc_mode; + CK_BBOOL bMultiPart; + CK_BBOOL fix_keylength; + uint32_t keylength; + CK_BBOOL fix_blocksize; + uint32_t block_size; + CK_BBOOL requires_iv; + uint32_t iv_length; + CK_FLAGS required_flags; + CK_KEY_TYPE key_type; + char *szDescription; +} PKCS_ALGORITHM_MAP; + +extern KMF_SIGNATURE_MODE PKCS_GetDefaultSignatureMode(KMF_ALGORITHM_INDEX); +extern PKCS_ALGORITHM_MAP* PKCS_GetAlgorithmMap(KMF_ALGCLASS, uint32_t, + uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _ALGORITHM_H */ diff --git a/usr/src/lib/libkmf/include/kmfapi.h b/usr/src/lib/libkmf/include/kmfapi.h new file mode 100644 index 0000000000..64ded2ce6a --- /dev/null +++ b/usr/src/lib/libkmf/include/kmfapi.h @@ -0,0 +1,346 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * + * Constant definitions and function prototypes for the KMF library. + * Commonly used data types are defined in "kmftypes.h". + */ + +#ifndef _KMFAPI_H +#define _KMFAPI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmftypes.h> +#include <security/cryptoki.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Setup operations. + */ +extern KMF_RETURN KMF_Initialize(KMF_HANDLE_T *, char *, char *); +extern KMF_RETURN KMF_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *); +extern KMF_RETURN KMF_Finalize(KMF_HANDLE_T); + +/* + * Key operations. + */ +extern KMF_RETURN KMF_SignDataWithKey(KMF_HANDLE_T, + KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +extern KMF_RETURN KMF_VerifyDataWithKey(KMF_HANDLE_T, + KMF_KEY_HANDLE *, KMF_ALGORITHM_INDEX, KMF_DATA *, KMF_DATA *); + +extern KMF_RETURN KMF_CreateKeypair(KMF_HANDLE_T, + KMF_CREATEKEYPAIR_PARAMS *, KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +extern KMF_RETURN KMF_DeleteKeyFromKeystore(KMF_HANDLE_T, + KMF_DELETEKEY_PARAMS *, KMF_KEY_HANDLE *); + +extern KMF_RETURN KMF_SignCertRecord(KMF_HANDLE_T, KMF_KEY_HANDLE *, + KMF_X509_CERTIFICATE *, KMF_DATA *); + +extern KMF_RETURN KMF_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +extern KMF_RETURN KMF_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, + KMF_RAW_KEY_DATA *); + +extern KMF_RETURN KMF_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, + KMF_KEY_HANDLE *); + +extern KMF_RETURN KMF_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, + KMF_RAW_SYM_KEY *); + +/* + * Certificate operations. + */ +extern KMF_RETURN KMF_FindCert(KMF_HANDLE_T, KMF_FINDCERT_PARAMS *, + KMF_X509_DER_CERT *, uint32_t *); + +extern KMF_RETURN KMF_EncodeCertRecord(KMF_X509_CERTIFICATE *, + KMF_DATA *); +extern KMF_RETURN KMF_SignCertWithKey(KMF_HANDLE_T, const KMF_DATA *, + KMF_KEY_HANDLE *, KMF_DATA *); +extern KMF_RETURN KMF_SignCertWithCert(KMF_HANDLE_T, + KMF_CRYPTOWITHCERT_PARAMS *, + const KMF_DATA *, KMF_DATA *, KMF_DATA *); + +extern KMF_RETURN KMF_SignDataWithCert(KMF_HANDLE_T, + KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, KMF_DATA *, KMF_DATA *); + +extern KMF_RETURN KMF_VerifyCertWithKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, + const KMF_DATA *); +extern KMF_RETURN KMF_VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *, + const KMF_DATA *); +extern KMF_RETURN KMF_VerifyDataWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, + const KMF_DATA *); + +extern KMF_RETURN KMF_EncryptWithCert(KMF_HANDLE_T, KMF_DATA *, + KMF_DATA *, KMF_DATA *); + +extern KMF_RETURN KMF_DecryptWithCert(KMF_HANDLE_T, + KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, KMF_DATA *, KMF_DATA *); + +extern KMF_RETURN KMF_StoreCert(KMF_HANDLE_T, + KMF_STORECERT_PARAMS *, KMF_DATA *); +extern KMF_RETURN KMF_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *); +extern KMF_RETURN KMF_DeleteCertFromKeystore(KMF_HANDLE_T, + KMF_DELETECERT_PARAMS *); + +extern KMF_RETURN KMF_ValidateCert(KMF_HANDLE_T, + KMF_VALIDATECERT_PARAMS *, int *); + +extern KMF_RETURN KMF_CreateCertFile(KMF_DATA *, KMF_ENCODE_FORMAT, char *); + +extern KMF_RETURN KMF_DownloadCert(KMF_HANDLE_T, char *, char *, int, + unsigned int, char *, KMF_ENCODE_FORMAT *); +extern KMF_RETURN KMF_IsCertFile(KMF_HANDLE_T, char *, KMF_ENCODE_FORMAT *); + +extern KMF_RETURN KMF_CheckCertDate(KMF_HANDLE_T, KMF_DATA *); + +/* + * CRL operations. + */ +extern KMF_RETURN KMF_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *); +extern KMF_RETURN KMF_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *); +extern KMF_RETURN KMF_ListCRL(KMF_HANDLE_T, KMF_LISTCRL_PARAMS *, char **); +extern KMF_RETURN KMF_FindCRL(KMF_HANDLE_T, KMF_FINDCRL_PARAMS *, + char **, int *); + +extern KMF_RETURN KMF_FindCertInCRL(KMF_HANDLE_T, + KMF_FINDCERTINCRL_PARAMS *); +extern KMF_RETURN KMF_VerifyCRLFile(KMF_HANDLE_T, + KMF_VERIFYCRL_PARAMS *); + +extern KMF_RETURN KMF_CheckCRLDate(KMF_HANDLE_T, + KMF_CHECKCRLDATE_PARAMS *); +extern KMF_RETURN KMF_DownloadCRL(KMF_HANDLE_T, char *, char *, + int, unsigned int, char *, KMF_ENCODE_FORMAT *); +extern KMF_RETURN KMF_IsCRLFile(KMF_HANDLE_T, char *, KMF_ENCODE_FORMAT *); + +/* + * CSR operations. + */ +extern KMF_RETURN KMF_SetCSRPubKey(KMF_HANDLE_T, + KMF_KEY_HANDLE *, KMF_CSR_DATA *); +extern KMF_RETURN KMF_SetCSRVersion(KMF_CSR_DATA *, uint32_t); +extern KMF_RETURN KMF_SetCSRSubjectName(KMF_CSR_DATA *, KMF_X509_NAME *); +extern KMF_RETURN KMF_CreateCSRFile(KMF_DATA *, KMF_ENCODE_FORMAT, char *); +extern KMF_RETURN KMF_SetCSRExtension(KMF_CSR_DATA *, KMF_X509_EXTENSION *); +extern KMF_RETURN KMF_SetCSRSignatureAlgorithm(KMF_CSR_DATA *, + KMF_ALGORITHM_INDEX); +extern KMF_RETURN KMF_SetCSRSubjectAltName(KMF_CSR_DATA *, char *, + int, KMF_GENERALNAMECHOICES); +extern KMF_RETURN KMF_SetCSRKeyUsage(KMF_CSR_DATA *, int, uint16_t); +extern KMF_RETURN KMF_SignCSR(KMF_HANDLE_T, const KMF_CSR_DATA *, + KMF_KEY_HANDLE *, KMF_DATA *); + +/* + * GetCert operations. + */ +extern KMF_RETURN KMF_GetCertExtensionData(const KMF_DATA *, KMF_OID *, + KMF_X509_EXTENSION *); + +extern KMF_RETURN KMF_GetCertCriticalExtensions(const KMF_DATA *, + KMF_X509_EXTENSION **, int *); + +extern KMF_RETURN KMF_GetCertNonCriticalExtensions(const KMF_DATA *, + KMF_X509_EXTENSION **, int *); + +extern KMF_RETURN KMF_GetCertKeyUsageExt(const KMF_DATA *, + KMF_X509EXT_KEY_USAGE *); + +extern KMF_RETURN KMF_GetCertEKU(const KMF_DATA *, KMF_X509EXT_EKU *); + +extern KMF_RETURN KMF_GetCertBasicConstraintExt(const KMF_DATA *, + KMF_BOOL *, KMF_X509EXT_BASICCONSTRAINTS *); + +extern KMF_RETURN KMF_GetCertPoliciesExt(const KMF_DATA *, + KMF_BOOL *, KMF_X509EXT_CERT_POLICIES *); + +extern KMF_RETURN KMF_GetCertAuthInfoAccessExt(const KMF_DATA *, + KMF_X509EXT_AUTHINFOACCESS *); + +extern KMF_RETURN KMF_GetCertCRLDistributionPointsExt(const KMF_DATA *, + KMF_X509EXT_CRLDISTPOINTS *); + +extern KMF_RETURN KMF_GetCertVersionString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertSubjectNameString(KMF_HANDLE_T, const KMF_DATA *, + char **); + +extern KMF_RETURN KMF_GetCertIssuerNameString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertSerialNumberString(KMF_HANDLE_T, const KMF_DATA *, + char **); + +extern KMF_RETURN KMF_GetCertStartDateString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertEndDateString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertPubKeyAlgString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertSignatureAlgString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertPubKeyDataString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertEmailString(KMF_HANDLE_T, + const KMF_DATA *, char **); + +extern KMF_RETURN KMF_GetCertExtensionString(KMF_HANDLE_T, const KMF_DATA *, + KMF_PRINTABLE_ITEM, char **); + +extern KMF_RETURN KMF_GetCertIDData(const KMF_DATA *, KMF_DATA *); +extern KMF_RETURN KMF_GetCertIDString(const KMF_DATA *, char **); +extern KMF_RETURN KMF_GetCertValidity(const KMF_DATA *, time_t *, time_t *); + +/* + * SetCert operations + */ +extern KMF_RETURN KMF_SetCertPubKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, + KMF_X509_CERTIFICATE *); + +extern KMF_RETURN KMF_SetCertSubjectName(KMF_X509_CERTIFICATE *, + KMF_X509_NAME *); + +extern KMF_RETURN KMF_SetCertKeyUsage(KMF_X509_CERTIFICATE *, int, uint16_t); + +extern KMF_RETURN KMF_SetCertIssuerName(KMF_X509_CERTIFICATE *, + KMF_X509_NAME *); + +extern KMF_RETURN KMF_SetCertSignatureAlgorithm(KMF_X509_CERTIFICATE *, + KMF_ALGORITHM_INDEX); + +extern KMF_RETURN KMF_SetCertValidityTimes(KMF_X509_CERTIFICATE *, + time_t, uint32_t); + +extern KMF_RETURN KMF_SetCertSerialNumber(KMF_X509_CERTIFICATE *, + KMF_BIGINT *); + +extern KMF_RETURN KMF_SetCertVersion(KMF_X509_CERTIFICATE *, uint32_t); + +extern KMF_RETURN KMF_SetCertIssuerAltName(KMF_X509_CERTIFICATE *, + int, KMF_GENERALNAMECHOICES, char *); + +extern KMF_RETURN KMF_SetCertSubjectAltName(KMF_X509_CERTIFICATE *, + int, KMF_GENERALNAMECHOICES, char *); + +extern KMF_RETURN KMF_AddCertEKU(KMF_X509_CERTIFICATE *, KMF_OID *, int); + +extern KMF_RETURN KMF_SetCertExtension(KMF_X509_CERTIFICATE *, + KMF_X509_EXTENSION *); + +extern KMF_RETURN KMF_SetCertBasicConstraintExt(KMF_X509_CERTIFICATE *, + KMF_BOOL, KMF_X509EXT_BASICCONSTRAINTS *); + +extern KMF_RETURN KMF_ExportPK12(KMF_HANDLE_T, KMF_EXPORTP12_PARAMS *, char *); +extern KMF_RETURN KMF_ImportPK12(KMF_HANDLE_T, char *, KMF_CREDENTIAL *, + KMF_DATA **, int *, KMF_RAW_KEY_DATA **, int *); + +/* + * Get OCSP response operation. + */ +extern KMF_RETURN KMF_GetOCSPForCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, + KMF_DATA *); + +extern KMF_RETURN KMF_CreateOCSPRequest(KMF_HANDLE_T, KMF_OCSPREQUEST_PARAMS *, + char *); + +extern KMF_RETURN KMF_GetEncodedOCSPResponse(KMF_HANDLE_T, char *, char *, int, + char *, int, char *, unsigned int); + +extern KMF_RETURN KMF_GetOCSPStatusForCert(KMF_HANDLE_T, + KMF_OCSPRESPONSE_PARAMS_INPUT *, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *); + +/* + * Policy Operations + */ +extern KMF_RETURN KMF_SetPolicy(KMF_HANDLE_T, char *, char *); + +/* + * Error handling. + */ +extern KMF_RETURN KMF_GetPluginErrorString(KMF_HANDLE_T, char **); +extern KMF_RETURN KMF_GetKMFErrorString(KMF_RETURN, char **); + +/* + * Miscellaneous + */ +extern KMF_RETURN KMF_DNParser(char *, KMF_X509_NAME *); +extern KMF_RETURN KMF_DN2Der(KMF_X509_NAME *, KMF_DATA *); +extern KMF_RETURN KMF_ReadInputFile(KMF_HANDLE_T, char *, KMF_DATA *); +extern KMF_RETURN KMF_Der2Pem(KMF_OBJECT_TYPE, unsigned char *, + int, unsigned char **, int *); +extern KMF_RETURN KMF_Pem2Der(unsigned char *, int, unsigned char **, int *); +extern char *KMF_OID2String(KMF_OID *); +extern KMF_RETURN KMF_String2OID(char *, KMF_OID *); +extern int KMF_CompareRDNs(KMF_X509_NAME *, KMF_X509_NAME *); +extern KMF_RETURN KMF_GetFileFormat(char *, KMF_ENCODE_FORMAT *); +extern uint16_t KMF_StringToKeyUsage(char *); +extern KMF_RETURN KMF_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, + KMF_CREDENTIAL *); +extern KMF_RETURN KMF_HexString2Bytes(unsigned char *, unsigned char **, + size_t *); + +/* + * Memory cleanup operations + */ +extern void KMF_FreeDN(KMF_X509_NAME *); +extern void KMF_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *); +extern void KMF_FreeData(KMF_DATA *); +extern void KMF_FreeAlgOID(KMF_X509_ALGORITHM_IDENTIFIER *); +extern void KMF_FreeExtension(KMF_X509_EXTENSION *); +extern void KMF_FreeTBSCSR(KMF_TBS_CSR *); +extern void KMF_FreeSignedCSR(KMF_CSR_DATA *); +extern void KMF_FreeTBSCert(KMF_X509_TBS_CERT *); +extern void KMF_FreeSignedCert(KMF_X509_CERTIFICATE *); +extern void KMF_FreeString(char *); +extern void KMF_FreeEKU(KMF_X509EXT_EKU *); +extern void KMF_FreeSPKI(KMF_X509_SPKI *); +extern void KMF_FreeKMFKey(KMF_HANDLE_T, KMF_KEY_HANDLE *); +extern void KMF_FreeBigint(KMF_BIGINT *); +extern void KMF_FreeRawKey(KMF_RAW_KEY_DATA *); +extern void KMF_FreeRawSymKey(KMF_RAW_SYM_KEY *); +extern void KMF_FreeCRLDistributionPoints(KMF_X509EXT_CRLDISTPOINTS *); + +/* APIs for PKCS#11 token */ +extern KMF_RETURN KMF_PK11TokenLookup(KMF_HANDLE_T, char *, CK_SLOT_ID *); + +#ifdef __cplusplus +} +#endif +#endif /* _KMFAPI_H */ diff --git a/usr/src/lib/libkmf/include/kmfapiP.h b/usr/src/lib/libkmf/include/kmfapiP.h new file mode 100644 index 0000000000..64b524b6a7 --- /dev/null +++ b/usr/src/lib/libkmf/include/kmfapiP.h @@ -0,0 +1,348 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _KMFAPIP_H +#define _KMFAPIP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapi.h> +#include <kmfpolicy.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Plugin function table */ +typedef struct { + ushort_t version; + KMF_RETURN (*ConfigureKeystore) ( + KMF_HANDLE_T, + KMF_CONFIG_PARAMS *); + + KMF_RETURN (*FindCert) ( + KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *, + KMF_X509_DER_CERT *, + uint32_t *); + + void (*FreeKMFCert) ( + KMF_HANDLE_T, + KMF_X509_DER_CERT *); + + KMF_RETURN (*StoreCert) ( + KMF_HANDLE_T, + KMF_STORECERT_PARAMS *, + KMF_DATA *); + + KMF_RETURN (*ImportCert) ( + KMF_HANDLE_T, + KMF_IMPORTCERT_PARAMS *); + + KMF_RETURN (*ImportCRL) ( + KMF_HANDLE_T, + KMF_IMPORTCRL_PARAMS *); + + KMF_RETURN (*DeleteCert) ( + KMF_HANDLE_T, + KMF_DELETECERT_PARAMS *); + + KMF_RETURN (*DeleteCRL) ( + KMF_HANDLE_T, + KMF_DELETECRL_PARAMS *); + + KMF_RETURN (*CreateKeypair) ( + KMF_HANDLE_T, + KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, + KMF_KEY_HANDLE *); + + KMF_RETURN (*FindKey) ( + KMF_HANDLE_T, + KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, + uint32_t *); + + KMF_RETURN (*EncodePubkeyData) ( + KMF_HANDLE_T, + KMF_KEY_HANDLE *, + KMF_DATA *); + + KMF_RETURN (*SignData) ( + KMF_HANDLE_T, + KMF_KEY_HANDLE *, + KMF_OID *, + KMF_DATA *, + KMF_DATA *); + + KMF_RETURN (*DeleteKey) ( + KMF_HANDLE_T, + KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, + boolean_t); + + KMF_RETURN (*ListCRL) ( + KMF_HANDLE_T, + KMF_LISTCRL_PARAMS *, + char **); + + KMF_RETURN (*FindCRL) ( + KMF_HANDLE_T, + KMF_FINDCRL_PARAMS *, + char **, + int *); + + KMF_RETURN (*FindCertInCRL) ( + KMF_HANDLE_T, + KMF_FINDCERTINCRL_PARAMS *); + + KMF_RETURN (*GetErrorString) ( + KMF_HANDLE_T, + char **); + + KMF_RETURN (*GetPrikeyByCert) ( + KMF_HANDLE_T, + KMF_CRYPTOWITHCERT_PARAMS *, + KMF_DATA *, + KMF_KEY_HANDLE *, + KMF_KEY_ALG); + + KMF_RETURN (*DecryptData) ( + KMF_HANDLE_T, + KMF_KEY_HANDLE *, + KMF_OID *, + KMF_DATA *, + KMF_DATA *); + + KMF_RETURN (*ExportP12)( + KMF_HANDLE_T, + KMF_EXPORTP12_PARAMS *, + int, KMF_X509_DER_CERT *, + int, KMF_KEY_HANDLE *, + char *); + + KMF_RETURN (*StorePrivateKey)( + KMF_HANDLE_T, + KMF_STOREKEY_PARAMS *, + KMF_RAW_KEY_DATA *); + + KMF_RETURN (*CreateSymKey) ( + KMF_HANDLE_T, + KMF_CREATESYMKEY_PARAMS *, + KMF_KEY_HANDLE *); + + KMF_RETURN (*GetSymKeyValue) ( + KMF_HANDLE_T, + KMF_KEY_HANDLE *, + KMF_RAW_SYM_KEY *); + + KMF_RETURN (*SetTokenPin) ( + KMF_HANDLE_T, + KMF_SETPIN_PARAMS *, + KMF_CREDENTIAL *); + + void (*Finalize) (); + +} KMF_PLUGIN_FUNCLIST; + +typedef struct { + KMF_KEYSTORE_TYPE type; + char *applications; + char *path; + void *dldesc; + KMF_PLUGIN_FUNCLIST *funclist; +} KMF_PLUGIN; + +typedef struct _KMF_PLUGIN_LIST { + KMF_PLUGIN *plugin; + struct _KMF_PLUGIN_LIST *next; +} KMF_PLUGIN_LIST; + +typedef struct _kmf_handle { + /* + * session handle opened by KMF_SelectToken() to talk + * to a specific slot in Crypto framework. It is used + * by pkcs11 plugin module. + */ + CK_SESSION_HANDLE pk11handle; + KMF_ERROR lasterr; + KMF_POLICY_RECORD *policy; + KMF_PLUGIN_LIST *plugins; +} KMF_HANDLE; + +#define CLEAR_ERROR(h, rv) { \ + if (h == NULL) { \ + rv = KMF_ERR_BAD_PARAMETER; \ + } else { \ + h->lasterr.errcode = 0; \ + h->lasterr.kstype = 0; \ + rv = KMF_OK; \ + } \ +} + +#define KMF_PLUGIN_INIT_SYMBOL "KMF_Plugin_Initialize" + +#ifndef KMF_PLUGIN_PATH +#if defined(__sparcv9) +#define KMF_PLUGIN_PATH "/usr/lib/security/sparcv9/" +#elif defined(__sparc) +#define KMF_PLUGIN_PATH "/usr/lib/security/" +#elif defined(__i386) +#define KMF_PLUGIN_PATH "/usr/lib/security/" +#elif defined(__amd64) +#define KMF_PLUGIN_PATH "/usr/lib/security/amd64/" +#endif +#endif /* !KMF_PLUGIN_PATH */ + +KMF_PLUGIN_FUNCLIST *KMF_Plugin_Initialize(); + +KMF_RETURN +SignCert(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +VerifyCertWithKey(KMF_HANDLE_T, KMF_DATA *, const KMF_DATA *); + +KMF_RETURN +VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *); + +KMF_RETURN +VerifyDataWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, const KMF_DATA *); + +KMF_RETURN +VerifyDataWithKey(KMF_HANDLE_T, KMF_DATA *, KMF_ALGORITHM_INDEX, KMF_DATA *, + KMF_DATA *); + +KMF_RETURN +EncryptWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, KMF_DATA *); + +KMF_RETURN +DecryptWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *, + KMF_DATA *); + +KMF_RETURN +SignCsr(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, + KMF_X509_ALGORITHM_IDENTIFIER *, KMF_DATA *); + +KMF_BOOL PKCS_ConvertAlgorithmId2PKCSKeyType( + KMF_ALGORITHM_INDEX, CK_KEY_TYPE *); + +KMF_RETURN PKCS_VerifyData( + KMF_HANDLE *, + KMF_ALGORITHM_INDEX, + KMF_X509_SPKI *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN PKCS_EncryptData( + KMF_HANDLE *, + KMF_ALGORITHM_INDEX, + KMF_X509_SPKI *, + KMF_DATA *, + KMF_DATA *); + +KMF_PLUGIN *FindPlugin(KMF_HANDLE_T, KMF_KEYSTORE_TYPE); + +KMF_BOOL IsEqualOid(KMF_OID *, KMF_OID *); + +KMF_OID *X509_AlgIdToAlgorithmOid(KMF_ALGORITHM_INDEX); + +KMF_ALGORITHM_INDEX X509_AlgorithmOidToAlgId(KMF_OID *); +KMF_RETURN GetIDFromSPKI(KMF_X509_SPKI *, KMF_DATA *); +CK_RV DigestData(CK_SESSION_HANDLE, KMF_DATA *, KMF_DATA *); + +KMF_RETURN KMF_SetAltName(KMF_X509_EXTENSIONS *, + KMF_OID *, int, KMF_GENERALNAMECHOICES, char *); +KMF_RETURN GetSequenceContents(char *, size_t, char **, size_t *); +KMF_X509_EXTENSION *FindExtn(KMF_X509_EXTENSIONS *, KMF_OID *); +KMF_RETURN add_an_extension(KMF_X509_EXTENSIONS *exts, + KMF_X509_EXTENSION *newextn); +KMF_RETURN set_integer(KMF_DATA *, void *, int); +void free_keyidlist(KMF_OID *, int); +KMF_RETURN copy_data(KMF_DATA *, KMF_DATA *); +void Cleanup_PK11_Session(KMF_HANDLE_T handle); +void free_dp_name(KMF_CRL_DIST_POINT *); +void free_dp(KMF_CRL_DIST_POINT *); +KMF_RETURN set_key_usage_extension(KMF_X509_EXTENSIONS *, + int, uint32_t); +int is_pk11_ready(); +KMF_RETURN KMF_SelectToken(KMF_HANDLE_T, char *, int); + + +/* Indexes into the key parts array for RSA keys */ +#define KMF_RSA_MODULUS (0) +#define KMF_RSA_PUBLIC_EXPONENT (1) +#define KMF_RSA_PRIVATE_EXPONENT (2) +#define KMF_RSA_PRIME1 (3) +#define KMF_RSA_PRIME2 (4) +#define KMF_RSA_EXPONENT1 (5) +#define KMF_RSA_EXPONENT2 (6) +#define KMF_RSA_COEFFICIENT (7) + +/* Key part counts for RSA keys */ +#define KMF_NUMBER_RSA_PUBLIC_KEY_PARTS (2) +#define KMF_NUMBER_RSA_PRIVATE_KEY_PARTS (8) + +/* Key part counts for DSA keys */ +#define KMF_NUMBER_DSA_PUBLIC_KEY_PARTS (4) +#define KMF_NUMBER_DSA_PRIVATE_KEY_PARTS (4) + +/* Indexes into the key parts array for DSA keys */ +#define KMF_DSA_PRIME (0) +#define KMF_DSA_SUB_PRIME (1) +#define KMF_DSA_BASE (2) +#define KMF_DSA_PUBLIC_VALUE (3) + +#ifndef max +#define max(a, b) ((a) < (b) ? (b) : (a)) +#endif + +/* Maximum key parts for all algorithms */ +#define KMF_MAX_PUBLIC_KEY_PARTS \ + (max(KMF_NUMBER_RSA_PUBLIC_KEY_PARTS, \ + KMF_NUMBER_DSA_PUBLIC_KEY_PARTS)) + +#define KMF_MAX_PRIVATE_KEY_PARTS \ + (max(KMF_NUMBER_RSA_PRIVATE_KEY_PARTS, \ + KMF_NUMBER_DSA_PRIVATE_KEY_PARTS)) + +#define KMF_MAX_KEY_PARTS \ + (max(KMF_MAX_PUBLIC_KEY_PARTS, KMF_MAX_PRIVATE_KEY_PARTS)) + +typedef enum { + KMF_ALGMODE_NONE = 0, + KMF_ALGMODE_CUSTOM, + KMF_ALGMODE_PUBLIC_KEY, + KMF_ALGMODE_PRIVATE_KEY, + KMF_ALGMODE_PKCS1_EMSA_V15 +} KMF_SIGNATURE_MODE; + +#define KMF_CERT_PRINTABLE_LEN 1024 +#define SHA1_HASH_LENGTH 20 + +#define OCSPREQ_TEMPNAME "/tmp/ocsp.reqXXXXXX" +#define OCSPRESP_TEMPNAME "/tmp/ocsp.respXXXXXX" + +#ifdef __cplusplus +} +#endif +#endif /* _KMFAPIP_H */ diff --git a/usr/src/lib/libkmf/include/kmfpolicy.h b/usr/src/lib/libkmf/include/kmfpolicy.h new file mode 100644 index 0000000000..e00c55e620 --- /dev/null +++ b/usr/src/lib/libkmf/include/kmfpolicy.h @@ -0,0 +1,197 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _KMFPOLICY_H +#define _KMFPOLICY_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapi.h> +#include <libxml/tree.h> +#include <libxml/parser.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *name; + char *serial; +}KMF_RESP_CERT_POLICY; + +typedef struct { + char *responderURI; + char *proxy; + boolean_t uri_from_cert; + char *response_lifetime; + boolean_t ignore_response_sign; +}KMF_OCSP_BASIC_POLICY; + +typedef struct { + KMF_OCSP_BASIC_POLICY basic; + KMF_RESP_CERT_POLICY resp_cert; + boolean_t has_resp_cert; +}KMF_OCSP_POLICY; + +typedef struct { + char *basefilename; + char *directory; + char *proxy; + boolean_t get_crl_uri; + boolean_t ignore_crl_sign; + boolean_t ignore_crl_date; +}KMF_CRL_POLICY; + +typedef struct { + KMF_OCSP_POLICY ocsp_info; + KMF_CRL_POLICY crl_info; +}KMF_VALIDATION_POLICY; + +typedef struct { + int eku_count; + KMF_OID *ekulist; +}KMF_EKU_POLICY; + + +#define KMF_REVOCATION_METHOD_CRL 0x1 +#define KMF_REVOCATION_METHOD_OCSP 0x2 + + +typedef struct { + char *name; + KMF_VALIDATION_POLICY validation_info; + KMF_EKU_POLICY eku_set; + uint32_t ku_bits; + boolean_t ignore_date; + boolean_t ignore_unknown_ekus; + boolean_t ignore_trust_anchor; + char *validity_adjusttime; + char *ta_name; + char *ta_serial; + uint32_t revocation; +} KMF_POLICY_RECORD; + + +/* + * Short cut for ocsp_info and etc. + */ +#define VAL_OCSP validation_info.ocsp_info + +#define VAL_OCSP_BASIC VAL_OCSP.basic +#define VAL_OCSP_RESPONDER_URI VAL_OCSP_BASIC.responderURI +#define VAL_OCSP_PROXY VAL_OCSP_BASIC.proxy +#define VAL_OCSP_URI_FROM_CERT VAL_OCSP_BASIC.uri_from_cert +#define VAL_OCSP_RESP_LIFETIME VAL_OCSP_BASIC.response_lifetime +#define VAL_OCSP_IGNORE_RESP_SIGN VAL_OCSP_BASIC.ignore_response_sign + +#define VAL_OCSP_RESP_CERT VAL_OCSP.resp_cert +#define VAL_OCSP_RESP_CERT_NAME VAL_OCSP_RESP_CERT.name +#define VAL_OCSP_RESP_CERT_SERIAL VAL_OCSP_RESP_CERT.serial + +/* + * Short cut for crl_info and etc. + */ +#define VAL_CRL validation_info.crl_info +#define VAL_CRL_BASEFILENAME validation_info.crl_info.basefilename +#define VAL_CRL_DIRECTORY validation_info.crl_info.directory +#define VAL_CRL_GET_URI validation_info.crl_info.get_crl_uri +#define VAL_CRL_PROXY validation_info.crl_info.proxy +#define VAL_CRL_IGNORE_SIGN validation_info.crl_info.ignore_crl_sign +#define VAL_CRL_IGNORE_DATE validation_info.crl_info.ignore_crl_date + +/* + * Policy related constant definitions. + */ +#define KMF_POLICY_DTD "/usr/share/lib/xml/dtd/kmfpolicy.dtd" +#define KMF_DEFAULT_POLICY_FILE "/etc/security/kmfpolicy.xml" + +#define KMF_DEFAULT_POLICY_NAME "default" + +#define KMF_POLICY_ROOT "kmf-policy-db" + +#define KULOWBIT 7 +#define KUHIGHBIT 15 + +#define KMF_POLICY_ELEMENT "kmf-policy" +#define KMF_POLICY_NAME_ATTR "name" +#define KMF_OPTIONS_IGNORE_DATE_ATTR "ignore-date" +#define KMF_OPTIONS_IGNORE_UNKNOWN_EKUS "ignore-unknown-eku" +#define KMF_OPTIONS_IGNORE_TRUST_ANCHOR "ignore-trust-anchor" +#define KMF_OPTIONS_VALIDITY_ADJUSTTIME "validity-adjusttime" +#define KMF_POLICY_TA_NAME_ATTR "ta-name" +#define KMF_POLICY_TA_SERIAL_ATTR "ta-serial" + +#define KMF_VALIDATION_METHODS_ELEMENT "validation-methods" + +#define KMF_OCSP_ELEMENT "ocsp" +#define KMF_OCSP_BASIC_ELEMENT "ocsp-basic" +#define KMF_OCSP_RESPONDER_ATTR "responder" +#define KMF_OCSP_PROXY_ATTR "proxy" +#define KMF_OCSP_URI_ATTR "uri-from-cert" +#define KMF_OCSP_RESPONSE_LIFETIME_ATTR "response-lifetime" +#define KMF_OCSP_IGNORE_SIGN_ATTR "ignore-response-sign" +#define KMF_OCSP_RESPONDER_CERT_ELEMENT "responder-cert" + +#define KMF_CERT_NAME_ATTR "name" +#define KMF_CERT_SERIAL_ATTR "serial" + +#define KMF_CRL_ELEMENT "crl" +#define KMF_CRL_BASENAME_ATTR "basefilename" +#define KMF_CRL_DIRECTORY_ATTR "directory" +#define KMF_CRL_GET_URI_ATTR "get-crl-uri" +#define KMF_CRL_PROXY_ATTR "proxy" +#define KMF_CRL_IGNORE_SIGN_ATTR "ignore-crl-sign" +#define KMF_CRL_IGNORE_DATE_ATTR "ignore-crl-date" + +#define KMF_KEY_USAGE_SET_ELEMENT "key-usage-set" +#define KMF_KEY_USAGE_ELEMENT "key-usage" +#define KMF_KEY_USAGE_USE_ATTR "use" + +#define KMF_EKU_ELEMENT "ext-key-usage" +#define KMF_EKU_NAME_ELEMENT "eku-name" +#define KMF_EKU_NAME_ATTR "name" +#define KMF_EKU_OID_ELEMENT "eku-oid" +#define KMF_EKU_OID_ATTR "oid" + +#define TMPFILE_TEMPLATE "policyXXXXXX" + +extern char *ku2str(uint32_t); +extern uint32_t str2ku(char *); +extern int parsePolicyElement(xmlNodePtr, KMF_POLICY_RECORD *); + +extern char *KMF_OID2EKUString(KMF_OID *); +extern KMF_OID *kmf_ekuname2oid(char *); +extern KMF_OID *kmf_string2oid(char *); + +extern KMF_RETURN KMF_GetPolicy(char *, char *, KMF_POLICY_RECORD *); +extern KMF_RETURN KMF_AddPolicyToDB(KMF_POLICY_RECORD *, char *, boolean_t); +extern KMF_RETURN KMF_DeletePolicyFromDB(char *, char *); +extern KMF_RETURN KMF_VerifyPolicy(KMF_POLICY_RECORD *); + +extern void KMF_FreePolicyRecord(KMF_POLICY_RECORD *); +extern void KMF_FreeEKUPolicy(KMF_EKU_POLICY *); + +#ifdef __cplusplus +} +#endif +#endif /* _KMFPOLICY_H */ diff --git a/usr/src/lib/libkmf/include/kmftypes.h b/usr/src/lib/libkmf/include/kmftypes.h new file mode 100644 index 0000000000..a5f71d30d9 --- /dev/null +++ b/usr/src/lib/libkmf/include/kmftypes.h @@ -0,0 +1,1363 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * File: kmftypes.h + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _KMFTYPES_H +#define _KMFTYPES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <stdlib.h> +#include <strings.h> +#include <pthread.h> + +#include <security/cryptoki.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t KMF_BOOL; + +#define KMF_FALSE (0) +#define KMF_TRUE (1) + +/* KMF_HANDLE_T is a pointer to an incomplete C struct for type safety. */ +typedef struct _kmf_handle *KMF_HANDLE_T; + +/* + * KMF_DATA + * The KMF_DATA structure is used to associate a length, in bytes, with + * an arbitrary block of contiguous memory. + */ +typedef struct kmf_data +{ + size_t Length; /* in bytes */ + uchar_t *Data; +} KMF_DATA; + +typedef struct { + uchar_t *val; + size_t len; +} KMF_BIGINT; + +/* + * KMF_OID + * The object identifier (OID) structure is used to hold a unique identifier for + * the atomic data fields and the compound substructure that comprise the fields + * of a certificate or CRL. + */ +typedef KMF_DATA KMF_OID; + +typedef struct kmf_x509_private { + int keystore_type; + int flags; /* see below */ + char *label; +#define KMF_FLAG_CERT_VALID 1 /* contains valid certificate */ +#define KMF_FLAG_CERT_SIGNED 2 /* this is a signed certificate */ +} KMF_X509_PRIVATE, KMF_X509_PRIVATE_PTR; + +/* + * KMF_X509_DER_CERT + * This structure associates packed DER certificate data. + * Also, it contains the private information internal used + * by KMF layer. + */ +typedef struct +{ + KMF_DATA certificate; + KMF_X509_PRIVATE kmf_private; +} KMF_X509_DER_CERT; + +typedef enum { + KMF_KEYSTORE_NSS = 1, + KMF_KEYSTORE_OPENSSL = 2, + KMF_KEYSTORE_PK11TOKEN = 3, + KMF_KEYSTORE_DEFAULT /* based on configuration */ +} KMF_KEYSTORE_TYPE; + +#define VALID_KEYSTORE_TYPE(t) ((t >= KMF_KEYSTORE_NSS) &&\ + (t <= KMF_KEYSTORE_PK11TOKEN)) + +typedef enum { + KMF_FORMAT_UNDEF = 0, + KMF_FORMAT_ASN1 = 1, /* DER */ + KMF_FORMAT_PEM = 2, + KMF_FORMAT_PKCS12 = 3, + KMF_FORMAT_RAWKEY = 4 /* For FindKey operation */ +} KMF_ENCODE_FORMAT; + +typedef enum { + KMF_ALL_CERTS = 0, + KMF_NONEXPIRED_CERTS = 1, + KMF_EXPIRED_CERTS = 2 +} KMF_CERT_VALIDITY; + +typedef enum { + KMF_KU_SIGN_CERT = 0, + KMF_KU_SIGN_DATA = 1, + KMF_KU_ENCRYPT_DATA = 2 +} KMF_KU_PURPOSE; + + +/* Keystore Configuration */ +typedef struct { + char *configdir; + char *certPrefix; + char *keyPrefix; + char *secModName; +} KMF_NSS_CONFIG; + +typedef struct { + char *label; + boolean_t readonly; +} KMF_PKCS11_CONFIG; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + union { + KMF_NSS_CONFIG nss_conf; + KMF_PKCS11_CONFIG pkcs11_conf; + } ks_config_u; +} KMF_CONFIG_PARAMS; + +#define nssconfig ks_config_u.nss_conf +#define pkcs11config ks_config_u.pkcs11_conf + +/* + * Generic credential structure used by other structures below + * to convey authentication information to the underlying + * mechanisms. + */ +typedef struct { + char *cred; + uint32_t credlen; +} KMF_CREDENTIAL; + +typedef struct +{ + char *trustflag; + char *slotlabel; /* "internal" by default */ + int issuerId; + int subjectId; + char *crlfile; /* for ImportCRL */ + boolean_t crl_check; /* for ImportCRL */ + + /* + * crl_subjName and crl_issuerName are used as the CRL deletion + * criteria. One should be non-NULL and the other one should be NULL. + * If crl_subjName is not NULL, then delete CRL by the subject name. + * Othewise, delete by the issuer name. + */ + char *crl_subjName; + char *crl_issuerName; +} KMF_NSS_PARAMS; + +typedef struct { + char *dirpath; + char *certfile; + char *crlfile; + char *keyfile; + char *outcrlfile; + boolean_t crl_check; /* CRL import check; default is true */ + KMF_ENCODE_FORMAT format; /* output file format */ +} KMF_OPENSSL_PARAMS; + +typedef struct { + boolean_t private; /* for finding CKA_PRIVATE objects */ + boolean_t sensitive; + boolean_t not_extractable; +} KMF_PKCS11_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + char *certLabel; + char *issuer; + char *subject; + char *idstr; + KMF_BIGINT *serial; + KMF_CERT_VALIDITY find_cert_validity; + + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + KMF_PKCS11_PARAMS pkcs11_opts; + } ks_opt_u; +} KMF_FINDCERT_PARAMS, KMF_DELETECERT_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + char *certLabel; + char *issuer; + char *subject; + char *idstr; + KMF_BIGINT *serial; + KMF_DATA *ocsp_response; + + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + KMF_PKCS11_PARAMS pkcs11_opts; + } ks_opt_u; +} KMF_VALIDATECERT_PARAMS; + +typedef enum { + KMF_KEYALG_NONE = 0, + KMF_RSA = 1, + KMF_DSA = 2, + KMF_AES = 3, + KMF_RC4 = 4, + KMF_DES = 5, + KMF_DES3 = 6 +}KMF_KEY_ALG; + +typedef enum { + KMF_KEYCLASS_NONE = 0, + KMF_ASYM_PUB = 1, /* public key of an asymmetric keypair */ + KMF_ASYM_PRI = 2, /* private key of an asymmetric keypair */ + KMF_SYMMETRIC = 3 /* symmetric key */ +}KMF_KEY_CLASS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_CREDENTIAL cred; + KMF_KEY_CLASS keyclass; + KMF_KEY_ALG keytype; + KMF_ENCODE_FORMAT format; /* for key */ + char *findLabel; + char *idstr; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + KMF_PKCS11_PARAMS pkcs11_opts; + } ks_opt_u; +} KMF_FINDKEY_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; /* all */ + char *certLabel; + + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + } ks_opt_u; +} KMF_STORECERT_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_CREDENTIAL cred; + KMF_DATA *certificate; + char *label; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + } ks_opt_u; +} KMF_STOREKEY_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_CREDENTIAL cred; + union { + KMF_NSS_PARAMS nss_opts; + } ks_opt_u; +} KMF_DELETEKEY_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + char *certfile; + char *certLabel; + + union { + KMF_NSS_PARAMS nss_opts; + } ks_opt_u; +} KMF_IMPORTCERT_PARAMS; + +typedef enum { + KMF_CERT = 0, + KMF_CSR = 1, + KMF_CRL = 2 +}KMF_OBJECT_TYPE; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_KEY_ALG keytype; + uint32_t keylength; + char *keylabel; + KMF_CREDENTIAL cred; + KMF_BIGINT rsa_exponent; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + }ks_opt_u; +} KMF_CREATEKEYPAIR_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + } ks_opt_u; +} KMF_IMPORTCRL_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + } ks_opt_u; +} KMF_DELETECRL_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + } ks_opt_u; +} KMF_LISTCRL_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + union { + KMF_NSS_PARAMS nss_opts; + } ks_opt_u; +} KMF_FINDCRL_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + char *certLabel; + + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + } ks_opt_u; +} KMF_FINDCERTINCRL_PARAMS; + +typedef struct { + char *crl_name; + KMF_DATA *tacert; +} KMF_VERIFYCRL_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_CREDENTIAL cred; + KMF_ENCODE_FORMAT format; /* for key */ + char *certLabel; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + }ks_opt_u; +} KMF_CRYPTOWITHCERT_PARAMS; + +typedef struct { + char *crl_name; +} KMF_CHECKCRLDATE_PARAMS; + +typedef struct { + CK_SLOT_ID slot; +} pk11_setpin_opts; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + char *tokenname; + KMF_CREDENTIAL cred; /* current token PIN */ + union { + KMF_NSS_PARAMS nss_opts; + pk11_setpin_opts pkcs11_opts; + }ks_opt_u; +} KMF_SETPIN_PARAMS; + +typedef struct { + KMF_BIGINT mod; + KMF_BIGINT pubexp; + KMF_BIGINT priexp; + KMF_BIGINT prime1; + KMF_BIGINT prime2; + KMF_BIGINT exp1; + KMF_BIGINT exp2; + KMF_BIGINT coef; +} KMF_RAW_RSA_KEY; + +typedef struct { + KMF_BIGINT prime; + KMF_BIGINT subprime; + KMF_BIGINT base; + KMF_BIGINT value; +} KMF_RAW_DSA_KEY; + +typedef struct { + KMF_BIGINT keydata; +} KMF_RAW_SYM_KEY; + +typedef struct { + KMF_KEY_ALG keytype; + union { + KMF_RAW_RSA_KEY rsa; + KMF_RAW_DSA_KEY dsa; + KMF_RAW_SYM_KEY sym; + }rawdata; +} KMF_RAW_KEY_DATA; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + char *certLabel; + char *issuer; + char *subject; + char *idstr; + KMF_BIGINT *serial; + KMF_CREDENTIAL cred; /* cred for accessing the token */ + KMF_CREDENTIAL p12cred; /* cred used for securing the file */ + + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + }ks_opt_u; +} KMF_EXPORTP12_PARAMS; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_KEY_ALG keytype; + uint32_t keylength; + char *keylabel; + KMF_CREDENTIAL cred; + union { + KMF_NSS_PARAMS nss_opts; + KMF_OPENSSL_PARAMS openssl_opts; + KMF_PKCS11_PARAMS pkcs11_opts; + }ks_opt_u; +} KMF_CREATESYMKEY_PARAMS; + +/* Data structures for OCSP support */ +typedef struct { + KMF_DATA *issuer_cert; + KMF_DATA *user_cert; +} KMF_OCSPREQUEST_PARAMS; + +typedef struct { + KMF_DATA *response; + KMF_DATA *issuer_cert; + KMF_DATA *user_cert; + KMF_DATA *signer_cert; /* can be NULL */ + boolean_t ignore_response_sign; /* default is FALSE */ + uint32_t response_lifetime; /* in seconds */ +} KMF_OCSPRESPONSE_PARAMS_INPUT; + +typedef enum { + OCSP_GOOD = 0, + OCSP_REVOKED = 1, + OCSP_UNKNOWN = 2 +} KMF_OCSP_CERT_STATUS; + +typedef struct { + int response_status; + int reason; /* if revoked */ + KMF_OCSP_CERT_STATUS cert_status; +} KMF_OCSPRESPONSE_PARAMS_OUTPUT; + +#define nssparms ks_opt_u.nss_opts +#define sslparms ks_opt_u.openssl_opts +#define pkcs11parms ks_opt_u.pkcs11_opts + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + KMF_KEY_ALG keyalg; + KMF_KEY_CLASS keyclass; + boolean_t israw; + char *keylabel; + void *keyp; +} KMF_KEY_HANDLE; + +typedef struct { + KMF_KEYSTORE_TYPE kstype; + uint32_t errcode; +} KMF_ERROR; + +/* + * Typenames to use with subjectAltName + */ +typedef enum { + GENNAME_OTHERNAME = 0x00, + GENNAME_RFC822NAME, + GENNAME_DNSNAME, + GENNAME_X400ADDRESS, + GENNAME_DIRECTORYNAME, + GENNAME_EDIPARTYNAME, + GENNAME_URI, + GENNAME_IPADDRESS, + GENNAME_REGISTEREDID +} KMF_GENERALNAMECHOICES; + +/* + * KMF_FIELD + * This structure contains the OID/value pair for any item that can be + * identified by an OID. + */ +typedef struct +{ + KMF_OID FieldOid; + KMF_DATA FieldValue; +} KMF_FIELD; + +typedef enum { + KMF_OK = 0x00, + KMF_ERR_BAD_PARAMETER = 0x01, + KMF_ERR_BAD_KEY_FORMAT = 0x02, + KMF_ERR_BAD_ALGORITHM = 0x03, + KMF_ERR_MEMORY = 0x04, + KMF_ERR_ENCODING = 0x05, + KMF_ERR_PLUGIN_INIT = 0x06, + KMF_ERR_PLUGIN_NOTFOUND = 0x07, + KMF_ERR_INTERNAL = 0x0b, + KMF_ERR_BAD_CERT_FORMAT = 0x0c, + KMF_ERR_KEYGEN_FAILED = 0x0d, + KMF_ERR_UNINITIALIZED = 0x10, + KMF_ERR_ISSUER = 0x11, + KMF_ERR_NOT_REVOKED = 0x12, + KMF_ERR_CERT_NOT_FOUND = 0x13, + KMF_ERR_CRL_NOT_FOUND = 0x14, + KMF_ERR_RDN_PARSER = 0x15, + KMF_ERR_RDN_ATTR = 0x16, + KMF_ERR_SLOTNAME = 0x17, + KMF_ERR_EMPTY_CRL = 0x18, + KMF_ERR_BUFFER_SIZE = 0x19, + KMF_ERR_AUTH_FAILED = 0x1a, + KMF_ERR_TOKEN_SELECTED = 0x1b, + KMF_ERR_NO_TOKEN_SELECTED = 0x1c, + KMF_ERR_TOKEN_NOT_PRESENT = 0x1d, + KMF_ERR_EXTENSION_NOT_FOUND = 0x1e, + KMF_ERR_POLICY_ENGINE = 0x1f, + KMF_ERR_POLICY_DB_FORMAT = 0x20, + KMF_ERR_POLICY_NOT_FOUND = 0x21, + KMF_ERR_POLICY_DB_FILE = 0x22, + KMF_ERR_POLICY_NAME = 0x23, + KMF_ERR_OCSP_POLICY = 0x24, + KMF_ERR_TA_POLICY = 0x25, + KMF_ERR_KEY_NOT_FOUND = 0x26, + KMF_ERR_OPEN_FILE = 0x27, + KMF_ERR_OCSP_BAD_ISSUER = 0x28, + KMF_ERR_OCSP_BAD_CERT = 0x29, + KMF_ERR_OCSP_CREATE_REQUEST = 0x2a, + KMF_ERR_CONNECT_SERVER = 0x2b, + KMF_ERR_SEND_REQUEST = 0x2c, + KMF_ERR_OCSP_CERTID = 0x2d, + KMF_ERR_OCSP_MALFORMED_RESPONSE = 0x2e, + KMF_ERR_OCSP_RESPONSE_STATUS = 0x2f, + KMF_ERR_OCSP_NO_BASIC_RESPONSE = 0x30, + KMF_ERR_OCSP_BAD_SIGNER = 0x31, + KMF_ERR_OCSP_RESPONSE_SIGNATURE = 0x32, + KMF_ERR_OCSP_UNKNOWN_CERT = 0x33, + KMF_ERR_OCSP_STATUS_TIME_INVALID = 0x34, + KMF_ERR_BAD_HTTP_RESPONSE = 0x35, + KMF_ERR_RECV_RESPONSE = 0x36, + KMF_ERR_RECV_TIMEOUT = 0x37, + KMF_ERR_DUPLICATE_KEYFILE = 0x38, + KMF_ERR_AMBIGUOUS_PATHNAME = 0x39, + KMF_ERR_FUNCTION_NOT_FOUND = 0x3a, + KMF_ERR_PKCS12_FORMAT = 0x3b, + KMF_ERR_BAD_KEY_TYPE = 0x3c, + KMF_ERR_BAD_KEY_CLASS = 0x3d, + KMF_ERR_BAD_KEY_SIZE = 0x3e, + KMF_ERR_BAD_HEX_STRING = 0x3f, + KMF_ERR_KEYUSAGE = 0x40, + KMF_ERR_VALIDITY_PERIOD = 0x41, + KMF_ERR_OCSP_REVOKED = 0x42, + KMF_ERR_CERT_MULTIPLE_FOUND = 0x43, + KMF_ERR_WRITE_FILE = 0x44, + KMF_ERR_BAD_URI = 0x45, + KMF_ERR_BAD_CRLFILE = 0x46, + KMF_ERR_BAD_CERTFILE = 0x47, + KMF_ERR_GETKEYVALUE_FAILED = 0x48, + KMF_ERR_BAD_KEYHANDLE = 0x49, + KMF_ERR_BAD_OBJECT_TYPE = 0x4a, + KMF_ERR_OCSP_RESPONSE_LIFETIME = 0x4b, + KMF_ERR_UNKNOWN_CSR_ATTRIBUTE = 0x4c, + KMF_ERR_UNINITIALIZED_TOKEN = 0x4d, + KMF_ERR_INCOMPLETE_TBS_CERT = 0x4e, + KMF_ERR_MISSING_ERRCODE = 0x4f, + KMF_KEYSTORE_ALREADY_INITIALIZED = 0x50 +} KMF_RETURN; + +typedef enum { + OCSP_SUCCESS = 0, + OCSP_MALFORMED_REQUEST = 1, + OCSP_INTERNAL_ERROR = 2, + OCSP_TRYLATER = 3, + OCSP_SIGREQUIRED = 4, + OCSP_UNAUTHORIZED = 5 +} KMF_OCSP_RESPONSE_STATUS; + +typedef enum { + OCSP_NOSTATUS = -1, + OCSP_UNSPECIFIED = 0, + OCSP_KEYCOMPROMISE = 1, + OCSP_CACOMPROMISE = 2, + OCSP_AFFILIATIONCHANGE = 3, + OCSP_SUPERCEDED = 4, + OCSP_CESSATIONOFOPERATION = 5, + OCSP_CERTIFICATEHOLD = 6, + OCSP_REMOVEFROMCRL = 7 +} KMF_OCSP_REVOKED_STATUS; + +typedef enum { + KMF_ALGCLASS_NONE = 0, + KMF_ALGCLASS_CUSTOM, + KMF_ALGCLASS_SIGNATURE, + KMF_ALGCLASS_SYMMETRIC, + KMF_ALGCLASS_DIGEST, + KMF_ALGCLASS_RANDOMGEN, + KMF_ALGCLASS_UNIQUEGEN, + KMF_ALGCLASS_MAC, + KMF_ALGCLASS_ASYMMETRIC, + KMF_ALGCLASS_KEYGEN, + KMF_ALGCLASS_DERIVEKEY +} KMF_ALGCLASS; + +/* + * Algorithms + * This type defines a set of constants used to identify cryptographic + * algorithms. + */ +typedef enum { + KMF_ALGID_NONE = 0, + KMF_ALGID_CUSTOM, + KMF_ALGID_SHA1, + KMF_ALGID_RSA, + KMF_ALGID_DSA, + KMF_ALGID_MD5WithRSA, + KMF_ALGID_MD2WithRSA, + KMF_ALGID_SHA1WithRSA, + KMF_ALGID_SHA1WithDSA +} KMF_ALGORITHM_INDEX; + +typedef enum { + KMF_CERT_ISSUER = 1, + KMF_CERT_SUBJECT, + KMF_CERT_VERSION, + KMF_CERT_SERIALNUM, + KMF_CERT_NOTBEFORE, + KMF_CERT_NOTAFTER, + KMF_CERT_PUBKEY_ALG, + KMF_CERT_SIGNATURE_ALG, + KMF_CERT_EMAIL, + KMF_CERT_PUBKEY_DATA, + KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD, + KMF_X509_EXT_CERT_POLICIES, + KMF_X509_EXT_SUBJ_ALTNAME, + KMF_X509_EXT_ISSUER_ALTNAME, + KMF_X509_EXT_BASIC_CONSTRAINTS, + KMF_X509_EXT_NAME_CONSTRAINTS, + KMF_X509_EXT_POLICY_CONSTRAINTS, + KMF_X509_EXT_EXT_KEY_USAGE, + KMF_X509_EXT_INHIBIT_ANY_POLICY, + KMF_X509_EXT_AUTH_KEY_ID, + KMF_X509_EXT_SUBJ_KEY_ID, + KMF_X509_EXT_POLICY_MAPPINGS, + KMF_X509_EXT_CRL_DIST_POINTS, + KMF_X509_EXT_FRESHEST_CRL, + KMF_X509_EXT_KEY_USAGE +} KMF_PRINTABLE_ITEM; + +/* + * KMF_X509_ALGORITHM_IDENTIFIER + * This structure holds an object identifier naming a + * cryptographic algorithm and an optional set of + * parameters to be used as input to that algorithm. + */ +typedef struct +{ + KMF_OID algorithm; + KMF_DATA parameters; +} KMF_X509_ALGORITHM_IDENTIFIER; + +/* + * KMF_X509_TYPE_VALUE_PAIR + * This structure contain an type-value pair. + */ +typedef struct +{ + KMF_OID type; + uint8_t valueType; /* The Tag to use when BER encoded */ + KMF_DATA value; +} KMF_X509_TYPE_VALUE_PAIR; + + +/* + * KMF_X509_RDN + * This structure contains a Relative Distinguished Name + * composed of an ordered set of type-value pairs. + */ +typedef struct +{ + uint32_t numberOfPairs; + KMF_X509_TYPE_VALUE_PAIR *AttributeTypeAndValue; +} KMF_X509_RDN; + +/* + * KMF_X509_NAME + * This structure contains a set of Relative Distinguished Names. + */ +typedef struct +{ + uint32_t numberOfRDNs; + KMF_X509_RDN *RelativeDistinguishedName; +} KMF_X509_NAME; + +/* + * KMF_X509_SPKI + * This structure contains the public key and the + * description of the verification algorithm + * appropriate for use with this key. + */ +typedef struct +{ + KMF_X509_ALGORITHM_IDENTIFIER algorithm; + KMF_DATA subjectPublicKey; +} KMF_X509_SPKI; + +/* + * KMF_X509_TIME + * Time is represented as a string according to the + * definitions of GeneralizedTime and UTCTime + * defined in RFC 2459. + */ +typedef struct +{ + uint8_t timeType; + KMF_DATA time; +} KMF_X509_TIME; + +/* + * KMF_X509_VALIDITY + */ +typedef struct +{ + KMF_X509_TIME notBefore; + KMF_X509_TIME notAfter; +} KMF_X509_VALIDITY; + +/* + * KMF_X509EXT_BASICCONSTRAINTS + */ +typedef struct +{ + KMF_BOOL cA; + KMF_BOOL pathLenConstraintPresent; + uint32_t pathLenConstraint; +} KMF_X509EXT_BASICCONSTRAINTS; + +/* + * KMF_X509EXT_DATA_FORMAT + * This list defines the valid formats for a certificate extension. + */ +typedef enum +{ + KMF_X509_DATAFORMAT_ENCODED = 0, + KMF_X509_DATAFORMAT_PARSED, + KMF_X509_DATAFORMAT_PAIR +} KMF_X509EXT_DATA_FORMAT; + + +/* + * KMF_X509EXT_TAGandVALUE + * This structure contains a BER/DER encoded + * extension value and the type of that value. + */ +typedef struct +{ + uint8_t type; + KMF_DATA value; +} KMF_X509EXT_TAGandVALUE; + + +/* + * KMF_X509EXT_PAIR + * This structure aggregates two extension representations: + * a tag and value, and a parsed X509 extension representation. + */ +typedef struct +{ + KMF_X509EXT_TAGandVALUE tagAndValue; + void *parsedValue; +} KMF_X509EXT_PAIR; + +/* + * KMF_X509_EXTENSION + * This structure contains a complete certificate extension. + */ +typedef struct +{ + KMF_OID extnId; + KMF_BOOL critical; + KMF_X509EXT_DATA_FORMAT format; + union + { + KMF_X509EXT_TAGandVALUE *tagAndValue; + void *parsedValue; + KMF_X509EXT_PAIR *valuePair; + } value; + KMF_DATA BERvalue; +} KMF_X509_EXTENSION; + + +/* + * KMF_X509_EXTENSIONS + * This structure contains the set of all certificate + * extensions contained in a certificate. + */ +typedef struct +{ + uint32_t numberOfExtensions; + KMF_X509_EXTENSION *extensions; +} KMF_X509_EXTENSIONS; + +/* + * KMF_X509_TBS_CERT + * This structure contains a complete X.509 certificate. + */ +typedef struct +{ + KMF_DATA version; + KMF_BIGINT serialNumber; + KMF_X509_ALGORITHM_IDENTIFIER signature; + KMF_X509_NAME issuer; + KMF_X509_VALIDITY validity; + KMF_X509_NAME subject; + KMF_X509_SPKI subjectPublicKeyInfo; + KMF_DATA issuerUniqueIdentifier; + KMF_DATA subjectUniqueIdentifier; + KMF_X509_EXTENSIONS extensions; +} KMF_X509_TBS_CERT; + +/* + * KMF_X509_SIGNATURE + * This structure contains a cryptographic digital signature. + */ +typedef struct +{ + KMF_X509_ALGORITHM_IDENTIFIER algorithmIdentifier; + KMF_DATA encrypted; +} KMF_X509_SIGNATURE; + +/* + * KMF_X509_CERTIFICATE + * This structure associates a set of decoded certificate + * values with the signature covering those values. + */ +typedef struct +{ + KMF_X509_TBS_CERT certificate; + KMF_X509_SIGNATURE signature; +} KMF_X509_CERTIFICATE; + +#define CERT_ALG_OID(c) &c->certificate.signature.algorithm +#define CERT_SIG_OID(c) &c->signature.algorithmIdentifier.algorithm + +/* + * KMF_TBS_CSR + * This structure contains a complete PKCS#10 certificate request + */ +typedef struct +{ + KMF_DATA version; + KMF_X509_NAME subject; + KMF_X509_SPKI subjectPublicKeyInfo; + KMF_X509_EXTENSIONS extensions; +} KMF_TBS_CSR; + +/* + * KMF_CSR_DATA + * This structure contains a complete PKCS#10 certificate signed request + */ +typedef struct +{ + KMF_TBS_CSR csr; + KMF_X509_SIGNATURE signature; +} KMF_CSR_DATA; + +/* + * KMF_X509EXT_POLICYQUALIFIERINFO + */ +typedef struct +{ + KMF_OID policyQualifierId; + KMF_DATA value; +} KMF_X509EXT_POLICYQUALIFIERINFO; + +/* + * KMF_X509EXT_POLICYQUALIFIERS + */ +typedef struct +{ + uint32_t numberOfPolicyQualifiers; + KMF_X509EXT_POLICYQUALIFIERINFO *policyQualifier; +} KMF_X509EXT_POLICYQUALIFIERS; + +/* + * KMF_X509EXT_POLICYINFO + */ +typedef struct +{ + KMF_OID policyIdentifier; + KMF_X509EXT_POLICYQUALIFIERS policyQualifiers; +} KMF_X509EXT_POLICYINFO; + +typedef struct +{ + uint32_t numberOfPolicyInfo; + KMF_X509EXT_POLICYINFO *policyInfo; +} KMF_X509EXT_CERT_POLICIES; + +typedef struct +{ + uchar_t critical; + uint16_t KeyUsageBits; +} KMF_X509EXT_KEY_USAGE; + +typedef struct +{ + uchar_t critical; + uint16_t nEKUs; + KMF_OID *keyPurposeIdList; +} KMF_X509EXT_EKU; + + +/* + * X509 AuthorityInfoAccess extension + */ +typedef struct +{ + KMF_OID AccessMethod; + KMF_DATA AccessLocation; +} KMF_X509EXT_ACCESSDESC; + +typedef struct +{ + uint32_t numberOfAccessDescription; + KMF_X509EXT_ACCESSDESC *AccessDesc; +} KMF_X509EXT_AUTHINFOACCESS; + + +/* + * X509 Crl Distribution Point extension + */ +typedef struct { + KMF_GENERALNAMECHOICES choice; + KMF_DATA name; +} KMF_GENERALNAME; + +typedef struct { + uint32_t number; + KMF_GENERALNAME *namelist; +} KMF_GENERALNAMES; + +typedef enum { + DP_GENERAL_NAME = 1, + DP_RELATIVE_NAME = 2 +} KMF_CRL_DIST_POINT_TYPE; + +typedef struct { + KMF_CRL_DIST_POINT_TYPE type; + union { + KMF_GENERALNAMES full_name; + KMF_DATA relative_name; + } name; + KMF_DATA reasons; + KMF_GENERALNAMES crl_issuer; +} KMF_CRL_DIST_POINT; + +typedef struct { + uint32_t number; + KMF_CRL_DIST_POINT *dplist; +} KMF_X509EXT_CRLDISTPOINTS; + + +/* + * Definitions for common X.509v3 certificate attribute OIDs + */ +#define OID_ISO_MEMBER 42 /* Also in PKCS */ +#define OID_US OID_ISO_MEMBER, 134, 72 /* Also in PKCS */ +#define OID_CA OID_ISO_MEMBER, 124 + +#define OID_ISO_IDENTIFIED_ORG 43 +#define OID_OSINET OID_ISO_IDENTIFIED_ORG, 4 +#define OID_GOSIP OID_ISO_IDENTIFIED_ORG, 5 +#define OID_DOD OID_ISO_IDENTIFIED_ORG, 6 +#define OID_OIW OID_ISO_IDENTIFIED_ORG, 14 /* Also in x9.57 */ + +#define OID_ISO_CCITT_DIR_SERVICE 85 +#define OID_ISO_CCITT_COUNTRY 96 +#define OID_COUNTRY_US OID_ISO_CCITT_COUNTRY, 134, 72 +#define OID_COUNTRY_CA OID_ISO_CCITT_COUNTRY, 124 +#define OID_COUNTRY_US_ORG OID_COUNTRY_US, 1 +#define OID_COUNTRY_US_MHS_MD OID_COUNTRY_US, 2 +#define OID_COUNTRY_US_STATE OID_COUNTRY_US, 3 + +/* From the PKCS Standards */ +#define OID_ISO_MEMBER_LENGTH 1 +#define OID_US_LENGTH (OID_ISO_MEMBER_LENGTH + 2) + +#define OID_RSA OID_US, 134, 247, 13 +#define OID_RSA_LENGTH (OID_US_LENGTH + 3) + +#define OID_RSA_HASH OID_RSA, 2 +#define OID_RSA_HASH_LENGTH (OID_RSA_LENGTH + 1) + +#define OID_RSA_ENCRYPT OID_RSA, 3 +#define OID_RSA_ENCRYPT_LENGTH (OID_RSA_LENGTH + 1) + +#define OID_PKCS OID_RSA, 1 +#define OID_PKCS_LENGTH (OID_RSA_LENGTH + 1) + +#define OID_PKCS_1 OID_PKCS, 1 +#define OID_PKCS_1_LENGTH (OID_PKCS_LENGTH + 1) + +#define OID_PKCS_2 OID_PKCS, 2 +#define OID_PKCS_3 OID_PKCS, 3 +#define OID_PKCS_3_LENGTH (OID_PKCS_LENGTH + 1) + +#define OID_PKCS_4 OID_PKCS, 4 +#define OID_PKCS_5 OID_PKCS, 5 +#define OID_PKCS_5_LENGTH (OID_PKCS_LENGTH + 1) +#define OID_PKCS_6 OID_PKCS, 6 +#define OID_PKCS_7 OID_PKCS, 7 +#define OID_PKCS_7_LENGTH (OID_PKCS_LENGTH + 1) + +#define OID_PKCS_7_Data OID_PKCS_7, 1 +#define OID_PKCS_7_SignedData OID_PKCS_7, 2 +#define OID_PKCS_7_EnvelopedData OID_PKCS_7, 3 +#define OID_PKCS_7_SignedAndEnvelopedData OID_PKCS_7, 4 +#define OID_PKCS_7_DigestedData OID_PKCS_7, 5 +#define OID_PKCS_7_EncryptedData OID_PKCS_7, 6 + +#define OID_PKCS_8 OID_PKCS, 8 +#define OID_PKCS_9 OID_PKCS, 9 +#define OID_PKCS_9_LENGTH (OID_PKCS_LENGTH + 1) + +#define OID_PKCS_9_CONTENT_TYPE OID_PKCS_9, 3 +#define OID_PKCS_9_MESSAGE_DIGEST OID_PKCS_9, 4 +#define OID_PKCS_9_SIGNING_TIME OID_PKCS_9, 5 +#define OID_PKCS_9_COUNTER_SIGNATURE OID_PKCS_9, 6 +#define OID_PKCS_9_EXTENSION_REQUEST OID_PKCS_9, 14 + +#define OID_PKCS_10 OID_PKCS, 10 + +#define OID_PKCS_12 OID_PKCS, 12 +#define OID_PKCS_12_LENGTH (OID_PKCS_LENGTH + 1) + +#define PBEWithSHAAnd128BitRC4 OID_PKCS_12, 1, 1 +#define PBEWithSHAAnd40BitRC4 OID_PKCS_12, 1, 2 +#define PBEWithSHAAnd3KeyTripleDES_CBC OID_PKCS_12, 1, 3 +#define PBEWithSHAAnd2KeyTripleDES_CBC OID_PKCS_12, 1, 4 +#define PBEWithSHAAnd128BitRC2_CBC OID_PKCS_12, 1, 5 +#define PBEWithSHAAnd40BitRC2_CBC OID_PKCS_12, 1, 6 + +#define OID_BAG_TYPES OID_PKCS_12, 10, 1 +#define OID_KeyBag OID_BAG_TYPES, 1 +#define OID_PKCS8ShroudedKeyBag OID_BAG_TYPES, 2 +#define OID_CertBag OID_BAG_TYPES, 3 +#define OID_CrlBag OID_BAG_TYPES, 4 +#define OID_SecretBag OID_BAG_TYPES, 5 +#define OID_SafeContentsBag OID_BAG_TYPES, 6 + +#define OID_ContentInfo OID_PKCS_7, 0, 1 + +#define OID_CERT_TYPES OID_PKCS_9, 22 +#define OID_x509Certificate OID_CERT_TYPES, 1 +#define OID_sdsiCertificate OID_CERT_TYPES, 2 + +#define OID_CRL_TYPES OID_PKCS_9, 23 +#define OID_x509Crl OID_CRL_TYPES, 1 + +#define OID_DS OID_ISO_CCITT_DIR_SERVICE /* Also in X.501 */ +#define OID_DS_LENGTH 1 + +#define OID_ATTR_TYPE OID_DS, 4 /* Also in X.501 */ +#define OID_ATTR_TYPE_LENGTH (OID_DS_LENGTH + 1) + +#define OID_DSALG OID_DS, 8 /* Also in X.501 */ +#define OID_DSALG_LENGTH (OID_DS_LENGTH + 1) + +#define OID_EXTENSION OID_DS, 29 /* Also in X.501 */ +#define OID_EXTENSION_LENGTH (OID_DS_LENGTH + 1) + +/* + * From RFC 1274: + * {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) } + */ +#define OID_PILOT 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x1 +#define OID_PILOT_LENGTH 9 + +#define OID_USERID OID_PILOT 1 +#define OID_USERID_LENGTH (OID_PILOT_LENGTH + 1) + +/* + * From PKIX part1 + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define OID_PKIX 43, 6, 1, 5, 5, 7 +#define OID_PKIX_LENGTH 6 + +/* private certificate extensions, { id-pkix 1 } */ +#define OID_PKIX_PE OID_PKIX, 1 +#define OID_PKIX_PE_LENGTH (OID_PKIX_LENGTH + 1) + +/* policy qualifier types {id-pkix 2 } */ +#define OID_PKIX_QT OID_PKIX, 2 +#define OID_PKIX_QT_LENGTH (OID_PKIX_LENGTH + 1) + +/* CPS qualifier, { id-qt 1 } */ +#define OID_PKIX_QT_CPS OID_PKIX_QT, 1 +#define OID_PKIX_QT_CPS_LENGTH (OID_PKIX_QT_LENGTH + 1) +/* user notice qualifier, { id-qt 2 } */ +#define OID_PKIX_QT_UNOTICE OID_PKIX_QT, 2 +#define OID_PKIX_QT_UNOTICE_LENGTH (OID_PKIX_QT_LENGTH + 1) + +/* extended key purpose OIDs {id-pkix 3 } */ +#define OID_PKIX_KP OID_PKIX, 3 +#define OID_PKIX_KP_LENGTH (OID_PKIX_LENGTH + 1) + +/* access descriptors {id-pkix 4 } */ +#define OID_PKIX_AD OID_PKIX, 48 +#define OID_PKIX_AD_LENGTH (OID_PKIX_LENGTH + 1) + +/* access descriptors */ +/* OCSP */ +#define OID_PKIX_AD_OCSP OID_PKIX_AD, 1 +#define OID_PKIX_AD_OCSP_LENGTH (OID_PKIX_AD_LENGTH + 1) + +/* cAIssuers */ +#define OID_PKIX_AD_CAISSUERS OID_PKIX_AD, 2 +#define OID_PKIX_AD_CAISSUERS_LENGTH (OID_PKIX_AD_LENGTH + 1) + +/* end PKIX part1 */ +#define OID_APPL_TCP_PROTO 43, 6, 1, 2, 1, 27, 4 +#define OID_APPL_TCP_PROTO_LENGTH 8 + +#define OID_DAP OID_DS, 3, 1 +#define OID_DAP_LENGTH (OID_DS_LENGTH + 2) + +/* From x9.57 */ +#define OID_OIW_LENGTH 2 + +#define OID_OIW_SECSIG OID_OIW, 3 +#define OID_OIW_SECSIG_LENGTH (OID_OIW_LENGTH + 1) + +#define OID_OIW_ALGORITHM OID_OIW_SECSIG, 2 +#define OID_OIW_ALGORITHM_LENGTH (OID_OIW_SECSIG_LENGTH + 1) + +#define OID_OIWDIR OID_OIW, 7, 2 +#define OID_OIWDIR_LENGTH (OID_OIW_LENGTH + 2) + +#define OID_OIWDIR_CRPT OID_OIWDIR, 1 + +#define OID_OIWDIR_HASH OID_OIWDIR, 2 +#define OID_OIWDIR_HASH_LENGTH (OID_OIWDIR_LENGTH + 1) + +#define OID_OIWDIR_SIGN OID_OIWDIR, 3 +#define OID_OIWDIR_SIGN_LENGTH (OID_OIWDIR_LENGTH + 1) + +#define OID_X9CM OID_US, 206, 56 +#define OID_X9CM_MODULE OID_X9CM, 1 +#define OID_X9CM_INSTRUCTION OID_X9CM, 2 +#define OID_X9CM_ATTR OID_X9CM, 3 +#define OID_X9CM_X9ALGORITHM OID_X9CM, 4 +#define OID_X9CM_X9ALGORITHM_LENGTH ((OID_US_LENGTH) + 2 + 1) + +#define INTEL 96, 134, 72, 1, 134, 248, 77 +#define INTEL_LENGTH 7 + +#define INTEL_SEC_FORMATS INTEL_CDSASECURITY, 1 +#define INTEL_SEC_FORMATS_LENGTH (INTEL_CDSASECURITY_LENGTH + 1) + +#define INTEL_SEC_ALGS INTEL_CDSASECURITY, 2, 5 +#define INTEL_SEC_ALGS_LENGTH (INTEL_CDSASECURITY_LENGTH + 2) + +extern const KMF_OID +KMFOID_AliasedEntryName, +KMFOID_AuthorityRevocationList, +KMFOID_BusinessCategory, +KMFOID_CACertificate, +KMFOID_CertificateRevocationList, +KMFOID_ChallengePassword, +KMFOID_CollectiveFacsimileTelephoneNumber, +KMFOID_CollectiveInternationalISDNNumber, +KMFOID_CollectiveOrganizationName, +KMFOID_CollectiveOrganizationalUnitName, +KMFOID_CollectivePhysicalDeliveryOfficeName, +KMFOID_CollectivePostOfficeBox, +KMFOID_CollectivePostalAddress, +KMFOID_CollectivePostalCode, +KMFOID_CollectiveStateProvinceName, +KMFOID_CollectiveStreetAddress, +KMFOID_CollectiveTelephoneNumber, +KMFOID_CollectiveTelexNumber, +KMFOID_CollectiveTelexTerminalIdentifier, +KMFOID_CommonName, +KMFOID_ContentType, +KMFOID_CounterSignature, +KMFOID_CountryName, +KMFOID_CrossCertificatePair, +KMFOID_DNQualifier, +KMFOID_Description, +KMFOID_DestinationIndicator, +KMFOID_DistinguishedName, +KMFOID_EmailAddress, +KMFOID_EnhancedSearchGuide, +KMFOID_ExtendedCertificateAttributes, +KMFOID_ExtensionRequest, +KMFOID_FacsimileTelephoneNumber, +KMFOID_GenerationQualifier, +KMFOID_GivenName, +KMFOID_HouseIdentifier, +KMFOID_Initials, +KMFOID_InternationalISDNNumber, +KMFOID_KnowledgeInformation, +KMFOID_LocalityName, +KMFOID_Member, +KMFOID_MessageDigest, +KMFOID_Name, +KMFOID_ObjectClass, +KMFOID_OrganizationName, +KMFOID_OrganizationalUnitName, +KMFOID_Owner, +KMFOID_PhysicalDeliveryOfficeName, +KMFOID_PostOfficeBox, +KMFOID_PostalAddress, +KMFOID_PostalCode, +KMFOID_PreferredDeliveryMethod, +KMFOID_PresentationAddress, +KMFOID_ProtocolInformation, +KMFOID_RFC822mailbox, +KMFOID_RegisteredAddress, +KMFOID_RoleOccupant, +KMFOID_SearchGuide, +KMFOID_SeeAlso, +KMFOID_SerialNumber, +KMFOID_SigningTime, +KMFOID_StateProvinceName, +KMFOID_StreetAddress, +KMFOID_SupportedApplicationContext, +KMFOID_Surname, +KMFOID_TelephoneNumber, +KMFOID_TelexNumber, +KMFOID_TelexTerminalIdentifier, +KMFOID_Title, +KMFOID_UniqueIdentifier, +KMFOID_UniqueMember, +KMFOID_UnstructuredAddress, +KMFOID_UnstructuredName, +KMFOID_UserCertificate, +KMFOID_UserPassword, +KMFOID_X_121Address, +KMFOID_domainComponent, +KMFOID_userid; + +extern const KMF_OID +KMFOID_AuthorityKeyID, +KMFOID_AuthorityInfoAccess, +KMFOID_VerisignCertificatePolicy, +KMFOID_KeyUsageRestriction, +KMFOID_SubjectDirectoryAttributes, +KMFOID_SubjectKeyIdentifier, +KMFOID_KeyUsage, +KMFOID_PrivateKeyUsagePeriod, +KMFOID_SubjectAltName, +KMFOID_IssuerAltName, +KMFOID_BasicConstraints, +KMFOID_CrlNumber, +KMFOID_CrlReason, +KMFOID_HoldInstructionCode, +KMFOID_InvalidityDate, +KMFOID_DeltaCrlIndicator, +KMFOID_IssuingDistributionPoints, +KMFOID_NameConstraints, +KMFOID_CrlDistributionPoints, +KMFOID_CertificatePolicies, +KMFOID_PolicyMappings, +KMFOID_PolicyConstraints, +KMFOID_AuthorityKeyIdentifier, +KMFOID_ExtendedKeyUsage, +KMFOID_PkixAdOcsp, +KMFOID_PkixAdCaIssuers, +KMFOID_PKIX_PQ_CPSuri, +KMFOID_PKIX_PQ_Unotice, +KMFOID_PKIX_KP_ServerAuth, +KMFOID_PKIX_KP_ClientAuth, +KMFOID_PKIX_KP_CodeSigning, +KMFOID_PKIX_KP_EmailProtection, +KMFOID_PKIX_KP_IPSecEndSystem, +KMFOID_PKIX_KP_IPSecTunnel, +KMFOID_PKIX_KP_IPSecUser, +KMFOID_PKIX_KP_TimeStamping, +KMFOID_PKIX_KP_OCSPSigning; + +/* + * KMF Certificate validation codes. These may be masked together. + */ +#define KMF_CERT_VALIDATE_OK 0x00 +#define KMF_CERT_VALIDATE_ERR_TA 0x01 +#define KMF_CERT_VALIDATE_ERR_USER 0x02 +#define KMF_CERT_VALIDATE_ERR_SIGNATURE 0x04 +#define KMF_CERT_VALIDATE_ERR_KEYUSAGE 0x08 +#define KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE 0x10 +#define KMF_CERT_VALIDATE_ERR_TIME 0x20 +#define KMF_CERT_VALIDATE_ERR_CRL 0x40 +#define KMF_CERT_VALIDATE_ERR_OCSP 0x80 +#define KMF_CERT_VALIDATE_ERR_ISSUER 0x100 + +/* + * KMF Key Usage bitmasks + */ +#define KMF_digitalSignature 0x8000 +#define KMF_nonRepudiation 0x4000 +#define KMF_keyEncipherment 0x2000 +#define KMF_dataEncipherment 0x1000 +#define KMF_keyAgreement 0x0800 +#define KMF_keyCertSign 0x0400 +#define KMF_cRLSign 0x0200 +#define KMF_encipherOnly 0x0100 +#define KMF_decipherOnly 0x0080 + +#define KMF_KUBITMASK 0xFF80 + +/* + * KMF Extended KeyUsage OID definitions + */ +#define KMF_EKU_SERVERAUTH 0x01 +#define KMF_EKU_CLIENTAUTH 0x02 +#define KMF_EKU_CODESIGNING 0x04 +#define KMF_EKU_EMAIL 0x08 +#define KMF_EKU_TIMESTAMP 0x10 +#define KMF_EKU_OCSPSIGNING 0x20 + + +#ifdef __cplusplus +} +#endif +#endif /* _KMFTYPES_H */ diff --git a/usr/src/lib/libkmf/include/oidsalg.h b/usr/src/lib/libkmf/include/oidsalg.h new file mode 100644 index 0000000000..af9f5e2ead --- /dev/null +++ b/usr/src/lib/libkmf/include/oidsalg.h @@ -0,0 +1,73 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * File: oidsalg.h + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + * + */ + +#ifndef _OIDSALG_H +#define _OIDSALG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmftypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t + OID_OIW_SHA1[] = { OID_OIW_ALGORITHM, 26}, + OID_OIW_DSA[] = { OID_OIW_ALGORITHM, 12 }, + OID_OIW_DSAWithSHA1[] = { OID_OIW_ALGORITHM, 27 }, + OID_RSAEncryption[] = { OID_PKCS_1, 1 }, + OID_MD2WithRSA[] = { OID_PKCS_1, 2 }, + OID_MD5WithRSA[] = { OID_PKCS_1, 4 }, + OID_SHA1WithRSA[] = { OID_PKCS_1, 5 }, + OID_X9CM_DSA[] = { OID_X9CM_X9ALGORITHM, 1 }, + OID_X9CM_DSAWithSHA1[] = { OID_X9CM_X9ALGORITHM, 3} +; + +KMF_OID + KMFOID_SHA1 = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_SHA1}, + KMFOID_RSA = {OID_PKCS_1_LENGTH+1, OID_RSAEncryption}, + KMFOID_DSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSA}, + KMFOID_MD5WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD5WithRSA}, + KMFOID_MD2WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD2WithRSA}, + KMFOID_SHA1WithRSA = {OID_PKCS_1_LENGTH+1, OID_SHA1WithRSA}, + KMFOID_SHA1WithDSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSAWithSHA1}, + KMFOID_OIW_DSAWithSHA1 = {OID_OIW_ALGORITHM_LENGTH+1, + OID_OIW_DSAWithSHA1}, + KMFOID_X9CM_DSA = {OID_X9CM_X9ALGORITHM_LENGTH+1, OID_X9CM_DSA}, + KMFOID_X9CM_DSAWithSHA1 = {OID_X9CM_X9ALGORITHM_LENGTH+1, + OID_X9CM_DSAWithSHA1} + +; + +#ifdef __cplusplus +} +#endif +#endif /* _OIDSALG_H */ diff --git a/usr/src/lib/libkmf/include/pem_encode.h b/usr/src/lib/libkmf/include/pem_encode.h new file mode 100644 index 0000000000..7ba568d2cf --- /dev/null +++ b/usr/src/lib/libkmf/include/pem_encode.h @@ -0,0 +1,137 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _PEM_ENCODE_H +#define _PEM_ENCODE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +#define PEM_STRING_X509 "CERTIFICATE" +#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST" +#define PEM_STRING_X509_CRL "X509 CRL" +#define PEM_BUFSIZE 1024 + +/* + * 0xF0 is a EOLN + * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). + * 0xF2 is EOF + * 0xE0 is ignore at start of line. + * 0xFF is error + */ + +#define B64_EOLN 0xF0 +#define B64_CR 0xF1 +#define B64_EOF 0xF2 +#define B64_WS 0xE0 +#define B64_ERROR 0xFF +#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3) + +typedef struct pem_encode_ctx_st +{ + int num; /* number saved in a partial encode/decode */ + /* + * The length is either the output line length + * (in input bytes) or the shortest input line + * length that is ok. Once decoding begins, + * the length is adjusted up each time a longer + * line is decoded. + */ + int length; + unsigned char enc_data[80]; /* data to encode */ + int line_num; /* number read on current line */ + int expect_nl; +} PEM_ENCODE_CTX; + +KMF_RETURN +Der2Pem(KMF_OBJECT_TYPE, unsigned char *, int, unsigned char **, int *); + +KMF_RETURN +Pem2Der(unsigned char *, int, unsigned char **, int *); + +#ifdef __cplusplus +} +#endif +#endif /* _PEM_ENCODE_H */ diff --git a/usr/src/lib/libkmf/include/rdn_parser.h b/usr/src/lib/libkmf/include/rdn_parser.h new file mode 100644 index 0000000000..d94208e1b2 --- /dev/null +++ b/usr/src/lib/libkmf/include/rdn_parser.h @@ -0,0 +1,126 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _RDN_PARSER_H +#define _RDN_PARSER_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +typedef enum { + OID_AVA_COMMON_NAME = 0, + OID_AVA_SURNAME, + OID_AVA_GIVEN_NAME, + OID_AVA_LOCALITY, + OID_AVA_STATE_OR_PROVINCE, + OID_AVA_ORGANIZATION_NAME, + OID_AVA_ORGANIZATIONAL_UNIT_NAME, + OID_AVA_COUNTRY_NAME, + OID_AVA_STREET_ADDRESS, + OID_AVA_DC, + OID_RFC1274_UID, + OID_PKCS9_EMAIL_ADDRESS, + OID_RFC1274_MAIL, + OID_UNKNOWN +} OidAvaTag; + +struct NameToKind { + const char *name; + OidAvaTag kind; + KMF_OID *OID; +}; + +#define C_DOUBLE_QUOTE '\042' + +#define C_BACKSLASH '\134' + +#define C_EQUAL '=' + +#define OPTIONAL_SPACE(c) \ + (((c) == ' ') || ((c) == '\r') || ((c) == '\n')) + +#define SPECIAL_CHAR(c) \ + (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) || \ + ((c) == '\r') || ((c) == '\n') || ((c) == '+') || \ + ((c) == '<') || ((c) == '>') || ((c) == '#') || \ + ((c) == ';') || ((c) == C_BACKSLASH)) + + +#define IS_PRINTABLE(c) \ + ((((c) >= 'a') && ((c) <= 'z')) || \ + (((c) >= 'A') && ((c) <= 'Z')) || \ + (((c) >= '0') && ((c) <= '9')) || \ + ((c) == ' ') || \ + ((c) == '\'') || \ + ((c) == '\050') || /* ( */ \ + ((c) == '\051') || /* ) */ \ + (((c) >= '+') && ((c) <= '/')) || /* + , - . / */ \ + ((c) == ':') || \ + ((c) == '=') || \ + ((c) == '?')) + + +KMF_RETURN ParseDistinguishedName(char *, int, KMF_X509_NAME *); + +#ifdef __cplusplus +} +#endif +#endif /* _RDN_PARSER_H */ diff --git a/usr/src/lib/libkmf/libkmf/Makefile b/usr/src/lib/libkmf/libkmf/Makefile new file mode 100644 index 0000000000..ebc53eefb3 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/Makefile @@ -0,0 +1,51 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/libkmf/libkmf/Makefile + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/libkmf/Makefile.com b/usr/src/lib/libkmf/libkmf/Makefile.com new file mode 100644 index 0000000000..fc951c006b --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/Makefile.com @@ -0,0 +1,76 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY= libkmf.a +VERS= .1 + +OBJECTS= \ + algoid.o \ + algorithm.o \ + certgetsetop.o \ + certop.o \ + client.o \ + csrcrlop.o \ + generalop.o \ + keyop.o \ + kmfoids.o \ + pem_encode.o \ + pk11tokens.o \ + policy.o \ + pk11keys.o \ + rdn_parser.o + +BERDERLIB= -lkmfberder +BERDERLIB64= -lkmfberder + +CRYPTOUTILLIB= -lcryptoutil +CRYPTOUTILLIB64= -lcryptoutil + +include $(SRC)/lib/Makefile.lib + +SRCDIR= ../common +INCDIR= ../../include + +LIBS= $(DYNLIB) $(LINTLIB) + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +LDLIBS += $(BERDERLIB) $(CRYPTOUTILLIB) -lpkcs11 -lnsl -lsocket -lc +LDLIBS64 += $(BERDERLIB64) $(CRYPTOUTILLIB64) -lpkcs11 -lnsl -lsocket -lc + +# DYNLIB libraries do not have lint libs and are not linted +$(DYNLIB) := LDLIBS += -lxml2 +$(DYNLIB64) := LDLIBS64 += -lxml2 + +CPPFLAGS += -I$(INCDIR) -I/usr/include/libxml2 -I../../ber_der/inc -I$(SRCDIR) + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/libkmf/amd64/Makefile b/usr/src/lib/libkmf/libkmf/amd64/Makefile new file mode 100644 index 0000000000..3dfc6b7784 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/amd64/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libkmf/libkmf/common/algoid.c b/usr/src/lib/libkmf/libkmf/common/algoid.c new file mode 100644 index 0000000000..cbe2bd8f4c --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/algoid.c @@ -0,0 +1,126 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * ---------------------------------------------------------------------- + * File: algoid.c + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + * ---------------------------------------------------------------------- + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <string.h> + +#include <kmfapiP.h> +#include <oidsalg.h> + +typedef struct { + KMF_OID * AlgOID; + KMF_ALGORITHM_INDEX AlgID; +} KMF_OID_ID; + +/* + * The following table defines the mapping of AlgOID's to AlgID's. + */ +static KMF_OID_ID ALGOID_ID_Table[] = { + {&KMFOID_X9CM_DSA, KMF_ALGID_DSA}, + {&KMFOID_X9CM_DSAWithSHA1, KMF_ALGID_SHA1WithDSA}, + {&KMFOID_SHA1, KMF_ALGID_SHA1}, + {&KMFOID_RSA, KMF_ALGID_RSA}, + {&KMFOID_DSA, KMF_ALGID_DSA}, + {&KMFOID_MD5WithRSA, KMF_ALGID_MD5WithRSA}, + {&KMFOID_MD2WithRSA, KMF_ALGID_MD2WithRSA}, + {&KMFOID_SHA1WithRSA, KMF_ALGID_SHA1WithRSA}, + {&KMFOID_SHA1WithDSA, KMF_ALGID_SHA1WithDSA} +}; + +#define NUM_ALGOIDS ((sizeof (ALGOID_ID_Table))/(sizeof (ALGOID_ID_Table[0]))) + +/* + * Name: X509_AlgIdToAlgorithmOid + * + * Description: + * This function maps the specified AlgID to the corresponding + * Algorithm OID. + * + * Parameters: + * alg_int - AlgID to be mapped. + * + * Return value: + * Pointer to OID structure and NULL in case of failure. + * + */ +KMF_OID * +X509_AlgIdToAlgorithmOid(KMF_ALGORITHM_INDEX alg_int) +{ + int i; + + switch (alg_int) { + case KMF_ALGID_NONE: + return (NULL); + + default: + for (i = 0; i < NUM_ALGOIDS; i++) { + if (ALGOID_ID_Table[i].AlgID == alg_int) + return (ALGOID_ID_Table[i].AlgOID); + } + break; + } + + return (NULL); +} + +/* + * Name: X509_AlgorithmOidToAlgId + * + * Description: + * This function maps the specified Algorithm OID to the corresponding + * AlgID. + * + * Parameters: + * Oid - OID to be mapped. + * + * Return value: + * Algorithm ID and KMF_ALGID_NONE in case of failures. + */ +KMF_ALGORITHM_INDEX +X509_AlgorithmOidToAlgId(KMF_OID * Oid) +{ + int i; + + if ((Oid == NULL) || + (Oid->Data == NULL) || + (Oid->Length == 0)) { + return (KMF_ALGID_NONE); + } + + for (i = 0; i < NUM_ALGOIDS; i++) { + if (IsEqualOid(ALGOID_ID_Table[i].AlgOID, Oid)) + return (ALGOID_ID_Table[i].AlgID); + } + + return (KMF_ALGID_NONE); +} diff --git a/usr/src/lib/libkmf/libkmf/common/algorithm.c b/usr/src/lib/libkmf/libkmf/common/algorithm.c new file mode 100644 index 0000000000..fd8bfc0a2d --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/algorithm.c @@ -0,0 +1,172 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * File: algorithm.c + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapiP.h> +#include <algorithm.h> +#include <security/cryptoki.h> + +typedef struct _pkcs_key_type_map +{ + KMF_ALGORITHM_INDEX CssmAlgorithmId; + CK_KEY_TYPE ckKeyType; +} +PKCS_KEY_TYPE_MAP; + +static const PKCS_KEY_TYPE_MAP _PKCS2KMFKeyTypeMap[] = { + { KMF_ALGID_RSA, CKK_RSA }, + { KMF_ALGID_DSA, CKK_DSA } +}; + +#define SUP(_ckmech_, _kmfalg_, _kmfcls_, _kmfmode_, _multi_, \ + _fixkelen_, _keylen_, _fixblksz_, _blksz_, _reqiv_, _ivlen_,\ + _regalgflg_, _keytype_, _desc_) \ + { _ckmech_, _kmfalg_, _kmfcls_, _kmfmode_, _multi_, _fixkelen_,\ + _keylen_, _fixblksz_, _blksz_, _reqiv_, _ivlen_, _regalgflg_,\ + _keytype_, _desc_ }, + +static const PKCS_ALGORITHM_MAP _PKCS2KMFMap[] = { +/* + * PKCS #11 Mechanism, + * Alg. ID + * Alg. Class + * Alg. Mode + * Milti-Part + * Fix Key Length + * Key Length + * Fix Block Size + * Block Size + * Needs IV + * IV Length + * Alg. Flags + * Type + * Description + */ +SUP(CKM_RSA_PKCS_KEY_PAIR_GEN, KMF_ALGID_RSA, KMF_ALGCLASS_KEYGEN,\ + KMF_ALGMODE_NONE, 0, 0, 0,\ + 0, 0, 0, 0, CKF_GENERATE_KEY_PAIR,\ + CKK_RSA, "RSA PKCS #1 Key Pair Generation") +SUP(CKM_RSA_X_509, KMF_ALGID_RSA, KMF_ALGCLASS_ASYMMETRIC, KMF_ALGMODE_NONE, + 0, 0, 0, 0, 0, 0, 0, CKF_ENCRYPT, + CKK_RSA, "RSA RAW Encryption") +SUP(CKM_RSA_X_509, KMF_ALGID_RSA, KMF_ALGCLASS_ASYMMETRIC, KMF_ALGMODE_NONE, + 0, 0, 0, 0, 0, 0, 0, CKF_SIGN_RECOVER, + CKK_RSA, "RSA RAW Private Key Encryption") +SUP(CKM_RSA_X_509, KMF_ALGID_RSA, KMF_ALGCLASS_SIGNATURE, KMF_ALGMODE_NONE, + 0, 0, 0, 0, 0, 0, 0, CKF_SIGN, + CKK_RSA, "RSA RAW Signature") +SUP(CKM_RSA_PKCS, KMF_ALGID_RSA, KMF_ALGCLASS_SIGNATURE, + KMF_ALGMODE_PKCS1_EMSA_V15, + 0, 0, 0, 0, 0, 0, 0, CKF_SIGN, CKK_RSA, + "RSA PKCS #1 Signature") +SUP(CKM_MD2_RSA_PKCS, KMF_ALGID_MD2WithRSA, KMF_ALGCLASS_SIGNATURE, + KMF_ALGMODE_PKCS1_EMSA_V15, 1, 0, 0, 0, 0, + 0, 0, CKF_SIGN, CKK_RSA, "MD2 w/RSA Signature") +SUP(CKM_MD5_RSA_PKCS, KMF_ALGID_MD5WithRSA, KMF_ALGCLASS_SIGNATURE, + KMF_ALGMODE_PKCS1_EMSA_V15, 1, 0, 0, 0, 0, + 0, 0, CKF_SIGN, CKK_RSA, "MD5 w/RSA Signature") +SUP(CKM_SHA1_RSA_PKCS, KMF_ALGID_SHA1WithRSA, KMF_ALGCLASS_SIGNATURE, + KMF_ALGMODE_PKCS1_EMSA_V15, 1, 0, 0, 0, 0, + 0, 0, CKF_SIGN, CKK_RSA, "SHA-1 w/RSA Signature") + +SUP(CKM_DSA_KEY_PAIR_GEN, KMF_ALGID_DSA, KMF_ALGCLASS_KEYGEN, KMF_ALGMODE_NONE, + 0, 0, 0, 0, 0, 0, 0, + CKF_GENERATE_KEY_PAIR, CKK_DSA, "DSA Key Pair Generation") + +SUP(CKM_DSA, KMF_ALGID_DSA, KMF_ALGCLASS_SIGNATURE, KMF_ALGMODE_NONE, + 0, 0, 0, 0, 0, 0, 0, CKF_SIGN, + CKK_DSA, "DSA Signature") + +SUP(CKM_DSA_SHA1, KMF_ALGID_SHA1WithDSA, KMF_ALGCLASS_SIGNATURE, + KMF_ALGMODE_NONE, 1, 0, 0, 0, 0, 0, + 0, CKF_SIGN, CKK_DSA, "SHA-1 w/DSA Signature") + +SUP(CKM_SHA_1, KMF_ALGID_SHA1, KMF_ALGCLASS_DIGEST, KMF_ALGMODE_NONE, + 1, 1, 20, 0, 0, 0, 0, CKF_DIGEST, (CK_KEY_TYPE)-1, "SHA-1") +}; + +/* Undefine the macro definitions */ +#undef SUP + +/* Number of items in the algorithm map table */ +#define _PKCS2KMFMapCount (\ + sizeof (_PKCS2KMFMap) / sizeof (_PKCS2KMFMap[0])) + +/* Indicator that the algorithm was not found */ +#define PKCS_ALGORITHM_NOT_FOUND ((uint32_t)(~0)) + +/* + * Name: PKCSConv_GetMechanism + * + * Description: + * Searches the _PKCS2KMFMap table for a matching set of CSSM alg. + * description parameters. + * + * Parameters: + * algType (input) - KMF_ALGCLASS_* identifier to match. + * algID (input) - KMF_ALGID_* identifier to match. + * mode (input) - KMF_ALGMODE_* identifier to match. Use + * KMF_ALGMODE_NONE if a mode does not apply. + * + * Returns: + * Pointer to the lookup table entry that matches requested parameters. + * Ptr->keylength will equal PKCS11CONVERT_NOT_FOUND if no match is found. + */ +PKCS_ALGORITHM_MAP * +PKCS_GetAlgorithmMap(KMF_ALGCLASS algType, uint32_t algID, uint32_t mode) +{ + uint32_t i = 0; + + for (i = 0; i < _PKCS2KMFMapCount; i++) { + if ((_PKCS2KMFMap[i].context_type == algType) && + (_PKCS2KMFMap[i].algorithm == algID) && + (_PKCS2KMFMap[i].enc_mode == mode)) { + return ((PKCS_ALGORITHM_MAP *)&(_PKCS2KMFMap[i])); + } + } + + return (NULL); +} + +KMF_BOOL +PKCS_ConvertAlgorithmId2PKCSKeyType(KMF_ALGORITHM_INDEX AlgId, + CK_KEY_TYPE *pckKeyType) +{ + uint32_t uIndex; + uint32_t uMapSize = sizeof (_PKCS2KMFKeyTypeMap) / + sizeof (PKCS_KEY_TYPE_MAP); + + for (uIndex = 0; uIndex < uMapSize; uIndex++) { + if (_PKCS2KMFKeyTypeMap[uIndex].CssmAlgorithmId == AlgId) { + *pckKeyType = _PKCS2KMFKeyTypeMap[uIndex].ckKeyType; + return (1); + } + } + + return (0); +} diff --git a/usr/src/lib/libkmf/libkmf/common/certgetsetop.c b/usr/src/lib/libkmf/libkmf/common/certgetsetop.c new file mode 100644 index 0000000000..15b490b6f7 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/certgetsetop.c @@ -0,0 +1,2300 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright(c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <link.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ber_der.h> +#include <kmfapiP.h> +#include <libgen.h> +#include <cryptoutil.h> + +KMF_RETURN +copy_data(KMF_DATA *dst, KMF_DATA *src) +{ + KMF_RETURN ret = KMF_OK; + + if (dst == NULL || src == NULL) + return (KMF_ERR_BAD_PARAMETER); + + dst->Data = malloc(src->Length); + if (dst->Data == NULL) + return (KMF_ERR_MEMORY); + + dst->Length = src->Length; + (void) memcpy(dst->Data, src->Data, src->Length); + + return (ret); +} + +static KMF_RETURN +copy_extension_data(KMF_X509_EXTENSION *dstext, + KMF_X509_EXTENSION *srcext) +{ + KMF_RETURN ret = KMF_OK; + + if (dstext == NULL || srcext == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(dstext, 0, sizeof (KMF_X509_EXTENSION)); + + ret = copy_data(&dstext->extnId, &srcext->extnId); + if (ret != KMF_OK) + goto cleanup; + + dstext->extnId.Length = srcext->extnId.Length; + dstext->critical = srcext->critical; + dstext->format = srcext->format; + + ret = copy_data(&dstext->BERvalue, &srcext->BERvalue); + if (ret != KMF_OK) + goto cleanup; + + dstext->value.tagAndValue = malloc(sizeof (KMF_X509EXT_TAGandVALUE)); + if (dstext->value.tagAndValue == NULL) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + (void) memset(dstext->value.tagAndValue, 0, + sizeof (KMF_X509EXT_TAGandVALUE)); + + ret = copy_data(&dstext->value.tagAndValue->value, + &srcext->value.tagAndValue->value); + if (ret != KMF_OK) + goto cleanup; + + dstext->value.tagAndValue->type = srcext->value.tagAndValue->type; + +cleanup: + if (ret != KMF_OK) { + if (dstext->extnId.Data != NULL) + KMF_FreeData(&dstext->extnId); + + if (dstext->BERvalue.Data != NULL) + KMF_FreeData(&dstext->BERvalue); + + if (dstext->value.tagAndValue->value.Data == NULL) + KMF_FreeData(&dstext->value.tagAndValue->value); + } + + return (ret); +} + +/* + * Given a block of DER encoded X.509 certificate data and + * an OID for the desired extension, this routine will + * parse the cert data and return the data associated with + * the extension if it is found. + * + * RETURNS: + * KMF_OK - if extension found and copied OK. + * KMF_ERR_EXTENSION_NOT_FOUND - extension not found. + * parsing and memory allocation errors are also possible. + */ +KMF_RETURN +KMF_GetCertExtensionData(const KMF_DATA *certdata, + KMF_OID *extoid, KMF_X509_EXTENSION *extdata) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *cert = NULL; + KMF_X509_EXTENSION *eptr = NULL; + int i, found = 0; + + if (certdata == NULL || extoid == NULL || extdata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = DerDecodeSignedCertificate(certdata, &cert); + if (ret != KMF_OK) + return (ret); + + if (cert->certificate.extensions.numberOfExtensions == 0) + return (KMF_ERR_EXTENSION_NOT_FOUND); + + (void) memset((void *)extdata, 0, sizeof (KMF_X509_EXTENSION)); + for (i = 0; !found && + i < cert->certificate.extensions.numberOfExtensions; + i++) { + eptr = &cert->certificate.extensions.extensions[i]; + if (IsEqualOid(extoid, &eptr->extnId)) { + ret = copy_extension_data(extdata, eptr); + found++; + } + } + if (!found) + ret = KMF_ERR_EXTENSION_NOT_FOUND; + + if (cert != NULL) { + KMF_FreeSignedCert(cert); + free(cert); + } + + return (ret); +} + +/* + * Given a block of DER encoded X.509 certificate data, + * search the extensions and return the OIDs for all + * extensions marked "critical". + * + * + * RETURNS: + * KMF_OK - if extension found and copied OK. + * parsing and memory allocation errors are also possible. + * + * OIDlist - array of KMF_OID records, allocated + * by this function. + * NumOIDs - number of critical extensions found. + */ +KMF_RETURN +KMF_GetCertCriticalExtensions(const KMF_DATA *certdata, + KMF_X509_EXTENSION **extlist, int *nextns) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *cert; + KMF_X509_EXTENSION *eptr, *elist; + int i; + + if (certdata == NULL || extlist == NULL || nextns == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *nextns = 0; + *extlist = elist = NULL; + ret = DerDecodeSignedCertificate(certdata, &cert); + if (ret != KMF_OK) + return (ret); + + if (cert->certificate.extensions.numberOfExtensions == 0) + return (KMF_ERR_EXTENSION_NOT_FOUND); + + for (i = 0; i < cert->certificate.extensions.numberOfExtensions; + i++) { + eptr = &cert->certificate.extensions.extensions[i]; + if (eptr->critical != 0) { + (*nextns)++; + elist = realloc(elist, sizeof (KMF_X509_EXTENSION) * + (*nextns)); + if (elist == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + ret = copy_extension_data(&elist[(*nextns) - 1], + eptr); + if (ret != KMF_OK) + goto end; + } + } +end: + KMF_FreeSignedCert(cert); + free(cert); + if (ret != KMF_OK) { + if (elist != NULL) { + free(elist); + elist = NULL; + } + *nextns = 0; + } + *extlist = elist; + + return (ret); +} + +/* + * Given a block of DER encoded X.509 certificate data, + * search the extensions and return the OIDs for all + * extensions NOT marked "critical". + * + * + * RETURNS: + * KMF_OK - if extension found and copied OK. + * parsing and memory allocation errors are also possible. + * + * OIDlist - array of KMF_OID records, allocated + * by this function. + * NumOIDs - number of critical extensions found. + */ +KMF_RETURN +KMF_GetCertNonCriticalExtensions(const KMF_DATA *certdata, + KMF_X509_EXTENSION **extlist, int *nextns) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *cert; + KMF_X509_EXTENSION *eptr, *elist; + int i; + + if (certdata == NULL || extlist == NULL || nextns == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *nextns = 0; + *extlist = elist = NULL; + ret = DerDecodeSignedCertificate(certdata, &cert); + if (ret != KMF_OK) + return (ret); + + if (cert->certificate.extensions.numberOfExtensions == 0) + return (KMF_ERR_EXTENSION_NOT_FOUND); + + for (i = 0; i < cert->certificate.extensions.numberOfExtensions; + i++) { + eptr = &cert->certificate.extensions.extensions[i]; + if (eptr->critical == 0) { + (*nextns)++; + elist = realloc(elist, sizeof (KMF_X509_EXTENSION) * + (*nextns)); + if (elist == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + ret = copy_extension_data(&elist[(*nextns) - 1], + eptr); + if (ret != KMF_OK) + goto end; + } + } +end: + KMF_FreeSignedCert(cert); + free(cert); + if (ret != KMF_OK) { + if (elist != NULL) { + free(elist); + elist = NULL; + } + *nextns = 0; + } + *extlist = elist; + + return (ret); +} + +/* + * If the given certificate data (X.509 DER encoded data) + * contains the Key Usage extension, parse that + * data and return it in the KMF_X509EXT_BASICCONSTRAINTS + * record. + * + * RETURNS: + * KMF_OK - success + * KMF_ERR_BAD_PARAMETER - input data was bad. + * KMF_ERR_EXTENSION_NOT_FOUND - extension not found. + */ +KMF_RETURN +KMF_GetCertKeyUsageExt(const KMF_DATA *certdata, + KMF_X509EXT_KEY_USAGE *keyusage) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + + if (certdata == NULL || keyusage == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&extn, 0, sizeof (extn)); + /* + * Check standard KeyUsage bits + */ + ret = KMF_GetCertExtensionData(certdata, + (KMF_OID *)&KMFOID_KeyUsage, &extn); + + if (ret != KMF_OK) { + goto end; + } + keyusage->critical = (extn.critical != 0); + if (extn.value.tagAndValue->value.Length > 1) { + keyusage->KeyUsageBits = + extn.value.tagAndValue->value.Data[1] << 8; + } else { + keyusage->KeyUsageBits = + extn.value.tagAndValue->value.Data[0]; + } +end: + KMF_FreeExtension(&extn); + return (ret); +} + +static KMF_BOOL +isEKUPresent(KMF_X509EXT_EKU *ekuptr, KMF_OID *ekuoid) +{ + int i; + + if (ekuptr == NULL || ekuoid == NULL) + return (0); + + for (i = 0; i < ekuptr->nEKUs; i++) + if (IsEqualOid(&ekuptr->keyPurposeIdList[i], ekuoid)) + return (1); + + return (0); +} + +static KMF_RETURN +parse_eku_data(const KMF_DATA *asn1data, KMF_X509EXT_EKU *ekuptr) +{ + KMF_RETURN ret = KMF_OK; + BerElement *asn1 = NULL; + BerValue exdata; + KMF_OID oid; + char *end = NULL; + ber_len_t size; + + /* + * Decode the ASN.1 data for the extension. + */ + exdata.bv_val = (char *)asn1data->Data; + exdata.bv_len = asn1data->Length; + + if ((asn1 = kmfder_init(&exdata)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + /* + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + */ + if (kmfber_first_element(asn1, &size, &end) != + BER_OBJECT_IDENTIFIER) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + /* + * Count the number of EKU OIDs and store in + * the array. + */ + while (kmfber_next_element(asn1, &size, end) == + BER_OBJECT_IDENTIFIER) { + + /* Skip over the CONSTRUCTED SET tag */ + if (kmfber_scanf(asn1, "D", &oid) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + ekuptr->nEKUs++; + ekuptr->keyPurposeIdList = realloc(ekuptr->keyPurposeIdList, + ekuptr->nEKUs * sizeof (KMF_OID)); + if (ekuptr->keyPurposeIdList == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + ekuptr->keyPurposeIdList[ekuptr->nEKUs - 1] = oid; + } + +end: + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (ret != KMF_OK) { + if (ekuptr->keyPurposeIdList != NULL) { + free_keyidlist(ekuptr->keyPurposeIdList, ekuptr->nEKUs); + ekuptr->keyPurposeIdList = NULL; + ekuptr->critical = 0; + } + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertEKU(const KMF_DATA *certdata, + KMF_X509EXT_EKU *ekuptr) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + + if (certdata == NULL || ekuptr == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION)); + + ekuptr->nEKUs = 0; + ekuptr->keyPurposeIdList = NULL; + ekuptr->critical = 0; + + ret = KMF_GetCertExtensionData(certdata, + (KMF_OID *)&KMFOID_ExtendedKeyUsage, &extn); + + if (ret != KMF_OK) { + goto end; + } + + ret = parse_eku_data(&extn.BERvalue, ekuptr); + +end: + KMF_FreeExtension(&extn); + + return (ret); +} + +/* + * If the given certificate data (X.509 DER encoded data) + * contains the Basic Constraints extension, parse that + * data and return it in the KMF_X509EXT_BASICCONSTRAINTS + * record. + * + * RETURNS: + * KMF_OK - success + * KMF_ERR_BAD_PARAMETER - input data was bad. + * KMF_ERR_EXTENSION_NOT_FOUND - extension not found. + */ +KMF_RETURN +KMF_GetCertBasicConstraintExt(const KMF_DATA *certdata, + KMF_BOOL *critical, KMF_X509EXT_BASICCONSTRAINTS *constraint) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + BerElement *asn1 = NULL; + BerValue exdata; + ber_len_t size; + char *end = NULL; + int tag; + + if (certdata == NULL || constraint == NULL || critical == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION)); + ret = KMF_GetCertExtensionData(certdata, + (KMF_OID *)&KMFOID_BasicConstraints, &extn); + + if (ret != KMF_OK) { + goto end; + } + + *critical = (extn.critical != 0); + + exdata.bv_val = (char *)extn.value.tagAndValue->value.Data; + exdata.bv_len = extn.value.tagAndValue->value.Length; + + if ((asn1 = kmfder_init(&exdata)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + if (kmfber_scanf(asn1, "b", &constraint->cA) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + constraint->pathLenConstraintPresent = KMF_FALSE; + + tag = kmfber_next_element(asn1, &size, end); + if (tag == BER_INTEGER) { + if (kmfber_scanf(asn1, "i", + &constraint->pathLenConstraint) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + constraint->pathLenConstraintPresent = KMF_TRUE; + } +end: + KMF_FreeExtension(&extn); + if (asn1 != NULL) + kmfber_free(asn1, 1); + + return (ret); +} + +static KMF_X509EXT_POLICYQUALIFIERINFO * +get_pqinfo(BerElement *asn1) +{ + KMF_X509EXT_POLICYQUALIFIERINFO *pqinfo = NULL; + KMF_RETURN ret = KMF_OK; + int tag; + ber_len_t size; + char *end = NULL; + + /* + * Policy Qualifiers may be a list of sequences. + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL + * } + * + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId + * } + */ + + + /* + * We already got the CertPolicyId, we just need to + * find all of the policyQualifiers in the set. + * + * Mark the first element of the SEQUENCE and reset the end ptr + * so the ber/der code knows when to stop looking. + */ + if ((tag = kmfber_first_element(asn1, &size, &end)) != + BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* We found a sequence, loop until done */ + while ((tag = kmfber_next_element(asn1, &size, end)) == + BER_CONSTRUCTED_SEQUENCE) { + + /* Skip over the CONSTRUCTED SET tag */ + if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* + * Allocate memory for the Policy Qualifier Info + */ + pqinfo = malloc(sizeof (KMF_X509EXT_POLICYQUALIFIERINFO)); + if (pqinfo == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + (void) memset((void *)pqinfo, 0, + sizeof (KMF_X509EXT_POLICYQUALIFIERINFO)); + /* + * Read the PolicyQualifier OID + */ + if (kmfber_scanf(asn1, "D", + &pqinfo->policyQualifierId) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* + * The OID of the policyQualifierId determines what + * sort of data comes next. + */ + if (IsEqualOid(&pqinfo->policyQualifierId, + (KMF_OID *)&KMFOID_PKIX_PQ_CPSuri)) { + /* + * CPS uri must be an IA5STRING + */ + if (kmfber_scanf(asn1, "tl", &tag, &size) == + KMFBER_DEFAULT || tag != BER_IA5STRING || + size == 0) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + if ((pqinfo->value.Data = malloc(size)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + if (kmfber_scanf(asn1, "s", pqinfo->value.Data, + &pqinfo->value.Length) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + } else if (IsEqualOid(&pqinfo->policyQualifierId, + (KMF_OID *)&KMFOID_PKIX_PQ_Unotice)) { + if (kmfber_scanf(asn1, "tl", &tag, &size) == + KMFBER_DEFAULT || + tag != BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* + * For now, just copy the while UserNotice ASN.1 + * blob into the pqinfo data record. + * TBD - parse it into individual fields. + */ + if ((pqinfo->value.Data = malloc(size)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + if (kmfber_scanf(asn1, "s", pqinfo->value.Data, + &pqinfo->value.Length) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + } else { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + } +end: + if (ret != KMF_OK) { + if (pqinfo != NULL) { + KMF_FreeData(&pqinfo->value); + KMF_FreeData(&pqinfo->policyQualifierId); + free(pqinfo); + pqinfo = NULL; + } + } + return (pqinfo); +} + +/* + * If the given certificate data (X.509 DER encoded data) + * contains the Certificate Policies extension, parse that + * data and return it in the KMF_X509EXT_CERT_POLICIES + * record. + * + * RETURNS: + * KMF_OK - success + * KMF_ERR_BAD_PARAMETER - input data was bad. + * KMF_ERR_EXTENSION_NOT_FOUND - extension not found. + * parsing and memory allocation errors are also possible. + */ +KMF_RETURN +KMF_GetCertPoliciesExt(const KMF_DATA *certdata, + KMF_BOOL *critical, KMF_X509EXT_CERT_POLICIES *extptr) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + KMF_X509EXT_POLICYINFO *pinfo; + KMF_X509EXT_POLICYQUALIFIERINFO *pqinfo; + BerElement *asn1 = NULL; + BerValue exdata; + ber_len_t size; + char *end = NULL; + int tag; + + if (certdata == NULL || critical == NULL || extptr == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&extn, 0, sizeof (extn)); + ret = KMF_GetCertExtensionData(certdata, + (KMF_OID *)&KMFOID_CertificatePolicies, &extn); + + if (ret != KMF_OK) { + goto end; + } + + *critical = (extn.critical != 0); + + /* + * Decode the ASN.1 data for the extension. + */ + exdata.bv_val = (char *)extn.BERvalue.Data; + exdata.bv_len = extn.BERvalue.Length; + + (void) memset((void *)extptr, 0, sizeof (KMF_X509EXT_CERT_POLICIES)); + + if ((asn1 = kmfder_init(&exdata)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + /* + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + */ + if ((tag = kmfber_first_element(asn1, &size, &end)) != + BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + /* + * Collect all of the PolicyInformation SEQUENCES + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL + * } + * + * Loop over the SEQUENCES of PolicyInfo + */ + while ((tag = kmfber_next_element(asn1, &size, end)) == + BER_CONSTRUCTED_SEQUENCE) { + + /* Skip over the CONSTRUCTED SET tag */ + if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + pinfo = malloc(sizeof (KMF_X509EXT_POLICYINFO)); + if (pinfo == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + (void) memset((void *)pinfo, 0, + sizeof (KMF_X509EXT_POLICYINFO)); + /* + * Decode the PolicyInformation SEQUENCE + */ + if ((tag = kmfber_scanf(asn1, "D", + &pinfo->policyIdentifier)) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* + * Gather all of the associated PolicyQualifierInfo recs + */ + pqinfo = get_pqinfo(asn1); + if (pqinfo != NULL) { + int cnt = + pinfo->policyQualifiers.numberOfPolicyQualifiers; + cnt++; + pinfo->policyQualifiers.policyQualifier = realloc( + pinfo->policyQualifiers.policyQualifier, + cnt * sizeof (KMF_X509EXT_POLICYQUALIFIERINFO)); + if (pinfo->policyQualifiers.policyQualifier == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + pinfo->policyQualifiers.numberOfPolicyQualifiers = + cnt; + pinfo->policyQualifiers.policyQualifier[cnt-1] = + *pqinfo; + + free(pqinfo); + } + extptr->numberOfPolicyInfo++; + extptr->policyInfo = realloc(extptr->policyInfo, + extptr->numberOfPolicyInfo * + sizeof (KMF_X509EXT_POLICYINFO)); + if (extptr->policyInfo == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + extptr->policyInfo[extptr->numberOfPolicyInfo-1] = *pinfo; + free(pinfo); + } + + +end: + KMF_FreeExtension(&extn); + if (asn1 != NULL) + kmfber_free(asn1, 1); + return (ret); +} + +/* + * If the given certificate data (X.509 DER encoded data) + * contains the Authority Information Access extension, parse that + * data and return it in the KMF_X509EXT_AUTHINFOACCESS + * record. + * + * RETURNS: + * KMF_OK - success + * KMF_ERR_BAD_PARAMETER - input data was bad. + * KMF_ERR_EXTENSION_NOT_FOUND - extension not found. + */ +KMF_RETURN +KMF_GetCertAuthInfoAccessExt(const KMF_DATA *certdata, + KMF_X509EXT_AUTHINFOACCESS *aia) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + BerElement *asn1 = NULL; + BerValue exdata; + ber_len_t size; + char *end = NULL; + int tag; + KMF_X509EXT_ACCESSDESC *access_info = NULL; + + if (certdata == NULL || aia == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION)); + ret = KMF_GetCertExtensionData(certdata, + (KMF_OID *)&KMFOID_AuthorityInfoAccess, &extn); + + if (ret != KMF_OK) { + goto end; + } + + /* + * Decode the ASN.1 data for the extension. + */ + exdata.bv_val = (char *)extn.BERvalue.Data; + exdata.bv_len = extn.BERvalue.Length; + + (void) memset((void *)aia, 0, sizeof (KMF_X509EXT_AUTHINFOACCESS)); + + if ((asn1 = kmfder_init(&exdata)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + /* + * AuthorityInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + */ + if ((tag = kmfber_first_element(asn1, &size, &end)) != + BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + /* + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + */ + while ((tag = kmfber_next_element(asn1, &size, end)) == + BER_CONSTRUCTED_SEQUENCE) { + + /* Skip over the CONSTRUCTED SET tag */ + if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + access_info = malloc(sizeof (KMF_X509EXT_ACCESSDESC)); + if (access_info == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + (void) memset((void *)access_info, 0, + sizeof (KMF_X509EXT_ACCESSDESC)); + + /* + * Read the AccessMethod OID + */ + if (kmfber_scanf(asn1, "D", + &access_info->AccessMethod) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + /* + * The OID of the AccessMethod determines what + * sort of data comes next. + */ + if (IsEqualOid(&access_info->AccessMethod, + (KMF_OID *)&KMFOID_PkixAdOcsp)) { + if (kmfber_scanf(asn1, "tl", &tag, &size) == + KMFBER_DEFAULT || size == 0) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + /* + * OCSP uri must be an IA5STRING or a GENNAME_URI + * with an implicit tag. + */ + if (tag != BER_IA5STRING && + tag != (0x80 | GENNAME_URI)) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + if ((access_info->AccessLocation.Data = + malloc(size)) == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + if (kmfber_scanf(asn1, "s", + access_info->AccessLocation.Data, + &access_info->AccessLocation.Length) == + KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + } else if (IsEqualOid(&access_info->AccessMethod, + (KMF_OID *)&KMFOID_PkixAdCaIssuers)) { + /* will be supported later with PKIX */ + free(access_info); + access_info = NULL; + continue; + } else { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + aia->numberOfAccessDescription++; + aia->AccessDesc = realloc(aia->AccessDesc, + aia->numberOfAccessDescription * + sizeof (KMF_X509EXT_ACCESSDESC)); + + if (aia->AccessDesc == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + aia->AccessDesc[aia->numberOfAccessDescription-1] = + *access_info; + free(access_info); + access_info = NULL; + } + +end: + KMF_FreeExtension(&extn); + if (access_info != NULL) + free(access_info); + if (asn1 != NULL) + kmfber_free(asn1, 1); + return (ret); + +} + +/* + * This function parses the name portion of a der-encoded distribution point + * returns it in the KMF_CRL_DIST_POINT record. + * + * The "DistributionPointName" syntax is + * + * DistributionPointName ::= CHOICE { + * fullName [0] GeneralNames, + * nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GerneralName + * + * Note: for phase 1, we support fullName only. + */ +static KMF_RETURN +parse_dp_name(char *dp_der_code, int dp_der_size, KMF_CRL_DIST_POINT *dp) +{ + KMF_RETURN ret = KMF_OK; + char *url = NULL; + BerElement *asn1 = NULL; + BerValue ber_data; + ber_len_t size; + char *end = NULL; + int tag; + KMF_GENERALNAMES *fullname; + + if (dp_der_code == NULL || dp_der_size == 0 || dp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ber_data.bv_val = dp_der_code; + ber_data.bv_len = dp_der_size; + if ((asn1 = kmfder_init(&ber_data)) == NULL) + return (KMF_ERR_BAD_CERT_FORMAT); + + tag = kmfber_first_element(asn1, &size, &end); + if (tag != 0xA0 && tag != 0xA1) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + if (tag == 0xA0) { /* fullName */ + dp->type = DP_GENERAL_NAME; + + fullname = &(dp->name.full_name); + fullname->number = 0; + + /* Skip over the explicit tag and size */ + (void) kmfber_scanf(asn1, "T", &tag); + + tag = kmfber_next_element(asn1, &size, end); + while (tag != KMFBER_DEFAULT && + tag != KMFBER_END_OF_SEQORSET) { + + if (kmfber_scanf(asn1, "tl", &tag, &size) == + KMFBER_DEFAULT || size == 0) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + /* For phase 1, we are interested in a URI name only */ + if (tag != (0x80 | GENNAME_URI)) { + tag = kmfber_next_element(asn1, &size, end); + continue; + } + + if ((url = malloc(size)) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + /* Skip type and len, then read url and save it. */ + if (kmfber_read(asn1, url, 2) != 2) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + if (kmfber_read(asn1, url, size) != + (ber_slen_t)size) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + fullname->number++; + fullname->namelist = realloc(fullname->namelist, + fullname->number * sizeof (KMF_GENERALNAME)); + if (fullname->namelist == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + fullname->namelist[fullname->number - 1].choice = + GENNAME_URI; + fullname->namelist[fullname->number - 1].name.Length = + size; + fullname->namelist[fullname->number - 1].name.Data = + (unsigned char *)url; + + /* next */ + tag = kmfber_next_element(asn1, &size, end); + } + + } else if (tag == 0xA1) { + /* "nameRelativeToCRLIssuer" is not supported at phase 1. */ + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + +out: + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (ret != KMF_OK) { + free_dp_name(dp); + } + + if (ret == KMF_OK && fullname->number == 0) { + ret = KMF_ERR_EXTENSION_NOT_FOUND; + if (url != NULL) + free(url); + } + + return (ret); +} + +/* + * This function retrieves the CRL Distribution Points extension data from + * a DER encoded certificate if it contains this extension, parses the + * extension data, and returns it in the KMF_X509EXT_CRLDISTPOINTS record. + */ +KMF_RETURN +KMF_GetCertCRLDistributionPointsExt(const KMF_DATA *certdata, + KMF_X509EXT_CRLDISTPOINTS *crl_dps) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + BerElement *asn1 = NULL; + BerValue exdata; + ber_len_t size; + char *end = NULL; + int tag; + KMF_CRL_DIST_POINT *dp = NULL; + int i; + + if (certdata == NULL || crl_dps == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* Get the ASN.1 data for this extension. */ + (void) memset(&extn, 0, sizeof (KMF_X509_EXTENSION)); + ret = KMF_GetCertExtensionData(certdata, + (KMF_OID *)&KMFOID_CrlDistributionPoints, &extn); + if (ret != KMF_OK) { + return (ret); + } + + /* + * Decode the CRLDistributionPoints ASN.1 data. The Syntax for + * CRLDistributionPoints is + * + * CRLDistributionPoints ::= + * SEQUENCE SIZE (1..MAX) OF DistributionPoint + * + * DistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * reasons [1] ReasonFlags OPTIONAL, + * cRLIssuer [2] GeneralNames OPTIONAL } + */ + + exdata.bv_val = (char *)extn.BERvalue.Data; + exdata.bv_len = extn.BERvalue.Length; + if ((asn1 = kmfder_init(&exdata)) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + if ((tag = kmfber_first_element(asn1, &size, &end)) != + BER_CONSTRUCTED_SEQUENCE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + (void) memset((void *)crl_dps, 0, sizeof (KMF_X509EXT_CRLDISTPOINTS)); + + while ((tag = kmfber_next_element(asn1, &size, end)) == + BER_CONSTRUCTED_SEQUENCE) { + boolean_t has_name = B_FALSE; + boolean_t has_issuer = B_FALSE; + + /* Skip over the CONSTRUCTED SET tag */ + if (kmfber_scanf(asn1, "T", &tag) == KMFBER_DEFAULT) { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + tag = kmfber_next_element(asn1, &size, end); + if (tag != 0xA0 && tag != 0xA1 && tag != 0xA2) + goto out; + + if ((dp = malloc(sizeof (KMF_CRL_DIST_POINT))) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memset((void *)dp, 0, sizeof (KMF_CRL_DIST_POINT)); + + if (tag == 0xA0) { /* distributionPoint Name */ + char *name_der; + int name_size = size + 2; + + if ((name_der = malloc(name_size)) == NULL) { + ret = KMF_ERR_MEMORY; + free(dp); + dp = NULL; + goto out; + } + + if (kmfber_read(asn1, name_der, name_size) != + (ber_slen_t)(name_size)) { + ret = KMF_ERR_BAD_CERT_FORMAT; + free(name_der); + free(dp); + dp = NULL; + goto out; + } + has_name = B_TRUE; + + ret = parse_dp_name(name_der, name_size, dp); + free(name_der); + if (ret != KMF_OK) { + free(dp); + dp = NULL; + goto out; + } + + /* next field */ + tag = kmfber_next_element(asn1, &size, end); + } + + if (tag == 0XA1) { /* reasons */ + char *bit_string; + int len; + + if (kmfber_scanf(asn1, "B", &bit_string, &len) != + BER_BIT_STRING) { + ret = KMF_ERR_BAD_CERT_FORMAT; + free(dp); + dp = NULL; + goto out; + } + + dp->reasons.Length = len / 8; + if ((dp->reasons.Data = malloc(dp->reasons.Length)) == + NULL) { + ret = KMF_ERR_MEMORY; + free(dp); + dp = NULL; + goto out; + } + (void) memcpy(dp->reasons.Data, (uchar_t *)bit_string, + dp->reasons.Length); + + /* next field */ + tag = kmfber_next_element(asn1, &size, end); + } + + if (tag == 0XA2) { /* cRLIssuer */ + char *issuer_der = NULL; + int issuer_size; + + /* For cRLIssuer, read the data only at phase 1 */ + issuer_size = size + 2; + issuer_der = malloc(issuer_size); + if (issuer_der == NULL) { + ret = KMF_ERR_MEMORY; + free(dp); + dp = NULL; + goto out; + } + + if (kmfber_read(asn1, issuer_der, issuer_size) != + (ber_slen_t)(issuer_size)) { + free(issuer_der); + ret = KMF_ERR_BAD_CERT_FORMAT; + free(dp); + dp = NULL; + goto out; + } + + has_issuer = B_TRUE; + free(issuer_der); + } + + /* A distribution point cannot have a "reasons" field only. */ + if (has_name == B_FALSE && has_issuer == B_FALSE) { + ret = KMF_ERR_BAD_CERT_FORMAT; + free_dp(dp); + free(dp); + dp = NULL; + goto out; + } + + /* + * Although it is legal that a distributioon point contains + * a cRLIssuer field only, with or without "reasons", we will + * skip it if the name field is not presented for phase 1. + */ + if (has_name == B_FALSE) { + free_dp(dp); + } else { + crl_dps->number++; + crl_dps->dplist = realloc(crl_dps->dplist, + crl_dps->number * sizeof (KMF_CRL_DIST_POINT)); + if (crl_dps->dplist == NULL) { + ret = KMF_ERR_MEMORY; + free_dp(dp); + free(dp); + dp = NULL; + goto out; + } + crl_dps->dplist[crl_dps->number - 1] = *dp; + /* free the dp itself since we just used its contents */ + } + if (dp != NULL) { + free(dp); + dp = NULL; + } + } + +out: + KMF_FreeExtension(&extn); + + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (ret != KMF_OK) { + for (i = 0; i < crl_dps->number; i++) + free_dp(&(crl_dps->dplist[i])); + free(crl_dps->dplist); + } + + if (ret == KMF_OK && crl_dps->number == 0) { + ret = KMF_ERR_BAD_CERT_FORMAT; + } + + return (ret); +} + +static KMF_RETURN +KMF_CertGetPrintable(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + KMF_PRINTABLE_ITEM flag, char *resultStr) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*getPrintableFn)(void *, const KMF_DATA *, + KMF_PRINTABLE_ITEM, char *); + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || + resultStr == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * This framework function is actually implemented in the openssl + * plugin library, so we find the function address and call it. + */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + getPrintableFn = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_CertGetPrintable"); + if (getPrintableFn == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (getPrintableFn(handle, SignedCert, flag, resultStr)); +} + +KMF_RETURN +KMF_GetCertVersionString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_VERSION, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertSubjectNameString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_SUBJECT, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); + +} + +KMF_RETURN +KMF_GetCertIssuerNameString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_ISSUER, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertSerialNumberString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_SERIALNUM, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertStartDateString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_NOTBEFORE, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertEndDateString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_NOTAFTER, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertPubKeyAlgString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_PUBKEY_ALG, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertSignatureAlgString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_SIGNATURE_ALG, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertPubKeyDataString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_PUBKEY_DATA, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertEmailString(KMF_HANDLE_T handle, const KMF_DATA *SignedCert, + char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignedCert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, SignedCert, KMF_CERT_EMAIL, + tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +/* + * Given a certificate (DER Encoded data) and a KMF + * extension identifier constant (e.g. KMF_X509_EXT_*), + * return a human readable interpretation of the + * extension data. + * + * The string will be a maximum of KMF_CERT_PRINTABLE_LEN + * bytes long. The string is allocated locally and + * must be freed by the caller. + */ +KMF_RETURN +KMF_GetCertExtensionString(KMF_HANDLE_T handle, const KMF_DATA *cert, + KMF_PRINTABLE_ITEM extension, char **result) +{ + KMF_RETURN ret; + char *tmpstr; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (cert == NULL || result == NULL) + return (KMF_ERR_BAD_PARAMETER); + + tmpstr = malloc(KMF_CERT_PRINTABLE_LEN); + if (tmpstr == NULL) + return (KMF_ERR_MEMORY); + (void) memset(tmpstr, 0, KMF_CERT_PRINTABLE_LEN); + + ret = KMF_CertGetPrintable(handle, cert, extension, tmpstr); + + if (ret == KMF_OK) { + *result = tmpstr; + } else { + free(tmpstr); + *result = NULL; + } + + return (ret); +} + +KMF_RETURN +KMF_GetCertIDData(const KMF_DATA *SignedCert, KMF_DATA *ID) +{ + KMF_RETURN ret; + KMF_X509_CERTIFICATE *cert = NULL; + + if (SignedCert == NULL || ID == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = DerDecodeSignedCertificate(SignedCert, &cert); + if (ret != KMF_OK) + return (ret); + + ret = GetIDFromSPKI(&cert->certificate.subjectPublicKeyInfo, ID); + + KMF_FreeSignedCert(cert); + free(cert); + return (ret); +} + +KMF_RETURN +KMF_GetCertIDString(const KMF_DATA *SignedCert, + char **idstr) +{ + KMF_RETURN ret; + KMF_DATA ID = {NULL, 0}; + char tmpstr[256]; + int i; + + if (SignedCert == NULL || idstr == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = KMF_GetCertIDData(SignedCert, &ID); + if (ret != KMF_OK) { + KMF_FreeData(&ID); + return (ret); + } + + (void) memset(tmpstr, 0, sizeof (tmpstr)); + for (i = 0; i < ID.Length; i++) { + int len = strlen(tmpstr); + (void) snprintf(&tmpstr[len], sizeof (tmpstr) - len, + "%02x", (uchar_t)ID.Data[i]); + if ((i+1) < ID.Length) + (void) strcat(tmpstr, ":"); + } + *idstr = strdup(tmpstr); + if ((*idstr) == NULL) + ret = KMF_ERR_MEMORY; + + KMF_FreeData(&ID); + + return (ret); +} + +/* + * This function gets the time_t values of the notbefore and notafter dates + * from a der-encoded certificate. + */ +KMF_RETURN +KMF_GetCertValidity(const KMF_DATA *cert, time_t *not_before, + time_t *not_after) +{ + KMF_RETURN rv = KMF_OK; + KMF_X509_CERTIFICATE *certData = NULL; + struct tm tm_tmp; + time_t t_notbefore; + time_t t_notafter; + unsigned char *not_before_str; + unsigned char *not_after_str; + + if (cert == NULL || not_before == NULL || not_after == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = DerDecodeSignedCertificate(cert, &certData); + if (rv != KMF_OK) + return (rv); + + /* Get notBefore */ + not_before_str = certData->certificate.validity.notBefore.time.Data; + if (strptime((const char *)not_before_str, "%y %m %d %H %M %S", + &tm_tmp) == NULL) { + rv = KMF_ERR_VALIDITY_PERIOD; + goto out; + } + + errno = 0; + if (((t_notbefore = mktime(&tm_tmp)) == (time_t)(-1)) && + errno == EOVERFLOW) { + rv = KMF_ERR_VALIDITY_PERIOD; + goto out; + } + *not_before = t_notbefore; + + /* Get notAfter */ + not_after_str = certData->certificate.validity.notAfter.time.Data; + if (strptime((const char *)not_after_str, "%y %m %d %H %M %S", + &tm_tmp) == NULL) { + rv = KMF_ERR_VALIDITY_PERIOD; + goto out; + } + + errno = 0; + if (((t_notafter = mktime(&tm_tmp)) == (time_t)(-1)) && + errno == EOVERFLOW) { + rv = KMF_ERR_VALIDITY_PERIOD; + goto out; + } + *not_after = t_notafter; + +out: + if (certData != NULL) { + KMF_FreeSignedCert(certData); + free(certData); + } + + return (rv); +} + +KMF_RETURN +KMF_SetCertPubKey(KMF_HANDLE_T handle, + KMF_KEY_HANDLE *KMFKey, + KMF_X509_CERTIFICATE *Cert) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_SPKI *spki_ptr; + KMF_PLUGIN *plugin; + KMF_DATA KeyData = {NULL, 0}; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (KMFKey == NULL || Cert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* The keystore must extract the pubkey data */ + plugin = FindPlugin(handle, KMFKey->kstype); + if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) { + ret = plugin->funclist->EncodePubkeyData(handle, + KMFKey, &KeyData); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + spki_ptr = &Cert->certificate.subjectPublicKeyInfo; + + if (KeyData.Data != NULL) { + ret = DerDecodeSPKI(&KeyData, spki_ptr); + free(KeyData.Data); + } + + return (ret); +} + +KMF_RETURN +KMF_SetCertSubjectName(KMF_X509_CERTIFICATE *CertData, + KMF_X509_NAME *subject_name_ptr) +{ + if (CertData != NULL && subject_name_ptr != NULL) + CertData->certificate.subject = *subject_name_ptr; + else + return (KMF_ERR_BAD_PARAMETER); + + return (KMF_OK); +} + +KMF_RETURN +set_key_usage_extension(KMF_X509_EXTENSIONS *extns, + int critical, uint32_t bits) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + BerElement *asn1 = NULL; + BerValue *extdata; + int bitlen, i; + uint16_t kubits = (uint16_t)(bits & 0x0000ffff); + + if (extns == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&extn, 0, sizeof (extn)); + ret = copy_data(&extn.extnId, (KMF_OID *)&KMFOID_KeyUsage); + if (ret != KMF_OK) + return (ret); + extn.critical = critical; + extn.format = KMF_X509_DATAFORMAT_ENCODED; + + for (i = 7; i <= 15 && !(kubits & (1 << i)); i++); + + bitlen = 16 - i; + + if ((asn1 = kmfder_alloc()) == NULL) + return (KMF_ERR_MEMORY); + + kubits = htons(kubits); + if (kmfber_printf(asn1, "B", (char *)&kubits, bitlen) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + if (kmfber_flatten(asn1, &extdata) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + extn.BERvalue.Data = (uchar_t *)extdata->bv_val; + extn.BERvalue.Length = extdata->bv_len; + + free(extdata); + + ret = add_an_extension(extns, &extn); + if (ret != KMF_OK) { + free(extn.BERvalue.Data); + } +out: + if (asn1 != NULL) + kmfber_free(asn1, 1); + + return (ret); +} + +KMF_RETURN +KMF_SetCertKeyUsage(KMF_X509_CERTIFICATE *CertData, + int critical, uint16_t kubits) +{ + KMF_RETURN ret = KMF_OK; + + if (CertData == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = set_key_usage_extension( + &CertData->certificate.extensions, + critical, kubits); + + return (ret); +} + +KMF_RETURN +KMF_SetCertIssuerName(KMF_X509_CERTIFICATE *CertData, + KMF_X509_NAME *issuer_name_ptr) +{ + if (CertData != NULL && issuer_name_ptr != NULL) + CertData->certificate.issuer = *issuer_name_ptr; + else + return (KMF_ERR_BAD_PARAMETER); + + return (KMF_OK); +} + +KMF_RETURN +KMF_SetCertSignatureAlgorithm(KMF_X509_CERTIFICATE *CertData, + KMF_ALGORITHM_INDEX sigAlg) +{ + KMF_OID *alg; + + if (CertData == NULL) + return (KMF_ERR_BAD_PARAMETER); + + alg = X509_AlgIdToAlgorithmOid(sigAlg); + + if (alg != NULL) { + (void) copy_data((KMF_DATA *) + &CertData->certificate.signature.algorithm, + (KMF_DATA *)alg); + (void) copy_data(&CertData->certificate.signature.parameters, + &CertData->certificate.subjectPublicKeyInfo.algorithm. + parameters); + + (void) copy_data( + &CertData->signature.algorithmIdentifier.algorithm, + &CertData->certificate.signature.algorithm); + (void) copy_data( + &CertData->signature.algorithmIdentifier.parameters, + &CertData->certificate.signature.parameters); + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + return (KMF_OK); +} + +KMF_RETURN +KMF_SetCertValidityTimes(KMF_X509_CERTIFICATE *CertData, + time_t notBefore, uint32_t delta) +{ + time_t clock; + struct tm *gmt; + char szNotBefore[256]; + char szNotAfter[256]; + + if (CertData == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Set up validity fields */ + if (notBefore == NULL) + clock = time(NULL); + else + clock = notBefore; + + gmt = gmtime(&clock); /* valid starting today */ + + /* Build the format in 2 parts so SCCS doesn't get confused */ + (void) strftime(szNotBefore, sizeof (szNotBefore), + "%y%m%d%H" "%M00Z", gmt); + + CertData->certificate.validity.notBefore.timeType = BER_UTCTIME; + CertData->certificate.validity.notBefore.time.Length = + strlen((char *)szNotBefore); + CertData->certificate.validity.notBefore.time.Data = + (uchar_t *)strdup(szNotBefore); + + clock += delta; + gmt = gmtime(&clock); + + /* Build the format in 2 parts so SCCS doesn't get confused */ + (void) strftime(szNotAfter, sizeof (szNotAfter), + "%y%m%d%H" "%M00Z", gmt); + + CertData->certificate.validity.notAfter.timeType = BER_UTCTIME; + CertData->certificate.validity.notAfter.time.Length = + strlen((char *)szNotAfter); + CertData->certificate.validity.notAfter.time.Data = + (uchar_t *)strdup(szNotAfter); + + return (KMF_OK); +} + +/* + * Utility routine to set Integer values in the Certificate template + * for things like serialNumber and Version. The data structure + * expects pointers, not literal values, so we must allocate + * and copy here. Don't use memory from the stack since this data + * is freed later and that would be bad. + */ +KMF_RETURN +set_integer(KMF_DATA *data, void *value, int length) +{ + if (data == NULL || value == NULL) + return (KMF_ERR_BAD_PARAMETER); + + data->Data = malloc(length); + if (data->Data == NULL) + return (KMF_ERR_MEMORY); + + data->Length = length; + (void) memcpy((void *)data->Data, (const void *)value, length); + + return (KMF_OK); +} + +static KMF_RETURN +set_bigint(KMF_BIGINT *data, KMF_BIGINT *bigint) +{ + if (data == NULL || bigint == NULL || bigint->len == NULL) + return (KMF_ERR_BAD_PARAMETER); + + data->val = malloc(bigint->len); + if (data->val == NULL) + return (KMF_ERR_MEMORY); + + data->len = bigint->len; + + (void) memcpy((void *)data->val, bigint->val, bigint->len); + + return (KMF_OK); + +} + +KMF_RETURN +KMF_SetCertSerialNumber(KMF_X509_CERTIFICATE *CertData, + KMF_BIGINT *serno) +{ + if (CertData == NULL || serno == NULL || serno->len == 0) + return (KMF_ERR_BAD_PARAMETER); + return (set_bigint(&CertData->certificate.serialNumber, serno)); +} + +KMF_RETURN +KMF_SetCertVersion(KMF_X509_CERTIFICATE *CertData, + uint32_t version) +{ + if (CertData == NULL) + return (KMF_ERR_BAD_PARAMETER); + /* + * From RFC 3280: + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + if (version != 0 && version != 1 && version != 2) + return (KMF_ERR_BAD_PARAMETER); + return (set_integer(&CertData->certificate.version, (void *)&version, + sizeof (uint32_t))); +} + +KMF_RETURN +KMF_SetCertIssuerAltName(KMF_X509_CERTIFICATE *CertData, + int critical, + KMF_GENERALNAMECHOICES nametype, + char *namedata) +{ + if (CertData == NULL || namedata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + return (KMF_SetAltName( + &CertData->certificate.extensions, + (KMF_OID *)&KMFOID_IssuerAltName, + critical, nametype, namedata)); +} + +KMF_RETURN +KMF_SetCertSubjectAltName(KMF_X509_CERTIFICATE *CertData, + int critical, + KMF_GENERALNAMECHOICES nametype, + char *namedata) +{ + if (CertData == NULL || namedata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + return (KMF_SetAltName(&CertData->certificate.extensions, + (KMF_OID *)&KMFOID_SubjectAltName, + critical, nametype, namedata)); +} + +KMF_RETURN +KMF_AddCertEKU(KMF_X509_CERTIFICATE *CertData, KMF_OID *ekuOID, + int critical) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION *foundextn; + KMF_X509_EXTENSION newextn; + BerElement *asn1 = NULL; + BerValue *extdata = NULL; + char *olddata = NULL; + size_t oldsize = 0; + KMF_X509EXT_EKU ekudata; + + if (CertData == NULL || ekuOID == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&ekudata, 0, sizeof (KMF_X509EXT_EKU)); + (void) memset(&newextn, 0, sizeof (newextn)); + + foundextn = FindExtn(&CertData->certificate.extensions, + (KMF_OID *)&KMFOID_ExtendedKeyUsage); + if (foundextn != NULL) { + ret = GetSequenceContents( + (char *)foundextn->BERvalue.Data, + foundextn->BERvalue.Length, + &olddata, &oldsize); + if (ret != KMF_OK) + goto out; + + /* + * If the EKU is already in the cert, then just return OK. + */ + ret = parse_eku_data(&foundextn->BERvalue, &ekudata); + if (ret == KMF_OK) { + if (isEKUPresent(&ekudata, ekuOID)) { + goto out; + } + } + } + if ((asn1 = kmfder_alloc()) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(asn1, "{") == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + /* Write the old extension data first */ + if (olddata != NULL && oldsize > 0) { + if (kmfber_write(asn1, olddata, oldsize, 0) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + } + + /* Append this EKU OID and close the sequence */ + if (kmfber_printf(asn1, "D}", ekuOID) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + if (kmfber_flatten(asn1, &extdata) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + /* + * If we are just adding to an existing list of EKU OIDs, + * just replace the BER data associated with the found extension. + */ + if (foundextn != NULL) { + free(foundextn->BERvalue.Data); + foundextn->critical = critical; + foundextn->BERvalue.Data = (uchar_t *)extdata->bv_val; + foundextn->BERvalue.Length = extdata->bv_len; + } else { + ret = copy_data(&newextn.extnId, + (KMF_DATA *)&KMFOID_ExtendedKeyUsage); + if (ret != KMF_OK) + goto out; + newextn.critical = critical; + newextn.format = KMF_X509_DATAFORMAT_ENCODED; + newextn.BERvalue.Data = (uchar_t *)extdata->bv_val; + newextn.BERvalue.Length = extdata->bv_len; + ret = KMF_SetCertExtension(CertData, &newextn); + if (ret != KMF_OK) + free(newextn.BERvalue.Data); + } + +out: + KMF_FreeEKU(&ekudata); + if (extdata != NULL) + free(extdata); + + if (olddata != NULL) + free(olddata); + + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (ret != KMF_OK) + KMF_FreeData(&newextn.extnId); + + return (ret); +} + +KMF_RETURN +KMF_SetCertExtension(KMF_X509_CERTIFICATE *CertData, + KMF_X509_EXTENSION *extn) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSIONS *exts; + + if (CertData == NULL || extn == NULL) + return (KMF_ERR_BAD_PARAMETER); + + exts = &CertData->certificate.extensions; + + ret = add_an_extension(exts, extn); + + return (ret); +} + +KMF_RETURN +KMF_SetCertBasicConstraintExt(KMF_X509_CERTIFICATE *CertData, + KMF_BOOL critical, KMF_X509EXT_BASICCONSTRAINTS *constraint) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION extn; + BerElement *asn1 = NULL; + BerValue *extdata; + + if ((CertData == NULL) || (constraint == NULL)) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&extn, 0, sizeof (extn)); + ret = copy_data(&extn.extnId, (KMF_OID *)&KMFOID_BasicConstraints); + if (ret != KMF_OK) + return (ret); + extn.critical = critical; + extn.format = KMF_X509_DATAFORMAT_ENCODED; + + if ((asn1 = kmfder_alloc()) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(asn1, "{") == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + if (kmfber_printf(asn1, "b", constraint->cA) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + if (constraint->pathLenConstraintPresent) { + /* Write the pathLenConstraint value */ + if (kmfber_printf(asn1, "i", + constraint->pathLenConstraint) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + } + + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + if (kmfber_flatten(asn1, &extdata) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + extn.BERvalue.Data = (uchar_t *)extdata->bv_val; + extn.BERvalue.Length = extdata->bv_len; + + free(extdata); + ret = KMF_SetCertExtension(CertData, &extn); + if (ret != KMF_OK) { + free(extn.BERvalue.Data); + } + +out: + if (asn1 != NULL) + kmfber_free(asn1, 1); + + return (ret); +} diff --git a/usr/src/lib/libkmf/libkmf/common/certop.c b/usr/src/lib/libkmf/libkmf/common/certop.c new file mode 100644 index 0000000000..879701e427 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/certop.c @@ -0,0 +1,2773 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright(c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <link.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <ber_der.h> +#include <kmfapiP.h> +#include <pem_encode.h> +#include <libgen.h> +#include <cryptoutil.h> + +#define CERTFILE_TEMPNAME "/tmp/user.certXXXXXX" +#define CRLFILE_TEMPNAME "/tmp/crlXXXXXX" +#define X509_FORMAT_VERSION 2 + +static KMF_RETURN +get_keyalg_from_cert(KMF_DATA *cert, KMF_KEY_ALG *keyalg) +{ + KMF_RETURN rv; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_ALGORITHM_INDEX AlgorithmId; + + rv = DerDecodeSignedCertificate(cert, &SignerCert); + + if (rv != KMF_OK) + return (rv); + + /* Get the algorithm info from the signer certificate */ + AlgorithmId = X509_AlgorithmOidToAlgId( + &SignerCert->signature.algorithmIdentifier.algorithm); + + switch (AlgorithmId) { + case KMF_ALGID_MD5WithRSA: + case KMF_ALGID_MD2WithRSA: + case KMF_ALGID_SHA1WithRSA: + *keyalg = KMF_RSA; + break; + case KMF_ALGID_SHA1WithDSA: + *keyalg = KMF_DSA; + break; + default: + rv = KMF_ERR_BAD_ALGORITHM; + } + + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + return (rv); +} + +/* + * + * Name: find_private_key_by_cert + * + * Description: + * This function finds the corresponding private key in keystore + * for a certificate + * + * Parameters: + * handle(input) - opaque handle for KMF session + * params(input) - contains parameters used to find the private key + * SignerCertData(input) - pointer to a KMF_DATA structure containing a + * signer certificate + * key(output) - contains the found private key handle + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +static KMF_RETURN +find_private_key_by_cert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, + KMF_KEY_HANDLE *key) +{ + + KMF_RETURN ret; + KMF_KEY_ALG keytype; + KMF_PLUGIN *plugin; + + if (handle == NULL || params == NULL || + SignerCertData == NULL || key == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(key, 0, sizeof (KMF_KEY_HANDLE)); + ret = get_keyalg_from_cert(SignerCertData, &keytype); + if (ret != KMF_OK) + return (ret); + + /* Find the private key from the keystore */ + plugin = FindPlugin(handle, params->kstype); + + if (plugin != NULL && plugin->funclist->GetPrikeyByCert != NULL) { + CLEAR_ERROR(handle, ret); + return (plugin->funclist->GetPrikeyByCert(handle, + params, SignerCertData, key, keytype)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + +} + +static KMF_RETURN +check_key_usage(void *handle, + const KMF_DATA *cert, + const KMF_KU_PURPOSE purpose) +{ + KMF_X509EXT_BASICCONSTRAINTS constraint; + KMF_BOOL critical = B_FALSE; + KMF_X509EXT_KEY_USAGE keyusage; + KMF_RETURN ret = KMF_OK; + + if (handle == NULL || cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&constraint, 0, sizeof (KMF_X509EXT_BASICCONSTRAINTS)); + (void) memset(&keyusage, 0, sizeof (KMF_X509EXT_KEY_USAGE)); + + ret = KMF_GetCertKeyUsageExt(cert, &keyusage); + if (ret != KMF_OK) + /* + * If absent or error, the cert is assumed to be invalid + * for all key usage checking. + */ + return (ret); + + + switch (purpose) { + case KMF_KU_SIGN_CERT: + /* + * RFC 3280: + * The keyCertSign bit is asserted when the subject + * public key is used for verifying a signature on + * public key certificates. If the keyCertSign bit + * is asserted, then the cA bit in the basic constraints + * extension (section 4.2.1.10) MUST also be asserted. + * The basic constraints extension MUST appear as a + * critical extension in all CA certificates that + * contain public keys used to validate digital + * signatures on certificates. + */ + ret = KMF_GetCertBasicConstraintExt(cert, &critical, + &constraint); + + if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) { + /* real error */ + return (ret); + } + + if ((!critical) || (!constraint.cA) || + (!(keyusage.KeyUsageBits & KMF_keyCertSign))) + return (KMF_ERR_KEYUSAGE); + break; + case KMF_KU_SIGN_DATA: + /* + * RFC 3280: + * The digitalSignature bit is asserted when the subject + * public key is used with a digital signature mechanism + * to support security services other than certificate + * signing(bit 5), or CRL signing(bit 6). + */ + if (!(keyusage.KeyUsageBits & KMF_digitalSignature)) + return (KMF_ERR_KEYUSAGE); + break; + case KMF_KU_ENCRYPT_DATA: + /* + * RFC 3280: + * The dataEncipherment bit is asserted when the subject + * public key is used for enciphering user data, other than + * cryptographic keys. + */ + if (!(keyusage.KeyUsageBits & KMF_dataEncipherment)) + return (KMF_ERR_KEYUSAGE); + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + return (KMF_OK); +} + +KMF_RETURN +KMF_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *target, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs) +{ + KMF_PLUGIN *plugin; + KMF_RETURN rv = KMF_OK; + + + CLEAR_ERROR(handle, rv); + if (rv != KMF_OK) + return (rv); + + if (target == NULL || num_certs == NULL) + return (KMF_ERR_BAD_PARAMETER); /* ILLEGAL ARGS ERROR */ + + if ((target->find_cert_validity < KMF_ALL_CERTS) || + (target->find_cert_validity > KMF_EXPIRED_CERTS)) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, target->kstype); + + if (plugin != NULL && plugin->funclist->FindCert != NULL) { + return (plugin->funclist->FindCert(handle, target, + kmf_cert, num_certs)); + } + + return (KMF_ERR_PLUGIN_NOTFOUND); +} + +#define NODATA(d) (d.Data == NULL || d.Length == NULL) + +KMF_RETURN +KMF_EncodeCertRecord(KMF_X509_CERTIFICATE *CertData, KMF_DATA *encodedCert) +{ + KMF_RETURN ret; + + if (CertData == NULL || encodedCert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Validate that all required fields are present. + */ + if (NODATA(CertData->certificate.version) || + NODATA(CertData->certificate.signature.algorithm) || + NODATA(CertData->certificate.subjectPublicKeyInfo.subjectPublicKey) || + CertData->certificate.serialNumber.val == NULL || + CertData->certificate.serialNumber.len == 0 || + CertData->certificate.subject.numberOfRDNs == 0 || + CertData->certificate.issuer.numberOfRDNs == 0) { + return (KMF_ERR_INCOMPLETE_TBS_CERT); + } + + encodedCert->Length = 0; + encodedCert->Data = NULL; + + /* Pack the new certificate */ + ret = DerEncodeSignedCertificate(CertData, encodedCert); + + return (ret); +} + +/* + * + * Name: KMF_SignCertWithKey + * + * Description: + * This function signs a certificate using the private key and + * returns the result as a signed, encoded certificate in SignedCert + * + * Parameters: + * handle(input) - opaque handle for KMF session + * CertToBeSigned(input) - pointer to a KMF_DATA structure containing a + * DER encoded certificate to be signed + * Signkey(input) - pointer to private key handle needed for signing + * SignedCert(output) - pointer to the KMF_DATA structure containing the + * signed certificate + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SignCertWithKey(KMF_HANDLE_T handle, + const KMF_DATA *CertToBeSigned, + KMF_KEY_HANDLE *Signkey, + KMF_DATA *SignedCert) +{ + KMF_RETURN err; + + CLEAR_ERROR(handle, err); + if (err != KMF_OK) + return (err); + + if (CertToBeSigned == NULL || + Signkey == NULL || SignedCert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + err = SignCert(handle, CertToBeSigned, Signkey, SignedCert); + + return (err); +} + +/* + * + * Name: KMF_SignCertWithCert + * + * Description: + * This function signs a certificate using the signer cert and + * returns the result as a signed, encoded certificate in SignedCert + * + * Parameters: + * handle(input) - opaque handle for KMF session + * params(input) - contains parameters to be used for signing + * CertToBeSigned(input) - pointer to a KMF_DATA structure containing a + * DER encoded certificate to be signed + * SignerCert(input) - pointer to a KMF_DATA structure containing a + * signer certificate + * SignedCert(output) - pointer to the KMF_DATA structure containing the + * DER encoded signed certificate + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SignCertWithCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + const KMF_DATA *CertToBeSigned, + KMF_DATA *SignerCert, + KMF_DATA *SignedCert) +{ + KMF_RETURN ret; + KMF_KEY_HANDLE Signkey; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (CertToBeSigned == NULL || + SignerCert == NULL || SignedCert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* check the keyUsage of signer's certificate */ + ret = check_key_usage(handle, SignerCert, KMF_KU_SIGN_CERT); + if (ret != KMF_OK) + return (ret); + + /* + * Retrieve the private key from the keystore for the + * signer certificate. + */ + ret = find_private_key_by_cert(handle, params, SignerCert, &Signkey); + if (ret != KMF_OK) + return (ret); + + ret = SignCert(handle, CertToBeSigned, &Signkey, SignedCert); + + KMF_FreeKMFKey(handle, &Signkey); + + return (ret); +} + +/* + * + * Name: KMF_SignDataWithCert + * + * Description: + * This function signs a block of data using the signer cert and + * returns the the signature in output + * + * Parameters: + * handle(input) - opaque handle for KMF session + * params(input) - contains parameters to be used for signing + * tobesigned(input) - pointer to a KMF_DATA structure containing a + * the data to be signed + * output(output) - pointer to the KMF_DATA structure containing the + * signed data + * SignerCertData(input) - pointer to a KMF_DATA structure containing a + * signer certificate + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SignDataWithCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *tobesigned, + KMF_DATA *output, + KMF_DATA *SignerCertData) +{ + + KMF_RETURN ret; + KMF_KEY_HANDLE Signkey; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_PLUGIN *plugin; + KMF_ALGORITHM_INDEX AlgId; + KMF_DATA signature = {0, NULL}; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (tobesigned == NULL || + SignerCertData == NULL || output == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* check the keyUsage of signer's certificate */ + ret = check_key_usage(handle, SignerCertData, KMF_KU_SIGN_DATA); + if (ret != KMF_OK) + return (ret); + + /* + * Retrieve the private key from the keystore based on + * the signer certificate. + */ + ret = find_private_key_by_cert(handle, params, SignerCertData, + &Signkey); + if (ret != KMF_OK) { + goto cleanup; + } + + ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert); + if (ret != KMF_OK) + goto cleanup; + + plugin = FindPlugin(handle, Signkey.kstype); + if (plugin != NULL && plugin->funclist->SignData != NULL) { + ret = plugin->funclist->SignData(handle, &Signkey, + CERT_ALG_OID(SignerCert), tobesigned, output); + if (ret != KMF_OK) + goto cleanup; + + AlgId = X509_AlgorithmOidToAlgId(CERT_ALG_OID(SignerCert)); + + /* + * For DSA, NSS returns an encoded signature. Decode the + * signature as DSA signature should be 40-byte long. + */ + if ((AlgId == KMF_ALGID_SHA1WithDSA) && + (plugin->type == KMF_KEYSTORE_NSS)) { + ret = DerDecodeDSASignature(output, &signature); + if (ret != KMF_OK) { + goto cleanup; + } else { + output->Length = signature.Length; + (void) memcpy(output->Data, signature.Data, + signature.Length); + } + } else if (AlgId == KMF_ALGID_NONE) { + ret = KMF_ERR_BAD_ALGORITHM; + } + } else { + ret = KMF_ERR_PLUGIN_NOTFOUND; + } + +cleanup: + if (signature.Data) + free(signature.Data); + + KMF_FreeKMFKey(handle, &Signkey); + if (SignerCert != NULL) { + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + } + + return (ret); +} + +/* + * + * Name: KMF_VerifyCertWithKey + * + * Description: + * This function verifies that the CertToBeVerified was signed + * using a specific private key and that the certificate has not + * been altered since it was signed using that private key + * + * Parameters: + * handle(input) - opaque handle for KMF session + * KMFKey(input) - holds public key information for verification + * CertToBeVerified(input) - A signed certificate whose signature + * is to be verified + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. The value KMF_OK indicates success. All other + * values represent an error condition. + */ +KMF_RETURN +KMF_VerifyCertWithKey(KMF_HANDLE_T handle, + KMF_KEY_HANDLE *KMFKey, + const KMF_DATA *CertToBeVerified) +{ + KMF_RETURN err; + KMF_DATA derkey = {0, NULL}; + KMF_PLUGIN *plugin; + + CLEAR_ERROR(handle, err); + if (err != KMF_OK) + return (err); + + if (KMFKey == NULL || + CertToBeVerified == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* The keystore must extract the pubkey data */ + plugin = FindPlugin(handle, KMFKey->kstype); + if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) { + err = plugin->funclist->EncodePubkeyData(handle, + KMFKey, &derkey); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + if (err == KMF_OK && derkey.Length > 0) { + /* check the caller and do other setup for this SPI call */ + err = VerifyCertWithKey(handle, &derkey, CertToBeVerified); + + if (derkey.Data != NULL) + free(derkey.Data); + } + + return (err); +} + +/* + * + * Name: KMF_VerifyCertWithCert + * + * Description: + * Function to verify the signature of a signed certificate + * + * Parameters: + * handle - pointer to KMF handle + * CertToBeVerified(input) - pointer to the signed certificate + * SignerCert(input) - pointer to certificate used in signing + * + * Returns: + * A KMF_RETURN value. + * The value KMF_OK indicates success. + * All other values represent an error condition. + */ +KMF_RETURN +KMF_VerifyCertWithCert(KMF_HANDLE_T handle, + const KMF_DATA *CertToBeVerified, + const KMF_DATA *SignerCert) +{ + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (CertToBeVerified == NULL || + SignerCert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* check the keyUsage of signer's certificate */ + ret = check_key_usage(handle, SignerCert, KMF_KU_SIGN_CERT); + if (ret != KMF_OK) + return (ret); + + ret = VerifyCertWithCert(handle, CertToBeVerified, SignerCert); + return (ret); +} + +/* + * + * Name: KMF_VerifyDataWithCert + * + * Description: + * This function verifies the signature of a block of data using a signer + * certificate. + * + * Parameters: + * handle(input) - opaque handle for KMF session + * indata(input) - pointer to the block of data whose signature + * is to be verified + * insig(input) - pointer to the signature to be verified + * SignerCert(input) - pointer to signer cert for verification + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_VerifyDataWithCert(KMF_HANDLE_T handle, + KMF_DATA *indata, + KMF_DATA *insig, + const KMF_DATA *SignerCert) +{ + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (SignerCert == NULL || + indata == NULL || insig == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* check the keyUsage of signer's certificate */ + ret = check_key_usage(handle, SignerCert, KMF_KU_SIGN_DATA); + if (ret != KMF_OK) + return (ret); + + return (VerifyDataWithCert(handle, indata, insig, SignerCert)); +} + +/* + * Name: KMF_EncryptWithCert + * + * Description: + * Uses the public key from the cert to encrypt the plaintext + * into the ciphertext. + * + * Parameters: + * handle(input) - opaque handle for KMF session + * cert(input) - pointer to a DER encoded certificate for encryption + * by using its public key + * plaintext(input) - pointer to the plaintext to be encrypted + * ciphertext(output) - pointer to the ciphertext contains + * encrypted data + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_EncryptWithCert(KMF_HANDLE_T handle, + KMF_DATA *cert, + KMF_DATA *plaintext, + KMF_DATA *ciphertext) +{ + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (cert == NULL || + plaintext == NULL || ciphertext == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* check the keyUsage of the certificate */ + ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA); + if (ret != KMF_OK) + return (ret); + + return (EncryptWithCert(handle, cert, plaintext, ciphertext)); +} + +/* + * Name: KMF_DecryptWithCert + * + * Description: + * Uses the private key associated with the cert to decrypt + * the ciphertext into the plaintext. + * + * Parameters: + * handle(input) - opaque handle for KMF session + * params(input) - contains parameters to be used to find the private + * key for decryption + * cert(input) - pointer to a DER encoded certificate for decryption + * by using its private key + * ciphertext(input) - pointer to the ciphertext contains to be + * decrypted data + * plaintext(output) - pointer to the plaintext after decryption + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_DecryptWithCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *cert, + KMF_DATA *ciphertext, + KMF_DATA *plaintext) +{ + KMF_RETURN ret; + KMF_KEY_HANDLE Signkey; + KMF_X509_CERTIFICATE *x509cert = NULL; + KMF_X509_SPKI *spki_ptr; + KMF_PLUGIN *plugin; + KMF_ALGORITHM_INDEX AlgorithmId; + + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (cert == NULL || + plaintext == NULL || ciphertext == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* check the keyUsage of the certificate */ + ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA); + if (ret != KMF_OK) + return (ret); + + /* + * Retrieve the private key from the keystore based on + * the certificate. + */ + ret = find_private_key_by_cert(handle, params, cert, &Signkey); + if (ret != KMF_OK) { + return (ret); + } + + /* Decode the cert so we can get the alogorithm */ + ret = DerDecodeSignedCertificate(cert, &x509cert); + if (ret != KMF_OK) + goto cleanup; + + spki_ptr = &x509cert->certificate.subjectPublicKeyInfo; + AlgorithmId = X509_AlgorithmOidToAlgId((KMF_OID *) + &spki_ptr->algorithm.algorithm); + + /* DSA does not support decrypt */ + if (AlgorithmId == KMF_ALGID_DSA) { + ret = KMF_ERR_BAD_ALGORITHM; + goto cleanup; + } + + plugin = FindPlugin(handle, Signkey.kstype); + + if (plugin != NULL && plugin->funclist->DecryptData != NULL) { + ret = plugin->funclist->DecryptData(handle, + &Signkey, &spki_ptr->algorithm.algorithm, + ciphertext, plaintext); + } else { + ret = KMF_ERR_PLUGIN_NOTFOUND; + } + +cleanup: + KMF_FreeKMFKey(handle, &Signkey); + KMF_FreeSignedCert(x509cert); + free(x509cert); + + return (ret); +} + +KMF_RETURN +KMF_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *target, + KMF_DATA *pcert) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (target == NULL || pcert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, target->kstype); + + if (plugin != NULL && plugin->funclist->StoreCert != NULL) { + return (plugin->funclist->StoreCert(handle, target, pcert)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *target) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (target == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, target->kstype); + + if (plugin != NULL && plugin->funclist->ImportCert != NULL) { + return (plugin->funclist->ImportCert(handle, target)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_DeleteCertFromKeystore(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *target) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (target == NULL || + (target->find_cert_validity < KMF_ALL_CERTS) || + (target->find_cert_validity > KMF_EXPIRED_CERTS)) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, target->kstype); + + if (plugin != NULL && plugin->funclist->DeleteCert != NULL) { + return (plugin->funclist->DeleteCert(handle, target)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +/* + * This function gets the CRL URI entries from the certificate's Distribution + * points extension, and downloads the CRL file. The function also returns + * the URI string and the format of the CRL file. The caller should free + * the space allocated for the returned URI string. + */ +static KMF_RETURN +cert_get_crl(KMF_HANDLE_T handle, const KMF_DATA *cert, char *proxy, + char *filename, char **retn_uri, KMF_ENCODE_FORMAT *format) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509EXT_CRLDISTPOINTS crl_dps; + boolean_t done = B_FALSE; + char uri[1024]; + char *proxyname = NULL; + char *proxy_port_s = NULL; + int proxy_port = 0; + int i, j; + char *path = NULL; + + if (handle == NULL || cert == NULL || filename == NULL || + retn_uri == NULL || format == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Get the proxy info */ + if (proxy != NULL) { + proxyname = strtok(proxy, ":"); + proxy_port_s = strtok(NULL, "\0"); + if (proxy_port_s != NULL) { + proxy_port = strtol(proxy_port_s, NULL, 0); + } else { + proxy_port = 8080; /* default */ + } + } + + /* + * Get the CRL URI from the certificate's CRL Distribution + * Points extension and download the CRL file. There maybe more than + * one CRL URI entries in the DP extension, so we will continue + * the process until a CRL file is sucessfully downloaded or we + * are running out the CRL URI's. + */ + ret = KMF_GetCertCRLDistributionPointsExt((const KMF_DATA *)cert, + &crl_dps); + if (ret != KMF_OK) + goto out; + + for (i = 0; i < crl_dps.number; i++) { + KMF_CRL_DIST_POINT *dp = &(crl_dps.dplist[i]); + KMF_GENERALNAMES *fullname = &(dp->name.full_name); + KMF_DATA *data; + + if (done) + break; + for (j = 0; j < fullname->number; j++) { + data = &(fullname->namelist[j].name); + (void) memcpy(uri, data->Data, data->Length); + uri[data->Length] = '\0'; + ret = KMF_DownloadCRL(handle, uri, proxyname, + proxy_port, 30, filename, format); + if (ret == KMF_OK) { + done = B_TRUE; + path = malloc(data->Length + 1); + if (path == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) strncpy(path, uri, data->Length); + *retn_uri = path; + break; + } + } + } + +out: + KMF_FreeCRLDistributionPoints(&crl_dps); + return (ret); +} + +static KMF_RETURN +cert_crl_check(KMF_HANDLE_T handle, + KMF_VALIDATECERT_PARAMS *params, + KMF_DATA *user_cert, + KMF_DATA *issuer_cert) +{ + KMF_POLICY_RECORD *policy; + KMF_RETURN ret = KMF_OK; + KMF_IMPORTCRL_PARAMS icrl_params; + KMF_FINDCERTINCRL_PARAMS fcrl_params; + KMF_OPENSSL_PARAMS ssl_params; + KMF_VERIFYCRL_PARAMS vcrl_params; + char user_certfile[MAXPATHLEN]; + char crlfile_tmp[MAXPATHLEN]; + KMF_CHECKCRLDATE_PARAMS ccrldate_params; + char *basefilename = NULL; + char *dir = NULL; + char *crlfilename = NULL; + char *proxy = NULL; + char *uri = NULL; + KMF_ENCODE_FORMAT format; + + if (handle == NULL || params == NULL || + user_cert == NULL || issuer_cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + + (void) memset(&icrl_params, 0, sizeof (icrl_params)); + (void) memset(&vcrl_params, 0, sizeof (vcrl_params)); + (void) memset(&ccrldate_params, 0, sizeof (ccrldate_params)); + (void) memset(&fcrl_params, 0, sizeof (fcrl_params)); + (void) memset(&ssl_params, 0, sizeof (ssl_params)); + + /* + * If the get-crl-uri policy is TRUE, then download the CRL + * file first. The newly downloaded file will be stored in the + * NSS internal database for NSS keystore, and stored in a file for + * the File-based CRL plugins (OpenSSL and PKCS11). + * + * For file-based plugins, if the get-crl-uri policy is FALSE, + * then the caller should provide a CRL file in the policy. + * Also, after this step is done, the "crlfilename" variable should + * contain the proper CRL file to be used for the rest of CRL + * validation process. + */ + basefilename = policy->validation_info.crl_info.basefilename; + dir = policy->validation_info.crl_info.directory; + if (policy->validation_info.crl_info.get_crl_uri) { + /* + * Create a temporary file to hold the new CRL file initially. + */ + (void) strlcpy(crlfile_tmp, CRLFILE_TEMPNAME, + sizeof (crlfile_tmp)); + if (mkstemp(crlfile_tmp) == -1) { + ret = KMF_ERR_INTERNAL; + goto cleanup; + } + + /* + * Get the URI entry from the certificate's CRL distribution + * points extension and download the CRL file. + */ + proxy = policy->validation_info.crl_info.proxy; + ret = cert_get_crl(handle, user_cert, proxy, crlfile_tmp, + &uri, &format); + if (ret != KMF_OK) { + (void) unlink(crlfile_tmp); + goto cleanup; + } + + /* Cache the CRL file. */ + if (params->kstype == KMF_KEYSTORE_NSS) { + /* + * For NSS keystore, import this CRL file into th + * internal database. + */ + icrl_params.kstype = KMF_KEYSTORE_NSS; + icrl_params.nssparms.slotlabel = NULL; + icrl_params.nssparms.crlfile = crlfile_tmp; + icrl_params.nssparms.crl_check = B_FALSE; + ret = KMF_ImportCRL(handle, &icrl_params); + (void) unlink(crlfile_tmp); + if (ret != KMF_OK) + goto cleanup; + } else { + /* + * For File-based CRL plugin's, find the cache + * location from the CRL policy's attributes and + * cache it. + */ + if (basefilename == NULL) + basefilename = basename(uri); + + crlfilename = get_fullpath(dir == NULL ? "./" : dir, + basefilename); + if (crlfilename == NULL) { + (void) unlink(crlfile_tmp); + ret = KMF_ERR_BAD_CRLFILE; + goto cleanup; + } + + if (rename(crlfile_tmp, crlfilename) == -1) { + (void) unlink(crlfile_tmp); + ret = KMF_ERR_WRITE_FILE; + goto cleanup; + } + } + } else { + /* + * If the get_crl_uri policy is FALSE, for File-based CRL + * plugins, get the input CRL file from the policy. + */ + if (params->kstype != KMF_KEYSTORE_NSS) { + if (basefilename == NULL) { + ret = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + crlfilename = get_fullpath(dir == NULL ? "./" : dir, + basefilename); + if (crlfilename == NULL) { + ret = KMF_ERR_BAD_CRLFILE; + goto cleanup; + } + } + } + + /* + * Check the CRL signature if needed. + */ + if (!policy->validation_info.crl_info.ignore_crl_sign) { + /* + * NSS CRL is not file based, and its signature + * has been verified during CRL import. + */ + if (params->kstype != KMF_KEYSTORE_NSS) { + vcrl_params.crl_name = crlfilename; + vcrl_params.tacert = issuer_cert; + + ret = KMF_VerifyCRLFile(handle, &vcrl_params); + if (ret != KMF_OK) { + goto cleanup; + } + } + } + + /* + * Check the CRL validity if needed. + */ + if (!policy->validation_info.crl_info.ignore_crl_date) { + /* + * This is for file-based CRL, but not for NSS CRL. + */ + if (params->kstype != KMF_KEYSTORE_NSS) { + ccrldate_params.crl_name = crlfilename; + + ret = KMF_CheckCRLDate(handle, &ccrldate_params); + if (ret != KMF_OK) { + goto cleanup; + } + } + } + + /* + * Check the CRL revocation for the certificate. + */ + fcrl_params.kstype = params->kstype; + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + fcrl_params.certLabel = params->certLabel; + break; + case KMF_KEYSTORE_PK11TOKEN: + /* + * Create temporary file to hold the user certificate. + */ + (void) strlcpy(user_certfile, CERTFILE_TEMPNAME, + sizeof (user_certfile)); + if (mkstemp(user_certfile) == -1) { + ret = KMF_ERR_INTERNAL; + goto cleanup; + } + + ret = KMF_CreateCertFile(user_cert, KMF_FORMAT_ASN1, + user_certfile); + if (ret != KMF_OK) { + goto cleanup; + } + + ssl_params.certfile = user_certfile; + ssl_params.crlfile = crlfilename; + fcrl_params.sslparms = ssl_params; + break; + case KMF_KEYSTORE_OPENSSL: + ssl_params.certfile = params->ks_opt_u.openssl_opts.certfile; + ssl_params.crlfile = crlfilename; + fcrl_params.sslparms = ssl_params; + break; + default: + ret = KMF_ERR_PLUGIN_NOTFOUND; + goto cleanup; + } + + ret = KMF_FindCertInCRL(handle, &fcrl_params); + if (ret == KMF_ERR_NOT_REVOKED) { + ret = KMF_OK; + } + +cleanup: + (void) unlink(user_certfile); + + if (crlfilename != NULL) + free(crlfilename); + + if (uri != NULL) + free(uri); + + return (ret); +} + +static KMF_RETURN +cert_ocsp_check(KMF_HANDLE_T handle, + KMF_VALIDATECERT_PARAMS *params, + KMF_DATA *user_cert, + KMF_DATA *issuer_cert, + KMF_DATA *response) +{ + KMF_RETURN ret = KMF_OK; + KMF_POLICY_RECORD *policy; + KMF_FINDCERT_PARAMS fc_target; + KMF_OCSPRESPONSE_PARAMS_INPUT resp_params_in; + KMF_OCSPRESPONSE_PARAMS_OUTPUT resp_params_out; + KMF_DATA *new_response = NULL; + boolean_t ignore_response_sign = B_FALSE; + uint32_t ltime; + KMF_DATA *signer_cert = NULL; + KMF_BIGINT sernum = { NULL, 0 }; + + if (handle == NULL || params == NULL || user_cert == NULL || + issuer_cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + + /* + * Get the response lifetime from policy. + */ + if (policy->VAL_OCSP_BASIC.response_lifetime != NULL && + (str2lifetime(policy->VAL_OCSP_BASIC.response_lifetime, <ime) + < 0)) + return (KMF_ERR_OCSP_RESPONSE_LIFETIME); + + /* + * Get the ignore_response_sign policy. + * + * If ignore_response_sign is FALSE, we need to verify the response. + * Find the OCSP Responder certificate if it is specified in the OCSP + * policy. + */ + ignore_response_sign = policy->VAL_OCSP_BASIC.ignore_response_sign; + + if (ignore_response_sign == B_FALSE && + policy->VAL_OCSP.has_resp_cert == B_TRUE) { + char *signer_name; + KMF_OPENSSL_PARAMS ssl_params; + KMF_X509_DER_CERT signer_retrcert; + uchar_t *bytes = NULL; + size_t bytelen; + uint32_t num = 0; + + if (policy->VAL_OCSP_RESP_CERT.name == NULL || + policy->VAL_OCSP_RESP_CERT.serial == NULL) + return (KMF_ERR_POLICY_NOT_FOUND); + + signer_cert = malloc(sizeof (KMF_DATA)); + if (signer_cert == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memset(signer_cert, 0, sizeof (KMF_DATA)); + + signer_name = policy->VAL_OCSP_RESP_CERT.name; + ret = KMF_HexString2Bytes( + (uchar_t *)policy->VAL_OCSP_RESP_CERT.serial, + &bytes, &bytelen); + if (ret != KMF_OK || bytes == NULL) { + ret = KMF_ERR_OCSP_POLICY; + goto out; + } + + sernum.val = bytes; + sernum.len = bytelen; + + (void) memset(&fc_target, 0, sizeof (fc_target)); + (void) memset(&ssl_params, 0, sizeof (ssl_params)); + + fc_target.subject = signer_name; + fc_target.serial = &sernum; + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + fc_target.kstype = KMF_KEYSTORE_NSS; + params->nssparms.slotlabel = + params->nssparms.slotlabel; + break; + + case KMF_KEYSTORE_OPENSSL: + fc_target.kstype = KMF_KEYSTORE_OPENSSL; + ssl_params.dirpath = + params->sslparms.dirpath == NULL ? + "./" : params->sslparms.dirpath; + fc_target.sslparms = ssl_params; + break; + + case KMF_KEYSTORE_PK11TOKEN: + fc_target.kstype = KMF_KEYSTORE_PK11TOKEN; + break; + default: + ret = KMF_ERR_BAD_PARAMETER; + goto out; + break; + } + + num = 0; + ret = KMF_FindCert(handle, &fc_target, NULL, &num); + if (ret != KMF_OK || num != 1) { + if (num == 0) + ret = KMF_ERR_CERT_NOT_FOUND; + if (num > 0) + ret = KMF_ERR_CERT_MULTIPLE_FOUND; + goto out; + } + + (void) memset(&signer_retrcert, 0, sizeof (KMF_X509_DER_CERT)); + ret = KMF_FindCert(handle, &fc_target, &signer_retrcert, &num); + if (ret == KMF_OK) { + signer_cert->Length = + signer_retrcert.certificate.Length; + signer_cert->Data = signer_retrcert.certificate.Data; + } else { + goto out; + } + } + + /* + * If the caller provides an OCSP response, we will use it directly. + * Otherwise, we will try to fetch an OCSP response for the given + * certificate now. + */ + if (response == NULL) { + new_response = (KMF_DATA *) malloc(sizeof (KMF_DATA)); + if (new_response == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + new_response->Data = NULL; + new_response->Length = 0; + + ret = KMF_GetOCSPForCert(handle, user_cert, issuer_cert, + new_response); + if (ret != KMF_OK) + goto out; + } + + /* + * Process the OCSP response and retrieve the certificate status. + */ + resp_params_in.issuer_cert = issuer_cert; + resp_params_in.user_cert = user_cert; + resp_params_in.signer_cert = signer_cert; + resp_params_in.response = + response == NULL ? new_response : response; + resp_params_in.response_lifetime = ltime; + resp_params_in.ignore_response_sign = ignore_response_sign; + + ret = KMF_GetOCSPStatusForCert(handle, &resp_params_in, + &resp_params_out); + if (ret == KMF_OK) { + switch (resp_params_out.cert_status) { + case OCSP_GOOD: + break; + case OCSP_UNKNOWN: + ret = KMF_ERR_OCSP_UNKNOWN_CERT; + break; + case OCSP_REVOKED: + ret = KMF_ERR_OCSP_REVOKED; + break; + } + } + +out: + if (new_response) { + KMF_FreeData(new_response); + free(new_response); + } + + if (signer_cert) { + KMF_FreeData(signer_cert); + free(signer_cert); + } + + if (sernum.val != NULL) + free(sernum.val); + + return (ret); +} + +static KMF_RETURN +cert_ku_check(KMF_HANDLE_T handle, KMF_DATA *cert) +{ + KMF_POLICY_RECORD *policy; + KMF_X509EXT_KEY_USAGE keyusage; + KMF_RETURN ret = KMF_OK; + + if (handle == NULL || cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + (void) memset(&keyusage, 0, sizeof (keyusage)); + ret = KMF_GetCertKeyUsageExt(cert, &keyusage); + + if (ret == KMF_ERR_EXTENSION_NOT_FOUND) { + if (policy->ku_bits) { + /* keyusage is not set in cert but is set in policy */ + return (KMF_ERR_KEYUSAGE); + } else { + /* no keyusage set in both cert and policy */ + return (KMF_OK); + } + } + + if (ret != KMF_OK) { + /* real error */ + return (ret); + } + + /* + * Rule: if the KU bit is set in policy, the corresponding KU bit + * must be set in the certificate (but not vice versa). + */ + if ((policy->ku_bits & keyusage.KeyUsageBits) == policy->ku_bits) { + return (KMF_OK); + } else { + return (KMF_ERR_KEYUSAGE); + } + +} + +static KMF_RETURN +cert_eku_check(KMF_HANDLE_T handle, KMF_DATA *cert) +{ + KMF_POLICY_RECORD *policy; + KMF_X509EXT_BASICCONSTRAINTS constraint; + KMF_BOOL critical = B_FALSE; + KMF_RETURN ret = KMF_OK; + KMF_X509EXT_EKU eku; + uint16_t cert_eku = 0, policy_eku = 0; + int i; + + if (handle == NULL || cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + policy = handle->policy; + (void) memset(&constraint, 0, sizeof (constraint)); + + ret = KMF_GetCertBasicConstraintExt(cert, + &critical, &constraint); + + if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) { + /* real error */ + return (ret); + } + + if (constraint.cA) { + /* EKU extension appears only in end entity certificates */ + return (KMF_ERR_KEYUSAGE); + } + + ret = KMF_GetCertEKU(cert, &eku); + if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) { + /* real error */ + return (ret); + } + + if (ret == KMF_ERR_EXTENSION_NOT_FOUND) { + cert_eku = 0; + } else { + /* + * Build the EKU bitmap based on the certificate + */ + for (i = 0; i < eku.nEKUs; i++) { + if (IsEqualOid(&eku.keyPurposeIdList[i], + (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) { + cert_eku |= KMF_EKU_SERVERAUTH; + } else if (IsEqualOid(&eku.keyPurposeIdList[i], + (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) { + cert_eku |= KMF_EKU_CLIENTAUTH; + } else if (IsEqualOid(&eku.keyPurposeIdList[i], + (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) { + cert_eku |= KMF_EKU_CODESIGNING; + } else if (IsEqualOid(&eku.keyPurposeIdList[i], + (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) { + cert_eku |= KMF_EKU_EMAIL; + } else if (IsEqualOid(&eku.keyPurposeIdList[i], + (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) { + cert_eku |= KMF_EKU_TIMESTAMP; + } else if (IsEqualOid(&eku.keyPurposeIdList[i], + (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) { + cert_eku |= KMF_EKU_OCSPSIGNING; + } else if (!policy->ignore_unknown_ekus) { + return (KMF_ERR_KEYUSAGE); + } + } /* for */ + } + + /* + * Build the EKU bitmap based on the policy + */ + for (i = 0; i < policy->eku_set.eku_count; i++) { + if (IsEqualOid(&policy->eku_set.ekulist[i], + (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) { + policy_eku |= KMF_EKU_SERVERAUTH; + } else if (IsEqualOid(&policy->eku_set.ekulist[i], + (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) { + policy_eku |= KMF_EKU_CLIENTAUTH; + } else if (IsEqualOid(&policy->eku_set.ekulist[i], + (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) { + policy_eku |= KMF_EKU_CODESIGNING; + } else if (IsEqualOid(&policy->eku_set.ekulist[i], + (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) { + policy_eku |= KMF_EKU_EMAIL; + } else if (IsEqualOid(&policy->eku_set.ekulist[i], + (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) { + policy_eku |= KMF_EKU_TIMESTAMP; + } else if (IsEqualOid(&policy->eku_set.ekulist[i], + (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) { + policy_eku |= KMF_EKU_OCSPSIGNING; + } else if (!policy->ignore_unknown_ekus) { + return (KMF_ERR_KEYUSAGE); + } + } /* for */ + + /* + * Rule: if the EKU OID is set in policy, the corresponding EKU OID + * must be set in the certificate (but not vice versa). + */ + if ((policy_eku & cert_eku) == policy_eku) { + return (KMF_OK); + } else { + return (KMF_ERR_KEYUSAGE); + } +} + +static KMF_RETURN +kmf_find_issuer_cert(KMF_HANDLE_T handle, + KMF_VALIDATECERT_PARAMS *params, + char *user_issuer, + KMF_DATA *issuer_cert) +{ + + KMF_RETURN ret = KMF_OK; + KMF_FINDCERT_PARAMS fc_target; + KMF_OPENSSL_PARAMS ssl_params; + KMF_X509_DER_CERT *certlist = NULL; + uint32_t i, num = 0; + time_t t_notbefore; + time_t t_notafter; + time_t latest; + KMF_DATA tmp_cert = {0, NULL}; + + if (handle == NULL || params == NULL || + user_issuer == NULL || issuer_cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&fc_target, 0, sizeof (fc_target)); + (void) memset(&ssl_params, 0, sizeof (ssl_params)); + + fc_target.subject = user_issuer; + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + fc_target.kstype = KMF_KEYSTORE_NSS; + fc_target.nssparms.slotlabel = params->nssparms.slotlabel; + break; + + case KMF_KEYSTORE_OPENSSL: + fc_target.kstype = KMF_KEYSTORE_OPENSSL; + /* setup dirpath to search for TA in a directory */ + if (params->sslparms.dirpath == NULL) { + ssl_params.dirpath = "./"; + } else { + ssl_params.dirpath = params->sslparms.dirpath; + } + ssl_params.certfile = NULL; + fc_target.sslparms = ssl_params; + break; + + case KMF_KEYSTORE_PK11TOKEN: + fc_target.kstype = KMF_KEYSTORE_PK11TOKEN; + break; + default: + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + num = 0; + ret = KMF_FindCert(handle, &fc_target, NULL, &num); + if (ret == KMF_OK && num > 0) { + certlist = (KMF_X509_DER_CERT *)malloc(num * + sizeof (KMF_X509_DER_CERT)); + + if (certlist == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + (void) memset(certlist, 0, num * + sizeof (KMF_X509_DER_CERT)); + + ret = KMF_FindCert(handle, &fc_target, certlist, &num); + if (ret != KMF_OK) { + free(certlist); + certlist = NULL; + goto out; + } + } else { + goto out; + } + + if (num == 1) { + /* only one issuer cert is found */ + tmp_cert.Length = certlist[0].certificate.Length; + tmp_cert.Data = certlist[0].certificate.Data; + } else { + /* + * More than one issuer certs are found. We will + * pick the latest one. + */ + latest = 0; + for (i = 0; i < num; i++) { + ret = KMF_GetCertValidity(&certlist[i].certificate, + &t_notbefore, &t_notafter); + if (ret != KMF_OK) { + ret = KMF_ERR_VALIDITY_PERIOD; + goto out; + } + + if (t_notbefore > latest) { + tmp_cert.Length = + certlist[i].certificate.Length; + tmp_cert.Data = + certlist[i].certificate.Data; + latest = t_notbefore; + } + + } + } + + issuer_cert->Length = tmp_cert.Length; + issuer_cert->Data = malloc(tmp_cert.Length); + if (issuer_cert->Data == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memcpy(issuer_cert->Data, tmp_cert.Data, + tmp_cert.Length); + +out: + if (certlist != NULL) { + for (i = 0; i < num; i++) + KMF_FreeKMFCert(handle, &certlist[i]); + free(certlist); + } + + return (ret); + +} + +static KMF_RETURN +kmf_find_ta_cert(KMF_HANDLE_T handle, + KMF_VALIDATECERT_PARAMS *params, + KMF_DATA *ta_cert, + KMF_X509_NAME *user_issuerDN) +{ + + KMF_POLICY_RECORD *policy; + KMF_RETURN ret = KMF_OK; + KMF_FINDCERT_PARAMS fc_target; + KMF_OPENSSL_PARAMS ssl_params; + uint32_t num = 0; + char *ta_name; + KMF_BIGINT serial = { NULL, 0 }; + uchar_t *bytes = NULL; + size_t bytelen; + KMF_X509_DER_CERT ta_retrCert; + char *ta_subject = NULL; + KMF_X509_NAME ta_subjectDN; + + if (handle == NULL || params == NULL || + ta_cert == NULL || user_issuerDN == NULL) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + ta_name = policy->ta_name; + + ret = KMF_HexString2Bytes((uchar_t *)policy->ta_serial, + &bytes, &bytelen); + if (ret != KMF_OK || bytes == NULL) { + ret = KMF_ERR_TA_POLICY; + goto out; + } + + (void) memset(&fc_target, 0, sizeof (fc_target)); + (void) memset(&ssl_params, 0, sizeof (ssl_params)); + + serial.val = bytes; + serial.len = bytelen; + fc_target.serial = &serial; + fc_target.subject = ta_name; + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + fc_target.kstype = KMF_KEYSTORE_NSS; + fc_target.nssparms.slotlabel = params->nssparms.slotlabel; + break; + + case KMF_KEYSTORE_OPENSSL: + fc_target.kstype = KMF_KEYSTORE_OPENSSL; + /* setup dirpath to search for TA in a directory */ + if (params->sslparms.dirpath == NULL) { + ssl_params.dirpath = "./"; + } else { + ssl_params.dirpath = params->sslparms.dirpath; + } + ssl_params.certfile = NULL; + fc_target.sslparms = ssl_params; + break; + + case KMF_KEYSTORE_PK11TOKEN: + fc_target.kstype = KMF_KEYSTORE_PK11TOKEN; + break; + default: + ret = KMF_ERR_PLUGIN_NOTFOUND; + goto out; + } + + num = 0; + ret = KMF_FindCert(handle, &fc_target, NULL, &num); + if (ret != KMF_OK || num != 1) { + if (num == 0) + ret = KMF_ERR_CERT_NOT_FOUND; + if (num > 1) + ret = KMF_ERR_CERT_MULTIPLE_FOUND; + goto out; + } + + (void) memset(&ta_retrCert, 0, sizeof (KMF_X509_DER_CERT)); + + ret = KMF_FindCert(handle, &fc_target, &ta_retrCert, &num); + if (ret == KMF_OK) { + ta_cert->Length = ta_retrCert.certificate.Length; + ta_cert->Data = malloc(ta_retrCert.certificate.Length); + if (ta_cert->Data == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memcpy(ta_cert->Data, ta_retrCert.certificate.Data, + ta_retrCert.certificate.Length); + } else { + goto out; + } + + /* + * The found TA's name must be matching with issuer name in + * subscriber's certificate. + */ + (void) memset(&ta_subjectDN, 0, sizeof (ta_subjectDN)); + + ret = KMF_GetCertSubjectNameString(handle, ta_cert, &ta_subject); + if (ret != KMF_OK) + goto out; + + ret = KMF_DNParser(ta_subject, &ta_subjectDN); + if (ret != KMF_OK) + goto out; + + ret = KMF_CompareRDNs(user_issuerDN, &ta_subjectDN); + KMF_FreeDN(&ta_subjectDN); + +out: + if (ta_retrCert.certificate.Data) + KMF_FreeKMFCert(handle, &ta_retrCert); + + if ((ret != KMF_OK) && (ta_cert->Data != NULL)) + free(ta_cert->Data); + + if (serial.val != NULL) + free(serial.val); + + if (ta_subject) + free(ta_subject); + + return (ret); +} + +KMF_RETURN +KMF_ValidateCert(KMF_HANDLE_T handle, + KMF_VALIDATECERT_PARAMS *params, + int *result) +{ + KMF_RETURN ret = KMF_OK; + KMF_FINDCERT_PARAMS fc_target; + KMF_OPENSSL_PARAMS ssl_params; + KMF_X509_DER_CERT user_retrCert; + KMF_DATA ta_cert = {0, NULL}; + KMF_DATA user_cert = {0, NULL}; + KMF_DATA issuer_cert = {0, NULL}; + uint32_t num = 0; + char *user_issuer = NULL, *user_subject = NULL; + KMF_X509_NAME user_issuerDN, user_subjectDN; + boolean_t self_signed = B_FALSE; + KMF_POLICY_RECORD *policy; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if ((params == NULL) || (result == NULL)) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + + *result = KMF_CERT_VALIDATE_OK; + (void) memset(&fc_target, 0, sizeof (fc_target)); + (void) memset(&ssl_params, 0, sizeof (ssl_params)); + (void) memset(&user_issuerDN, 0, sizeof (user_issuerDN)); + (void) memset(&user_subjectDN, 0, sizeof (user_subjectDN)); + + fc_target.kstype = params->kstype; + fc_target.certLabel = params->certLabel; + fc_target.issuer = params->issuer; + fc_target.subject = params->subject; + fc_target.idstr = params->idstr; + fc_target.serial = params->serial; + if (params->kstype == KMF_KEYSTORE_NSS) + fc_target.ks_opt_u.nss_opts = params->ks_opt_u.nss_opts; + else if (params->kstype == KMF_KEYSTORE_OPENSSL) + fc_target.ks_opt_u.openssl_opts = params->ks_opt_u.openssl_opts; + else if (params->kstype == KMF_KEYSTORE_PK11TOKEN) + fc_target.ks_opt_u.pkcs11_opts = params->ks_opt_u.pkcs11_opts; + else + return (KMF_ERR_PLUGIN_NOTFOUND); + + /* + * Find the Subscriber's certificate based on the input parameter + */ + ret = KMF_FindCert(handle, &fc_target, NULL, &num); + if (ret != KMF_OK || num != 1) { + (*result) = (*result) | KMF_CERT_VALIDATE_ERR_USER; + if (num == 0) + ret = KMF_ERR_CERT_NOT_FOUND; + if (num > 1) + ret = KMF_ERR_CERT_MULTIPLE_FOUND; + goto out; + } + + (void) memset(&user_retrCert, 0, sizeof (KMF_X509_DER_CERT)); + + ret = KMF_FindCert(handle, &fc_target, &user_retrCert, &num); + if (ret == KMF_OK) { + user_cert.Length = user_retrCert.certificate.Length; + user_cert.Data = user_retrCert.certificate.Data; + } else { + *result |= KMF_CERT_VALIDATE_ERR_USER; + goto out; + } + + if ((ret = KMF_GetCertIssuerNameString(handle, &user_cert, + &user_issuer)) != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_USER; + goto out; + } + + if ((ret = KMF_DNParser(user_issuer, &user_issuerDN)) != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_USER; + goto out; + } + + if ((ret = KMF_GetCertSubjectNameString(handle, &user_cert, + &user_subject)) != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_USER; + KMF_FreeDN(&user_issuerDN); + goto out; + } + + if ((ret = KMF_DNParser(user_subject, &user_subjectDN)) != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_USER; + KMF_FreeDN(&user_issuerDN); + goto out; + } + + if ((KMF_CompareRDNs(&user_issuerDN, &user_subjectDN)) == 0) { + /* + * this is a self-signed cert + */ + self_signed = B_TRUE; + } + + KMF_FreeDN(&user_subjectDN); + + /* + * Check KeyUsage extension of the subscriber's certificate + */ + ret = cert_ku_check(handle, &user_cert); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_KEYUSAGE; + goto out; + } + + /* + * Validate Extended KeyUsage extension + */ + ret = cert_eku_check(handle, &user_cert); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE; + goto out; + } + + /* + * Check the certificate's validity period + * + * This step is needed when "ignore_date" in policy is set + * to false. + */ + if (!policy->ignore_date) { + /* + * Validate expiration date + */ + ret = KMF_CheckCertDate(handle, &user_cert); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_TIME; + goto out; + } + } + + /* + * When "ignore_trust_anchor" in policy is set to FALSE, + * we will try to find the TA cert based on the TA policy + * attributes. + * + * TA's subject name (ta_name) and serial number (ta_serial) + * are defined as optional attributes in policy dtd, but they + * should exist in policy when "ignore_trust_anchor" is set + * to FALSE. The policy verification code has enforced that. + */ + if (policy->ignore_trust_anchor) { + goto check_revocation; + } + + ret = kmf_find_ta_cert(handle, params, &ta_cert, &user_issuerDN); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_TA; + goto out; + } + + /* + * Verify the signature of subscriber's certificate using + * TA certificate. + */ + if (self_signed) { + ret = KMF_VerifyCertWithCert(handle, + &user_cert, &user_cert); + } else { + ret = KMF_VerifyCertWithCert(handle, + &user_cert, &ta_cert); + } + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_SIGNATURE; + goto out; + } + +check_revocation: + /* + * Check certificate revocation + */ + if (self_signed) { + /* skip revocation checking */ + goto out; + } + + /* + * When CRL or OCSP revocation method is set in the policy, + * we will try to find the issuer of the subscriber certificate + * using the issuer name of the subscriber certificate. The + * issuer certificate will be used to do the CRL checking + * and OCSP checking. + */ + if (!(policy->revocation & KMF_REVOCATION_METHOD_CRL) && + !(policy->revocation & KMF_REVOCATION_METHOD_OCSP)) { + goto out; + } + + ret = kmf_find_issuer_cert(handle, params, user_issuer, + &issuer_cert); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_ISSUER; + goto out; + } + + if (policy->revocation & KMF_REVOCATION_METHOD_CRL) { + ret = cert_crl_check(handle, params, + &user_cert, &issuer_cert); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_CRL; + goto out; + } + } + + if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) { + ret = cert_ocsp_check(handle, params, + &user_cert, &issuer_cert, params->ocsp_response); + if (ret != KMF_OK) { + *result |= KMF_CERT_VALIDATE_ERR_OCSP; + goto out; + } + } + +out: + if (user_retrCert.certificate.Data) + KMF_FreeKMFCert(handle, &user_retrCert); + + if (user_issuer) { + KMF_FreeDN(&user_issuerDN); + free(user_issuer); + } + + if (user_subject) + free(user_subject); + + if (ta_cert.Data) + free(ta_cert.Data); + + if (issuer_cert.Data) + free(issuer_cert.Data); + + return (ret); + +} + +KMF_RETURN +KMF_CreateCertFile(KMF_DATA *certdata, KMF_ENCODE_FORMAT format, + char *certfile) +{ + KMF_RETURN rv = KMF_OK; + int fd = -1; + KMF_DATA pemdata = {NULL, 0}; + + if (certdata == NULL || certfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1) + return (KMF_ERR_BAD_PARAMETER); + + if (format == KMF_FORMAT_PEM) { + int len; + rv = KMF_Der2Pem(KMF_CERT, + certdata->Data, certdata->Length, + &pemdata.Data, &len); + if (rv != KMF_OK) + goto cleanup; + pemdata.Length = (size_t)len; + } + + if ((fd = open(certfile, O_CREAT |O_RDWR, 0644)) == -1) { + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (format == KMF_FORMAT_PEM) { + if (write(fd, pemdata.Data, pemdata.Length) != + pemdata.Length) { + rv = KMF_ERR_WRITE_FILE; + } + } else { + if (write(fd, certdata->Data, certdata->Length) != + certdata->Length) { + rv = KMF_ERR_WRITE_FILE; + } + } + +cleanup: + if (fd != -1) + (void) close(fd); + + KMF_FreeData(&pemdata); + + return (rv); +} + +KMF_RETURN +KMF_IsCertFile(KMF_HANDLE_T handle, char *filename, KMF_ENCODE_FORMAT *pformat) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*IsCertFileFn)(void *, char *, KMF_ENCODE_FORMAT *); + + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (filename == NULL || pformat == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * This framework function is actually implemented in the openssl + * plugin library, so we find the function address and call it. + */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + IsCertFileFn = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_IsCertFile"); + if (IsCertFileFn == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (IsCertFileFn(handle, filename, pformat)); +} + +/* + * This function checks the validity period of a der-encoded certificate. + */ +KMF_RETURN +KMF_CheckCertDate(KMF_HANDLE_T handle, KMF_DATA *cert) +{ + KMF_RETURN rv; + struct tm *gmt; + time_t t_now; + time_t t_notbefore; + time_t t_notafter; + KMF_POLICY_RECORD *policy; + uint32_t adj; + + CLEAR_ERROR(handle, rv); + if (rv != KMF_OK) + return (rv); + + if (cert == NULL || cert->Data == NULL || + cert->Length == 0) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + rv = KMF_GetCertValidity(cert, &t_notbefore, &t_notafter); + if (rv != KMF_OK) + return (rv); + + /* + * Get the current time. The time returned from time() is local which + * cannot be used directly. It must be converted to UTC/GMT first. + */ + t_now = time(NULL); + gmt = gmtime(&t_now); + t_now = mktime(gmt); + + /* + * Adjust the validity time + */ + if (policy->validity_adjusttime != NULL) { + if (str2lifetime(policy->validity_adjusttime, &adj) < 0) + return (KMF_ERR_VALIDITY_PERIOD); + } else { + adj = 0; + } + + t_notafter += adj; + t_notbefore -= adj; + + if (t_now <= t_notafter && t_now >= t_notbefore) { + rv = KMF_OK; + } else { + rv = KMF_ERR_VALIDITY_PERIOD; + } + + return (rv); +} + +KMF_RETURN +KMF_ExportPK12(KMF_HANDLE_T handle, + KMF_EXPORTP12_PARAMS *params, + char *filename) +{ + KMF_RETURN rv; + KMF_PLUGIN *plugin; + KMF_KEYSTORE_TYPE kstype; + KMF_X509_DER_CERT *certlist = NULL; + KMF_KEY_HANDLE *keys = NULL; + uint32_t numkeys; + uint32_t numcerts; + int i; + + CLEAR_ERROR(handle, rv); + if (rv != KMF_OK) + return (rv); + + if (params == NULL || filename == NULL) + return (KMF_ERR_BAD_PARAMETER); + kstype = params->kstype; + if (kstype == KMF_KEYSTORE_PK11TOKEN) { + KMF_FINDCERT_PARAMS fcargs; + + (void) memset(&fcargs, 0, sizeof (fcargs)); + + fcargs.kstype = kstype; + fcargs.certLabel = params->certLabel; + fcargs.issuer = params->issuer; + fcargs.subject = params->subject; + fcargs.serial = params->serial; + fcargs.idstr = params->idstr; + + /* + * Special processing because PKCS11 doesn't have + * a native PKCS12 operation. + */ + rv = KMF_FindCert(handle, &fcargs, NULL, &numcerts); + if (rv == KMF_OK && numcerts > 0) { + certlist = (KMF_X509_DER_CERT *)malloc(numcerts * + sizeof (KMF_X509_DER_CERT)); + if (certlist == NULL) + return (KMF_ERR_MEMORY); + (void) memset(certlist, 0, numcerts * + sizeof (KMF_X509_DER_CERT)); + rv = KMF_FindCert(handle, &fcargs, + certlist, &numcerts); + if (rv != KMF_OK) { + free(certlist); + return (rv); + } + } else { + return (rv); + } + + numkeys = 0; + for (i = 0; i < numcerts; i++) { + KMF_CRYPTOWITHCERT_PARAMS fkparms; + KMF_KEY_HANDLE newkey; + + fkparms.kstype = kstype; + fkparms.format = KMF_FORMAT_RAWKEY; + fkparms.cred = params->cred; + fkparms.certLabel = certlist[i].kmf_private.label; + + rv = find_private_key_by_cert(handle, &fkparms, + &certlist[i].certificate, &newkey); + if (rv == KMF_OK) { + numkeys++; + keys = realloc(keys, + numkeys * sizeof (KMF_KEY_HANDLE)); + if (keys == NULL) { + free(certlist); + rv = KMF_ERR_MEMORY; + goto out; + } + keys[numkeys - 1] = newkey; + } else if (rv == KMF_ERR_KEY_NOT_FOUND) { + /* it is OK if a key is not found */ + rv = KMF_OK; + } + } + if (rv == KMF_OK) { + /* + * Switch the keystore type to use OpenSSL for + * exporting the raw cert and key data as PKCS12. + */ + kstype = KMF_KEYSTORE_OPENSSL; + } else { + rv = KMF_ERR_KEY_NOT_FOUND; + goto out; + } + } + plugin = FindPlugin(handle, kstype); + if (plugin != NULL && plugin->funclist->ExportP12 != NULL) { + rv = plugin->funclist->ExportP12(handle, + params, numcerts, certlist, + numkeys, keys, filename); + } else { + rv = KMF_ERR_PLUGIN_NOTFOUND; + } + +out: + if (certlist != NULL) { + for (i = 0; i < numcerts; i++) + KMF_FreeKMFCert(handle, &certlist[i]); + free(certlist); + } + if (keys != NULL) { + for (i = 0; i < numkeys; i++) + KMF_FreeKMFKey(handle, &keys[i]); + free(keys); + } + + return (rv); +} + +KMF_RETURN +KMF_ImportPK12(KMF_HANDLE_T handle, char *filename, + KMF_CREDENTIAL *cred, + KMF_DATA **certs, int *ncerts, + KMF_RAW_KEY_DATA **rawkeys, int *nkeys) +{ + KMF_RETURN rv; + KMF_PLUGIN *plugin; + KMF_RETURN (*openpkcs12)(KMF_HANDLE *, + char *, KMF_CREDENTIAL *, + KMF_DATA **, int *, + KMF_RAW_KEY_DATA **, int *); + + CLEAR_ERROR(handle, rv); + if (rv != KMF_OK) + return (rv); + + if (filename == NULL || + cred == NULL || + certs == NULL || ncerts == NULL || + rawkeys == NULL || nkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Use the pkcs12 reader from the OpenSSL plugin. + */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + openpkcs12 = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "openssl_read_pkcs12"); + if (openpkcs12 == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + /* Use OpenSSL interfaces to get raw key and cert data */ + rv = openpkcs12(handle, filename, cred, certs, ncerts, + rawkeys, nkeys); + + return (rv); +} + + +KMF_BOOL +IsEqualOid(KMF_OID *Oid1, KMF_OID *Oid2) +{ + return ((Oid1->Length == Oid2->Length) && + !memcmp(Oid1->Data, Oid2->Data, Oid1->Length)); +} + +static KMF_RETURN +copy_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid, + KMF_X509_ALGORITHM_IDENTIFIER *srcid) +{ + KMF_RETURN ret = KMF_OK; + if (!destid || !srcid) + return (KMF_ERR_BAD_PARAMETER); + + destid->algorithm.Length = srcid->algorithm.Length; + destid->algorithm.Data = malloc(destid->algorithm.Length); + if (destid->algorithm.Data == NULL) + return (KMF_ERR_MEMORY); + + (void) memcpy(destid->algorithm.Data, srcid->algorithm.Data, + destid->algorithm.Length); + + destid->parameters.Length = srcid->parameters.Length; + if (destid->parameters.Length > 0) { + destid->parameters.Data = malloc(destid->parameters.Length); + if (destid->parameters.Data == NULL) + return (KMF_ERR_MEMORY); + + (void) memcpy(destid->parameters.Data, srcid->parameters.Data, + destid->parameters.Length); + } else { + destid->parameters.Data = NULL; + } + return (ret); +} + +KMF_RETURN +SignCert(KMF_HANDLE_T handle, + const KMF_DATA *SubjectCert, + KMF_KEY_HANDLE *Signkey, + KMF_DATA *SignedCert) +{ + KMF_X509_CERTIFICATE *subj_cert = NULL; + KMF_DATA data_to_sign = {0, NULL}; + KMF_DATA signed_data = {0, NULL}; + KMF_RETURN ret = KMF_OK; + KMF_ALGORITHM_INDEX algid; + + if (!SignedCert) + return (KMF_ERR_BAD_PARAMETER); + + SignedCert->Length = 0; + SignedCert->Data = NULL; + + if (!SubjectCert) + return (KMF_ERR_BAD_PARAMETER); + + if (!SubjectCert->Data || !SubjectCert->Length) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Shortcut - just extract the already encoded TBS cert data from + * the original data buffer. Since we haven't changed anything, + * there is no need to re-encode it. + */ + ret = ExtractX509CertParts((KMF_DATA *)SubjectCert, + &data_to_sign, NULL); + if (ret != KMF_OK) { + goto cleanup; + } + + /* Estimate the signed data length generously */ + signed_data.Length = data_to_sign.Length*2; + signed_data.Data = calloc(1, signed_data.Length); + if (!signed_data.Data) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + /* + * If we got here OK, decode into a structure and then re-encode + * the complete certificate. + */ + ret = DerDecodeSignedCertificate(SubjectCert, &subj_cert); + if (ret != KMF_OK) { + goto cleanup; + } + + /* We are re-signing this cert, so clear out old signature data */ + if (subj_cert->signature.algorithmIdentifier.algorithm.Length == 0) { + KMF_FreeAlgOID(&subj_cert->signature.algorithmIdentifier); + ret = copy_algoid(&subj_cert->signature.algorithmIdentifier, + &subj_cert->certificate.signature); + } + + if (ret) + goto cleanup; + + /* Sign the data */ + ret = KMF_SignDataWithKey(handle, Signkey, + CERT_ALG_OID(subj_cert), + &data_to_sign, &signed_data); + + if (ret != KMF_OK) + goto cleanup; + + algid = X509_AlgorithmOidToAlgId(CERT_SIG_OID(subj_cert)); + + /* + * For DSA, KMF_SignDataWithKey() returns a 40-bytes decoded + * signature. So we must encode the signature correctly. + */ + if (algid == KMF_ALGID_SHA1WithDSA) { + + KMF_DATA signature; + + ret = DerEncodeDSASignature(&signed_data, &signature); + KMF_FreeData(&signed_data); + + if (ret != KMF_OK) + goto cleanup; + + subj_cert->signature.encrypted = signature; + } else { + subj_cert->signature.encrypted = signed_data; + } + + /* Now, re-encode the cert with the new signature */ + ret = DerEncodeSignedCertificate(subj_cert, SignedCert); + +cleanup: + /* Cleanup & return */ + if (ret != KMF_OK) + KMF_FreeData(SignedCert); + + KMF_FreeData(&data_to_sign); + + if (subj_cert != NULL) { + KMF_FreeSignedCert(subj_cert); + free(subj_cert); + } + + return (ret); +} + +KMF_RETURN +VerifyCertWithKey(KMF_HANDLE_T handle, + KMF_DATA *derkey, + const KMF_DATA *CertToBeVerified) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *signed_cert = NULL; + KMF_X509_SPKI spki; + KMF_DATA data_to_verify = {0, NULL}; + KMF_DATA signed_data = {0, NULL}; + KMF_DATA signature = { 0, NULL }; + KMF_ALGORITHM_INDEX algid; + + /* check the caller and do other setup for this SPI call */ + if (handle == NULL || CertToBeVerified == NULL || + derkey == NULL || derkey->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&spki, 0, sizeof (KMF_X509_SPKI)); + + ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerified, + &data_to_verify, &signed_data); + + if (ret != KMF_OK) + goto cleanup; + + ret = DerDecodeSPKI(derkey, &spki); + if (ret != KMF_OK) + goto cleanup; + + /* Decode the signer cert so we can get the Algorithm data */ + ret = DerDecodeSignedCertificate(CertToBeVerified, &signed_cert); + if (ret != KMF_OK) + return (ret); + + algid = X509_AlgorithmOidToAlgId(CERT_SIG_OID(signed_cert)); + + if (algid == KMF_ALGID_NONE) + return (KMF_ERR_BAD_ALGORITHM); + + if (algid == KMF_ALGID_SHA1WithDSA) { + ret = DerDecodeDSASignature(&signed_data, &signature); + if (ret != KMF_OK) + goto cleanup; + } else { + signature.Data = signed_data.Data; + signature.Length = signed_data.Length; + } + + ret = PKCS_VerifyData(handle, algid, &spki, + &data_to_verify, &signature); + +cleanup: + if (data_to_verify.Data != NULL) + free(data_to_verify.Data); + + if (signed_data.Data != NULL) + free(signed_data.Data); + + if (signed_cert) { + KMF_FreeSignedCert(signed_cert); + free(signed_cert); + } + if (algid == KMF_ALGID_SHA1WithDSA) { + free(signature.Data); + } + + KMF_FreeAlgOID(&spki.algorithm); + KMF_FreeData(&spki.subjectPublicKey); + + return (ret); +} + +KMF_RETURN +VerifyDataWithKey(KMF_HANDLE_T handle, + KMF_DATA *derkey, + KMF_ALGORITHM_INDEX sigAlg, + KMF_DATA *indata, + KMF_DATA *insig) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_SPKI spki; + + if (!indata || !insig || !derkey || !derkey->Data) + return (KMF_ERR_BAD_PARAMETER); + + ret = DerDecodeSPKI(derkey, &spki); + if (ret != KMF_OK) + goto cleanup; + + ret = PKCS_VerifyData(handle, sigAlg, &spki, indata, insig); + +cleanup: + KMF_FreeAlgOID(&spki.algorithm); + KMF_FreeData(&spki.subjectPublicKey); + + return (ret); +} + +KMF_RETURN +VerifyCertWithCert(KMF_HANDLE_T handle, + const KMF_DATA *CertToBeVerifiedData, + const KMF_DATA *SignerCertData) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_X509_CERTIFICATE *ToBeVerifiedCert = NULL; + KMF_X509_SPKI *pubkey; + KMF_DATA data_to_verify = {0, NULL}; + KMF_DATA signed_data = {0, NULL}; + KMF_DATA signature; + KMF_ALGORITHM_INDEX algid; + + if (!CertToBeVerifiedData || + !CertToBeVerifiedData->Data || + !CertToBeVerifiedData->Length) + return (KMF_ERR_BAD_PARAMETER); + + if (!SignerCertData || + !SignerCertData->Data || + !SignerCertData->Length) + return (KMF_ERR_BAD_PARAMETER); + + /* Decode the cert into parts for verification */ + ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerifiedData, + &data_to_verify, &signed_data); + if (ret != KMF_OK) + goto cleanup; + + /* Decode the signer cert so we can get the SPKI data */ + ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert); + if (ret != KMF_OK) + goto cleanup; + + /* + * TODO ! Validate the SignerCert to make sure it is OK to be + * used to verify other certs. Or - should this be done the calling + * application? + */ + /* ValidateCert(SignerCert); */ + + /* Get the public key info from the signer certificate */ + pubkey = &SignerCert->certificate.subjectPublicKeyInfo; + + /* Decode the to-be-verified cert so we know what algorithm to use */ + ret = DerDecodeSignedCertificate(CertToBeVerifiedData, + &ToBeVerifiedCert); + + if (ret != KMF_OK) + goto cleanup; + + algid = X509_AlgorithmOidToAlgId(CERT_SIG_OID(ToBeVerifiedCert)); + + if (algid == KMF_ALGID_SHA1WithDSA) { + ret = DerDecodeDSASignature(&signed_data, &signature); + if (ret != KMF_OK) + goto cleanup; + } else { + signature.Data = signed_data.Data; + signature.Length = signed_data.Length; + } + + ret = PKCS_VerifyData(handle, algid, pubkey, + &data_to_verify, &signature); + +cleanup: + KMF_FreeData(&data_to_verify); + KMF_FreeData(&signed_data); + + if (SignerCert) { + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + } + + if (ToBeVerifiedCert) { + KMF_FreeSignedCert(ToBeVerifiedCert); + free(ToBeVerifiedCert); + } + + if (algid == KMF_ALGID_SHA1WithDSA) { + free(signature.Data); + } + + return (ret); +} + +KMF_RETURN +VerifyDataWithCert(KMF_HANDLE_T handle, + KMF_DATA *indata, + KMF_DATA *insig, + const KMF_DATA *SignerCertData) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_X509_SPKI *pubkey; + KMF_ALGORITHM_INDEX algid; + + if (!indata || + !indata->Data || + !indata->Length) + return (KMF_ERR_BAD_PARAMETER); + + if (!insig || + !insig->Data || + !insig->Length) + return (KMF_ERR_BAD_PARAMETER); + + + if (!SignerCertData || + !SignerCertData->Data || + !SignerCertData->Length) + return (KMF_ERR_BAD_PARAMETER); + + /* Decode the signer cert so we can get the SPKI data */ + ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert); + if (ret != KMF_OK) + goto cleanup; + + /* Get the public key info from the signer certificate */ + pubkey = &SignerCert->certificate.subjectPublicKeyInfo; + + algid = X509_AlgorithmOidToAlgId(CERT_ALG_OID(SignerCert)); + if (algid == KMF_ALGID_NONE) { + ret = KMF_ERR_BAD_ALGORITHM; + } else { + ret = PKCS_VerifyData(handle, algid, + pubkey, indata, insig); + } + +cleanup: + if (SignerCert) { + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + } + + return (ret); +} + +KMF_RETURN +SignCsr(KMF_HANDLE_T handle, + const KMF_DATA *SubjectCsr, + KMF_KEY_HANDLE *Signkey, + KMF_X509_ALGORITHM_IDENTIFIER *algo, + KMF_DATA *SignedCsr) +{ + + KMF_CSR_DATA subj_csr; + KMF_TBS_CSR *tbs_csr = NULL; + KMF_DATA signed_data = {0, NULL}; + KMF_RETURN ret = KMF_OK; + + if (!SignedCsr) + return (KMF_ERR_BAD_PARAMETER); + + SignedCsr->Length = 0; + SignedCsr->Data = NULL; + + if (!SubjectCsr) + return (KMF_ERR_BAD_PARAMETER); + + if (!SubjectCsr->Data || !SubjectCsr->Length) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&subj_csr, 0, sizeof (subj_csr)); + /* Estimate the signed data length generously */ + signed_data.Length = SubjectCsr->Length*2; + signed_data.Data = calloc(1, signed_data.Length); + if (!signed_data.Data) { + ret = KMF_ERR_MEMORY; + goto cleanup; + } + + /* Sign the data */ + ret = KMF_SignDataWithKey(handle, Signkey, &algo->algorithm, + (KMF_DATA *)SubjectCsr, &signed_data); + + if (KMF_OK != ret) + goto cleanup; + + /* + * If we got here OK, decode into a structure and then re-encode + * the complete CSR. + */ + ret = DerDecodeTbsCsr(SubjectCsr, &tbs_csr); + if (ret) + goto cleanup; + + (void) memcpy(&subj_csr.csr, tbs_csr, sizeof (KMF_TBS_CSR)); + + ret = copy_algoid(&subj_csr.signature.algorithmIdentifier, algo); + if (ret) + goto cleanup; + + subj_csr.signature.encrypted = signed_data; + + /* Now, re-encode the CSR with the new signature */ + ret = DerEncodeSignedCsr(&subj_csr, SignedCsr); + if (ret != KMF_OK) { + KMF_FreeData(SignedCsr); + goto cleanup; + } + + /* Cleanup & return */ +cleanup: + free(tbs_csr); + + KMF_FreeTBSCSR(&subj_csr.csr); + + KMF_FreeAlgOID(&subj_csr.signature.algorithmIdentifier); + KMF_FreeData(&signed_data); + + return (ret); +} + +KMF_RETURN +EncryptWithCert(KMF_HANDLE_T handle, + KMF_DATA *cert, + KMF_DATA *plaintext, + KMF_DATA *ciphertext) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *x509cert = NULL; + KMF_X509_SPKI *pubkey; + KMF_OID *alg; + KMF_ALGORITHM_INDEX algid; + + /* Decode the cert so we can get the SPKI data */ + if ((ret = DerDecodeSignedCertificate(cert, &x509cert)) != KMF_OK) + return (ret); + + /* Get the public key info from the certificate */ + pubkey = &x509cert->certificate.subjectPublicKeyInfo; + + /* Use the algorithm in SPKI to encrypt data */ + alg = &pubkey->algorithm.algorithm; + + algid = X509_AlgorithmOidToAlgId(alg); + + /* DSA does not support encrypt */ + if (algid == KMF_ALGID_DSA || algid == KMF_ALGID_NONE) { + KMF_FreeSignedCert(x509cert); + free(x509cert); + return (KMF_ERR_BAD_ALGORITHM); + } + + ret = PKCS_EncryptData(handle, algid, pubkey, plaintext, ciphertext); + KMF_FreeSignedCert(x509cert); + free(x509cert); + + return (ret); +} diff --git a/usr/src/lib/libkmf/libkmf/common/client.c b/usr/src/lib/libkmf/libkmf/common/client.c new file mode 100644 index 0000000000..15c158312e --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/client.c @@ -0,0 +1,954 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * File: CLIENT.C + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <poll.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <unistd.h> +#include <libgen.h> +#include <kmfapi.h> +#include <kmfapiP.h> +#include <libxml2/libxml/uri.h> + +extern int errno; + +#define OCSP_BUFSIZE 1024 + +typedef enum { + KMF_RESPONSE_OCSP = 1, + KMF_RESPONSE_FILE = 2 +} KMF_RESPONSE_TYPE; + +#define TEMP_TEMPLATE "temp.XXXXXX" + +/* + * This function will establish a socket to the host on the specified port. + * If succeed, it return a socket descriptor; otherwise, return -1. + */ +static int init_socket(char *host, short port) +{ + struct sockaddr_in sin; + struct hostent *hp, hrec; + int sockfd, opt, herrno; + char hostbuf[BUFSIZ]; + + sin.sin_family = PF_INET; + sin.sin_port = htons(port); + if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { + if ((hp = gethostbyname_r(host, &hrec, hostbuf, + sizeof (hostbuf), &herrno)) == NULL) { + return (-1); + } + (void) memcpy((char *)&sin.sin_addr, hp->h_addr, + hp->h_length); + } + + if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + return (-1); + } + + opt = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, + sizeof (opt)) < 0) { + (void) close(sockfd); + return (-1); + } + + if (connect(sockfd, (struct sockaddr *)&sin, sizeof (sin)) < 0) { + (void) close(sockfd); + return (-1); + } + + return (sockfd); +} + +/* + * This function will connect to host on the port. + * If succeed, return a socket descriptor; otherwise, return 0. + */ +static int +connect_to_server(char *host, short port) +{ + int retry = 1; + int sd = 0; + + while (retry) { + if ((sd = init_socket(host, port)) == -1) { + if (errno == ECONNREFUSED) { + retry = 1; + (void) sleep(1); + } else { + retry = 0; + } + } else { + retry = 0; + } + } + return (sd); +} + +static KMF_RETURN +send_ocsp_request(int sock, char *reqfile, char *hostname) +{ + KMF_RETURN ret = KMF_OK; + int filefd, bytes, n, total = 0; + char buf[OCSP_BUFSIZE]; + struct stat s; + char req_header[256]; + static char req_format[] = +"POST %s HTTP/1.0\r\n\ +Content-Type: application/ocsp-request\r\n\ +Content-Length: %d\r\n\r\n"; + + if ((filefd = open(reqfile, O_RDONLY)) == -1) { + ret = KMF_ERR_OPEN_FILE; + return (ret); + } + + /* open the request file */ + if (fstat(filefd, &s) < 0) { + ret = KMF_ERR_OPEN_FILE; + return (ret); + } + + + /* Send http header */ + if (hostname != NULL) { + (void) snprintf(req_header, 256, req_format, hostname, + s.st_size); + } else { + (void) snprintf(req_header, 256, req_format, "/", s.st_size); + } + bytes = strlen(req_header); + + if ((n = write(sock, req_header, bytes)) < 0) { + ret = KMF_ERR_SEND_REQUEST; + goto exit; + } + + /* Send the request content */ + while ((bytes = read(filefd, buf, OCSP_BUFSIZE)) > 0) { + if ((n = write(sock, buf, bytes)) < 0) { + ret = KMF_ERR_SEND_REQUEST; + goto exit; + } + total += n; + (void) memset(buf, 0, sizeof (buf)); + } + +exit: + (void) close(filefd); + return (ret); +} + + +/* + * Perform a write that can handle EINTR. + */ +static int +looping_write(int fd, void *buf, int len) +{ + char *p = buf; + int cc, len2 = 0; + + if (len == 0) + return (0); + do { + cc = write(fd, p, len); + if (cc < 0) { + if (errno == EINTR) + continue; + return (cc); + } else if (cc == 0) { + return (len2); + } else { + p += cc; + len2 += cc; + len -= cc; + } + } while (len > 0); + + return (len2); +} + +/* + * This function will get the response from the server, check the http status + * line, and write the response content to a file. If this is a OCSP response, + * it will check the content type also. + */ +static KMF_RETURN +get_encoded_response(int sock, KMF_RESPONSE_TYPE resptype, int filefd, + unsigned int maxsecs) +{ + int ret = KMF_OK; + char *buf = NULL; + int buflen = 0; + int offset = 0; + int search_offset; + const int buf_incre = OCSP_BUFSIZE; /* 1 KB at a time */ + const int maxBufSize = 8 * buf_incre; /* 8 KB max */ + const char *CRLF = "\r\n"; + const char *headerEndMark = "\r\n\r\n"; + const char *httpprotocol = "HTTP/"; + const int CRLFlen = strlen(CRLF); + const int marklen = strlen(headerEndMark); + const int httplen = strlen(httpprotocol); + char *headerEnd = NULL; + boolean_t EOS = B_FALSE; + const char *httpcode = NULL; + const char *contenttype = NULL; + int contentlength = 0; + int bytes = 0; + char *statusLineEnd = NULL; + char *space = NULL; + char *nextHeader = NULL; + struct pollfd pfd; + int sock_flag; + int poll_ret; + boolean_t timeout = B_FALSE; + + /* set O_NONBLOCK flag on socket */ + if ((sock_flag = fcntl(sock, F_GETFL, 0)) == -1) { + return (KMF_ERR_RECV_RESPONSE); + } + sock_flag |= O_NONBLOCK; + if (fcntl(sock, F_SETFL, sock_flag) == -1) { + return (KMF_ERR_RECV_RESPONSE); + } + + /* set up poll */ + pfd.fd = sock; + pfd.events = POLLIN; + + /* + * First read HTTP status line and headers. We will read up to at + * least the end of the HTTP headers + */ + do { + if ((buflen - offset) < buf_incre) { + buflen += buf_incre; + buf = realloc(buf, buflen + 1); + if (buf == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + } + + pfd.revents = 0; + poll_ret = poll(&pfd, 1, maxsecs * MILLISEC); + if (poll_ret == 0) { + timeout = B_TRUE; + break; + } else if (poll_ret < 0) { + ret = KMF_ERR_RECV_RESPONSE; + goto out; + } else { + if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + ret = KMF_ERR_RECV_RESPONSE; + goto out; + } + } + + bytes = read(sock, buf + offset, buf_incre); + if (bytes < 0) { + if (errno == EWOULDBLOCK) { /* no data this time */ + continue; + } else { + ret = KMF_ERR_RECV_RESPONSE; + goto out; + } + } else if (bytes == 0) { /* no more data */ + EOS = B_TRUE; + } else { /* bytes > 0 */ + search_offset = (offset - marklen) > 0 ? + offset - marklen : 0; + offset += bytes; + *(buf + offset) = '\0'; /* NULL termination */ + + headerEnd = strstr((const char *)buf + search_offset, + headerEndMark); + } + + } while ((!headerEnd) && (EOS == B_FALSE) && (buflen < maxBufSize)); + + if (timeout == B_TRUE) { + ret = KMF_ERR_RECV_TIMEOUT; + goto out; + } else if (headerEnd == NULL) { + /* could not find the end of headers */ + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + + /* + * Parse the HTTP status line, which will look like this: + * "HTTP/1.1 200 OK". + */ + statusLineEnd = strstr((const char *)buf, CRLF); + if (statusLineEnd == NULL) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + *statusLineEnd = '\0'; + + space = strchr((const char *)buf, ' '); + if (space == NULL || + (strncasecmp((const char *)buf, httpprotocol, httplen) != 0)) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + + /* + * Check the HTTP status code. If it is not 200, the HTTP response + * is not good. + */ + httpcode = space + 1; + space = strchr(httpcode, ' '); + if (space == NULL) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + + *space = 0; + if (strcmp(httpcode, "200") != 0) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + + /* + * Parse the HTTP headers in the buffer. Save content-type and + * content-length only. + */ + nextHeader = statusLineEnd + CRLFlen; + *headerEnd = '\0'; /* terminate */ + do { + char *thisHeaderEnd = NULL; + char *value = NULL; + char *colon = strchr(nextHeader, ':'); + + if (colon == NULL) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + *colon = '\0'; + + value = colon + 1; + if (*value != ' ') { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + value++; + + thisHeaderEnd = strstr(value, CRLF); + if (thisHeaderEnd != NULL) + *thisHeaderEnd = '\0'; + + if (strcasecmp(nextHeader, "content-type") == 0) { + contenttype = value; + } else if (strcasecmp(nextHeader, "content-length") == 0) { + contentlength = atoi(value); + } + + if (thisHeaderEnd != NULL) { + nextHeader = thisHeaderEnd + CRLFlen; + } else { + nextHeader = NULL; + } + + } while (nextHeader && (nextHeader < (headerEnd + CRLFlen))); + + /* Check the contenttype if this is an OCSP response */ + if (resptype == KMF_RESPONSE_OCSP) { + if (contenttype == NULL) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } else if (strcasecmp(contenttype, + "application/ocsp-response") != 0) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + } + + /* Now we are ready to read the body of the response */ + offset = offset - (int)(headerEnd - (const char *)buf) - marklen; + if (offset) { + /* move all data to the beginning of the buffer */ + (void) memmove(buf, headerEnd + marklen, offset); + } + + /* resize buffer to only what's needed to hold the current response */ + buflen = (1 + (offset-1) / buf_incre) * buf_incre; + + while ((EOS == B_FALSE) && + ((contentlength == 0) || (offset < contentlength)) && + (buflen < maxBufSize)) { + /* we still need to receive more content data */ + if ((buflen - offset) < buf_incre) { + buflen += buf_incre; + buf = realloc(buf, buflen + 1); + if (buf == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + } + + pfd.revents = 0; + poll_ret = poll(&pfd, 1, maxsecs * MILLISEC); + if (poll_ret == 0) { + timeout = B_TRUE; + break; + } else if (poll_ret < 0) { + ret = KMF_ERR_RECV_RESPONSE; + goto out; + } else { + if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + ret = KMF_ERR_RECV_RESPONSE; + goto out; + } + } + + bytes = read(sock, buf + offset, buf_incre); + if (bytes < 0) { + if (errno == EWOULDBLOCK) { + continue; + } else { + ret = KMF_ERR_RECV_RESPONSE; + goto out; + } + } else if (bytes == 0) { /* no more data */ + EOS = B_TRUE; + } else { + offset += bytes; + } + } + + if (timeout == B_TRUE) { + ret = KMF_ERR_RECV_TIMEOUT; + goto out; + } else if (((contentlength != 0) && (offset < contentlength)) || + offset == 0) { + ret = KMF_ERR_BAD_HTTP_RESPONSE; + goto out; + } + + /* write to the file */ + if (looping_write(filefd, buf, offset) != offset) { + ret = KMF_ERR_WRITE_FILE; + } + +out: + free(buf); + return (ret); +} + +KMF_RETURN +KMF_GetEncodedOCSPResponse(KMF_HANDLE_T handle, char *reqfile, char *hostname, + int port, char *proxy, int proxy_port, char *respfile, + unsigned int maxsecs) +{ + KMF_RETURN ret = KMF_OK; + int sock, respfd; + char http_hostname[256]; + int final_proxy_port, final_port; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (hostname == NULL || reqfile == NULL || respfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + final_proxy_port = (proxy_port == 0 || proxy_port == -1) ? + 80 : proxy_port; + final_port = (port == 0 || port == -1) ? 80 : port; + + /* Connect to server */ + if (proxy != NULL) { + sock = connect_to_server(proxy, final_proxy_port); + } else { + sock = connect_to_server(hostname, final_port); + } + + if (sock == -1) { + return (KMF_ERR_CONNECT_SERVER); + } + + /* Send the OCSP request */ + if (proxy != NULL) { + (void) snprintf(http_hostname, sizeof (http_hostname), + "http://%s:%d", hostname, final_port); + ret = send_ocsp_request(sock, reqfile, http_hostname); + } else { + ret = send_ocsp_request(sock, reqfile, NULL); + } + + if (ret != KMF_OK) { + goto out; + } + + /* Retrieve the OCSP response */ + if (maxsecs == 0) { + maxsecs = 30; /* default poll time limit is 30 seconds */ + } + + if ((respfd = open(respfile, O_CREAT |O_RDWR | O_EXCL, 0600)) == -1) { + ret = KMF_ERR_OPEN_FILE; + } else { + ret = get_encoded_response(sock, KMF_RESPONSE_OCSP, + respfd, maxsecs); + (void) close(respfd); + } + +out: + (void) close(sock); + return (ret); +} + +static KMF_RETURN +send_download_request(int sock, char *hostname, int port, boolean_t is_proxy, + char *loc) +{ + KMF_RETURN ret = KMF_OK; + char url[256]; + char req_header[1024]; + static char req_format[] = +"GET %s HTTP/1.0\r\n\ +Host: %s:%d\r\n\ +Accept: */*\r\n\r\n"; + + if (is_proxy) { + (void) snprintf(url, sizeof (url), "http://%s:%d/%s", + hostname, port, loc); + } else { + (void) snprintf(url, sizeof (url), "/%s", loc); + } + + (void) snprintf(req_header, sizeof (req_header), req_format, url, + hostname, port); + + if (write(sock, req_header, strlen(req_header)) < 0) { + ret = KMF_ERR_SEND_REQUEST; + } + + return (ret); +} + +static KMF_RETURN +download_file(char *uri, char *proxy, int proxy_port, + unsigned int maxsecs, int filefd) +{ + KMF_RETURN ret = KMF_OK; + xmlURIPtr uriptr; + int sock; + boolean_t is_proxy; + int final_proxy_port; + char *hostname = NULL; + char *path = NULL; + int port; + + if (uri == NULL || filefd == -1) + return (KMF_ERR_BAD_PARAMETER); + + /* Parse URI */ + uriptr = xmlParseURI(uri); + if (uriptr == NULL) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + if (uriptr->scheme == NULL || + strncasecmp(uriptr->scheme, "http", 4) != 0) { + ret = KMF_ERR_BAD_URI; /* we support http only */ + goto out; + } + + /* get the host name */ + hostname = uriptr->server; + if (hostname == NULL) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + /* get the port number */ + port = uriptr->port; + if (port == 0) { + port = 80; + } + + /* Get the path */ + path = uriptr->path; + if (path == NULL) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + /* Connect to server */ + if (proxy != NULL) { + final_proxy_port = (proxy_port == 0 || proxy_port == -1) ? + 80 : proxy_port; + is_proxy = B_TRUE; + sock = connect_to_server(proxy, final_proxy_port); + } else { + is_proxy = B_FALSE; + sock = connect_to_server(hostname, port); + } + if (sock == -1) { + ret = KMF_ERR_CONNECT_SERVER; + goto out; + } + + /* Send the request */ + ret = send_download_request(sock, hostname, port, is_proxy, path); + if (ret != KMF_OK) { + goto out; + } + + /* Retrieve the response */ + ret = get_encoded_response(sock, KMF_RESPONSE_FILE, filefd, + maxsecs == 0 ? 30 : maxsecs); + if (ret != KMF_OK) { + goto out; + } + +out: + if (uriptr != NULL) + xmlFreeURI(uriptr); + + if (sock != -1) + (void) close(sock); + + return (ret); +} + + +KMF_RETURN +KMF_DownloadCRL(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port, + unsigned int maxsecs, char *crlfile, KMF_ENCODE_FORMAT *pformat) +{ + KMF_RETURN ret = KMF_OK; + char *filename = NULL; + char tempfn[MAXPATHLEN]; + boolean_t temp_created = B_FALSE; + mode_t old_mode; + int fd = -1, tmpfd = -1; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (uri == NULL || crlfile == NULL || pformat == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if ((fd = open(crlfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1) + return (KMF_ERR_OPEN_FILE); + + /* + * Download the file and save it to a temp file. To make rename() + * happy, the temp file needs to be created in the same directory as + * the target file. + */ + if ((filename = strdup(crlfile)) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename), + TEMP_TEMPLATE); + old_mode = umask(077); + tmpfd = mkstemp(tempfn); + (void) umask(old_mode); + if (tmpfd == -1) { + ret = KMF_ERR_INTERNAL; + goto out; + } else { + temp_created = B_TRUE; + } + + ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd); + (void) close(tmpfd); + if (ret != KMF_OK) { + goto out; + } + + /* Check if it is a CRL file and get its format */ + if (KMF_IsCRLFile(handle, tempfn, pformat) != KMF_OK) { + ret = KMF_ERR_BAD_CRLFILE; + goto out; + } + + /* Finally, change the temp filename to the target crlfile */ + if (rename(tempfn, crlfile) == -1) { + ret = KMF_ERR_WRITE_FILE; + goto out; + } + +out: + if (filename != NULL) + free(filename); + + if (ret != KMF_OK && temp_created == B_TRUE) + (void) unlink(tempfn); + + if (fd != -1) + (void) close(fd); + + return (ret); +} + + +KMF_RETURN +KMF_DownloadCert(KMF_HANDLE_T handle, char *uri, char *proxy, int proxy_port, + unsigned int maxsecs, char *certfile, KMF_ENCODE_FORMAT *pformat) +{ + KMF_RETURN ret = KMF_OK; + char *filename = NULL; + char tempfn[MAXPATHLEN]; + boolean_t temp_created = B_FALSE; + mode_t old_mode; + int fd = -1, tmpfd = -1; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (uri == NULL || certfile == NULL || pformat == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if ((fd = open(certfile, O_CREAT |O_RDWR | O_EXCL, 0644)) == -1) + return (KMF_ERR_OPEN_FILE); + + /* + * Download the file and save it to a temp file. To make rename() + * happy, the temp file needs to be created in the same directory as + * the target file. + */ + if ((filename = strdup(certfile)) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) snprintf(tempfn, MAXPATHLEN, "%s/%s", dirname(filename), + TEMP_TEMPLATE); + + old_mode = umask(077); + tmpfd = mkstemp(tempfn); + (void) umask(old_mode); + if (tmpfd == -1) { + ret = KMF_ERR_INTERNAL; + goto out; + } else { + temp_created = B_TRUE; + } + + ret = download_file(uri, proxy, proxy_port, maxsecs, tmpfd); + (void) close(tmpfd); + if (ret != KMF_OK) { + goto out; + } + + /* Check if it is a Cert file and get its format */ + if (KMF_IsCertFile(handle, tempfn, pformat) != KMF_OK) { + ret = KMF_ERR_BAD_CERTFILE; + goto out; + } + + /* Finally, change the temp filename to the target filename */ + if (rename(tempfn, certfile) == -1) { + ret = KMF_ERR_WRITE_FILE; + goto out; + } + +out: + if (filename != NULL) + free(filename); + + if (ret != KMF_OK && temp_created == B_TRUE) + (void) unlink(tempfn); + + if (fd != -1) + (void) close(fd); + + return (ret); +} + +KMF_RETURN +KMF_GetOCSPForCert(KMF_HANDLE_T handle, + KMF_DATA *user_cert, + KMF_DATA *ta_cert, + KMF_DATA *response) +{ + KMF_POLICY_RECORD *policy; + KMF_RETURN ret = KMF_OK; + KMF_OCSPREQUEST_PARAMS req_params; + char *hostname = NULL, *host_uri = NULL, *proxyname = NULL; + char *proxy_port_s = NULL; + int host_port = 0, proxy_port = 0; + char ocsp_reqname[MAXPATHLEN]; + char ocsp_respname[MAXPATHLEN]; + KMF_X509EXT_AUTHINFOACCESS aia; + int i; + boolean_t found = B_FALSE; + KMF_X509EXT_ACCESSDESC *access_info; + xmlURIPtr uriptr = NULL; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (user_cert == NULL || + ta_cert == NULL || response == NULL) + return (KMF_ERR_BAD_PARAMETER); + + policy = handle->policy; + + /* Create an OCSP request */ + req_params.issuer_cert = ta_cert; + req_params.user_cert = user_cert; + + /* + * Create temporary files to hold the OCSP request & response data. + */ + (void) strlcpy(ocsp_reqname, OCSPREQ_TEMPNAME, + sizeof (ocsp_reqname)); + if (mkstemp(ocsp_reqname) == -1) { + return (KMF_ERR_INTERNAL); + } + + (void) strlcpy(ocsp_respname, OCSPRESP_TEMPNAME, + sizeof (ocsp_respname)); + if (mkstemp(ocsp_respname) == -1) { + return (KMF_ERR_INTERNAL); + } + + ret = KMF_CreateOCSPRequest(handle, &req_params, ocsp_reqname); + if (ret != KMF_OK) { + goto out; + } + + if (policy->VAL_OCSP_BASIC.uri_from_cert == 0) { + if (policy->VAL_OCSP_BASIC.responderURI == NULL) { + ret = KMF_ERR_OCSP_POLICY; + goto out; + } + host_uri = policy->VAL_OCSP_BASIC.responderURI; + + } else { + /* + * Get the responder URI from certificate + * Authority Information Access + * thru OID_PKIX_AD_OCSP + */ + ret = KMF_GetCertAuthInfoAccessExt(user_cert, &aia); + if (ret != KMF_OK) { + goto out; + } + + for (i = 0; i < aia.numberOfAccessDescription; i++) { + access_info = &aia.AccessDesc[i]; + if (IsEqualOid(&access_info->AccessMethod, + (KMF_OID *)&KMFOID_PkixAdOcsp)) { + host_uri = + (char *)access_info->AccessLocation.Data; + found = B_TRUE; + break; + } + } + + if (!found) { + ret = KMF_ERR_OCSP_POLICY; + goto out; + } + } + + /* Parse the URI string; get the hostname and port */ + uriptr = xmlParseURI(host_uri); + if (uriptr == NULL) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + if (strncasecmp(uriptr->scheme, "http", 4) != 0) { + ret = KMF_ERR_BAD_URI; /* we support http only */ + goto out; + } + + hostname = uriptr->server; + if (hostname == NULL) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + host_port = uriptr->port; + if (host_port == 0) + host_port = 80; + + /* get the proxy info */ + if (policy->VAL_OCSP_BASIC.proxy != NULL) { + char *last; + proxyname = + strtok_r(policy->VAL_OCSP_BASIC.proxy, ":", &last); + proxy_port_s = strtok_r(NULL, "\0", &last); + if (proxy_port_s != NULL) { + proxy_port = strtol(proxy_port_s, NULL, 0); + } else { + proxy_port = 8080; /* default */ + } + } + + /* + * Send the request to an OCSP responder and receive an + * OCSP response. + */ + ret = KMF_GetEncodedOCSPResponse(handle, ocsp_reqname, + hostname, host_port, proxyname, proxy_port, + ocsp_respname, 30); + if (ret != KMF_OK) { + goto out; + } + + ret = KMF_ReadInputFile(handle, ocsp_respname, response); + +out: + (void) unlink(ocsp_reqname); + (void) unlink(ocsp_respname); + + if (uriptr != NULL) + xmlFreeURI(uriptr); + + return (ret); +} diff --git a/usr/src/lib/libkmf/libkmf/common/csrcrlop.c b/usr/src/lib/libkmf/libkmf/common/csrcrlop.c new file mode 100644 index 0000000000..4c8a700994 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/csrcrlop.c @@ -0,0 +1,563 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright(c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <link.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <ber_der.h> +#include <kmfapiP.h> + +#include <pem_encode.h> +#include <libgen.h> +#include <cryptoutil.h> + + +/* + * + * Name: KMF_SetCSRPubKey + * + * Description: + * This function converts the specified plugin public key to SPKI form, + * and save it in the KMF_CSR_DATA internal structure + * + * Parameters: + * KMFkey(input) - pointer to the KMF_KEY_HANDLE structure containing the + * public key generated by the plug-in CreateKeypair + * Csr(input/output) - pointer to a KMF_CSR_DATA structure containing + * SPKI + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SetCSRPubKey(KMF_HANDLE_T handle, + KMF_KEY_HANDLE *KMFKey, + KMF_CSR_DATA *Csr) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_SPKI *spki_ptr; + KMF_PLUGIN *plugin; + KMF_DATA KeyData = {NULL, 0}; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (KMFKey == NULL || Csr == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* The keystore must extract the pubkey data */ + plugin = FindPlugin(handle, KMFKey->kstype); + if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) { + ret = plugin->funclist->EncodePubkeyData(handle, + KMFKey, &KeyData); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + spki_ptr = &Csr->csr.subjectPublicKeyInfo; + + ret = DerDecodeSPKI(&KeyData, spki_ptr); + + KMF_FreeData(&KeyData); + + return (ret); +} + +KMF_RETURN +KMF_SetCSRVersion(KMF_CSR_DATA *CsrData, uint32_t version) +{ + if (CsrData == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * From RFC 3280: + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + if (version != 0 && version != 1 && version != 2) + return (KMF_ERR_BAD_PARAMETER); + return (set_integer(&CsrData->csr.version, (void *)&version, + sizeof (uint32_t))); +} + +KMF_RETURN +KMF_SetCSRSubjectName(KMF_CSR_DATA *CsrData, + KMF_X509_NAME *subject_name_ptr) +{ + if (CsrData != NULL && subject_name_ptr != NULL) + CsrData->csr.subject = *subject_name_ptr; + else + return (KMF_ERR_BAD_PARAMETER); + + return (KMF_OK); +} + +KMF_RETURN +KMF_CreateCSRFile(KMF_DATA *csrdata, KMF_ENCODE_FORMAT format, + char *csrfile) +{ + KMF_RETURN rv = KMF_OK; + int fd = -1; + KMF_DATA pemdata = {NULL, 0}; + + if (csrdata == NULL || csrfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1) + return (KMF_ERR_BAD_PARAMETER); + + if (format == KMF_FORMAT_PEM) { + int len; + rv = KMF_Der2Pem(KMF_CSR, + csrdata->Data, csrdata->Length, + &pemdata.Data, &len); + if (rv != KMF_OK) + goto cleanup; + pemdata.Length = (size_t)len; + } + + if ((fd = open(csrfile, O_CREAT |O_RDWR, 0644)) == -1) { + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (format == KMF_FORMAT_PEM) { + if (write(fd, pemdata.Data, pemdata.Length) != + pemdata.Length) { + rv = KMF_ERR_WRITE_FILE; + } + } else { + if (write(fd, csrdata->Data, csrdata->Length) != + csrdata->Length) { + rv = KMF_ERR_WRITE_FILE; + } + } + +cleanup: + if (fd != -1) + (void) close(fd); + + KMF_FreeData(&pemdata); + + return (rv); +} + +KMF_RETURN +KMF_SetCSRExtension(KMF_CSR_DATA *Csr, + KMF_X509_EXTENSION *extn) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSIONS *exts; + + if (Csr == NULL || extn == NULL) + return (KMF_ERR_BAD_PARAMETER); + + exts = &Csr->csr.extensions; + + ret = add_an_extension(exts, extn); + + return (ret); +} + +KMF_RETURN +KMF_SetCSRSignatureAlgorithm(KMF_CSR_DATA *CsrData, + KMF_ALGORITHM_INDEX sigAlg) +{ + KMF_OID *alg; + + if (CsrData == NULL) + return (KMF_ERR_BAD_PARAMETER); + + alg = X509_AlgIdToAlgorithmOid(sigAlg); + + if (alg != NULL) { + (void) copy_data((KMF_DATA *) + &CsrData->signature.algorithmIdentifier.algorithm, + (KMF_DATA *)alg); + (void) copy_data( + &CsrData->signature.algorithmIdentifier.parameters, + &CsrData->csr.subjectPublicKeyInfo.algorithm.parameters); + } else { + return (KMF_ERR_BAD_PARAMETER); + } + return (KMF_OK); +} + +KMF_RETURN +KMF_SetCSRSubjectAltName(KMF_CSR_DATA *Csr, + char *altname, int critical, + KMF_GENERALNAMECHOICES alttype) +{ + KMF_RETURN ret = KMF_OK; + + if (Csr == NULL || altname == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = KMF_SetAltName(&Csr->csr.extensions, + (KMF_OID *)&KMFOID_SubjectAltName, critical, alttype, + altname); + + return (ret); +} + +KMF_RETURN +KMF_SetCSRKeyUsage(KMF_CSR_DATA *CSRData, + int critical, uint16_t kubits) +{ + KMF_RETURN ret = KMF_OK; + + if (CSRData == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = set_key_usage_extension( + &CSRData->csr.extensions, + critical, kubits); + + return (ret); +} + +/* + * + * Name: KMF_SignCSR + * + * Description: + * This function signs a CSR and returns the result as a + * signed, encoded CSR in SignedCsr + * + * Parameters: + * tbsCsr(input) - pointer to a KMF_DATA structure containing a + * DER encoded TBS CSR data + * Signkey(input) - pointer to the KMF_KEY_HANDLE structure containing + * the private key generated by the plug-in CreateKeypair + * algo(input) - contains algorithm info needed for signing + * SignedCsr(output) - pointer to the KMF_DATA structure containing + * the signed CSR + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SignCSR(KMF_HANDLE_T handle, + const KMF_CSR_DATA *tbsCsr, + KMF_KEY_HANDLE *Signkey, + KMF_DATA *SignedCsr) +{ + KMF_RETURN err; + KMF_DATA csrdata = { NULL, 0 }; + + CLEAR_ERROR(handle, err); + if (err != KMF_OK) + return (err); + + if (tbsCsr == NULL || + Signkey == NULL || SignedCsr == NULL) + return (KMF_ERR_BAD_PARAMETER); + + SignedCsr->Data = NULL; + SignedCsr->Length = 0; + + err = DerEncodeTbsCsr((KMF_TBS_CSR *)&tbsCsr->csr, &csrdata); + if (err == KMF_OK) { + err = SignCsr(handle, &csrdata, Signkey, + (KMF_X509_ALGORITHM_IDENTIFIER *) + &tbsCsr->signature.algorithmIdentifier, + SignedCsr); + } + + if (err != KMF_OK) { + KMF_FreeData(SignedCsr); + } + KMF_FreeData(&csrdata); + return (err); +} + +KMF_RETURN +KMF_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + plugin = FindPlugin(handle, params->kstype); + break; + + case KMF_KEYSTORE_OPENSSL: + case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + break; + default: + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + if (plugin != NULL && plugin->funclist->ImportCRL != NULL) { + return (plugin->funclist->ImportCRL(handle, params)); + } + return (KMF_ERR_PLUGIN_NOTFOUND); +} + +KMF_RETURN +KMF_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + plugin = FindPlugin(handle, params->kstype); + break; + + case KMF_KEYSTORE_OPENSSL: + case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + break; + default: + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + if (plugin != NULL && plugin->funclist->DeleteCRL != NULL) { + return (plugin->funclist->DeleteCRL(handle, params)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_ListCRL(KMF_HANDLE_T handle, KMF_LISTCRL_PARAMS *params, char **crldata) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL || crldata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + plugin = FindPlugin(handle, params->kstype); + break; + + case KMF_KEYSTORE_OPENSSL: + case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + break; + default: + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + if (plugin != NULL && plugin->funclist->ListCRL != NULL) { + return (plugin->funclist->ListCRL(handle, params, crldata)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_FindCRL(KMF_HANDLE_T handle, KMF_FINDCRL_PARAMS *params, + char **CRLNameList, int *CRLCount) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL || + CRLCount == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, params->kstype); + if (plugin != NULL && plugin->funclist->FindCRL != NULL) { + return (plugin->funclist->FindCRL(handle, params, + CRLNameList, CRLCount)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + switch (params->kstype) { + case KMF_KEYSTORE_NSS: + plugin = FindPlugin(handle, params->kstype); + break; + + case KMF_KEYSTORE_OPENSSL: + case KMF_KEYSTORE_PK11TOKEN: /* PKCS#11 CRL is file-based */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + break; + default: + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + if (plugin != NULL && plugin->funclist->FindCertInCRL != NULL) { + return (plugin->funclist->FindCertInCRL(handle, params)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_VerifyCRLFile(KMF_HANDLE_T handle, + KMF_VERIFYCRL_PARAMS *params) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*verifyCRLFile)(KMF_HANDLE_T, + KMF_VERIFYCRL_PARAMS *); + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + verifyCRLFile = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_VerifyCRLFile"); + + if (verifyCRLFile == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (verifyCRLFile(handle, params)); +} + +KMF_RETURN +KMF_CheckCRLDate(KMF_HANDLE_T handle, KMF_CHECKCRLDATE_PARAMS *params) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*checkCRLDate)(void *, + KMF_CHECKCRLDATE_PARAMS *params); + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + checkCRLDate = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_CheckCRLDate"); + + if (checkCRLDate == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (checkCRLDate(handle, params)); + +} + +KMF_RETURN +KMF_IsCRLFile(KMF_HANDLE_T handle, char *filename, KMF_ENCODE_FORMAT *pformat) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*IsCRLFileFn)(void *, char *, KMF_ENCODE_FORMAT *); + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (filename == NULL || pformat == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * This framework function is actually implemented in the openssl + * plugin library, so we find the function address and call it. + */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + IsCRLFileFn = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_IsCRLFile"); + if (IsCRLFileFn == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (IsCRLFileFn(handle, filename, pformat)); +} diff --git a/usr/src/lib/libkmf/libkmf/common/generalop.c b/usr/src/lib/libkmf/libkmf/common/generalop.c new file mode 100644 index 0000000000..1617acc119 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/generalop.c @@ -0,0 +1,1742 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright(c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <dlfcn.h> +#include <link.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <thread.h> + +#include <ber_der.h> +#include <kmfapiP.h> + +#include <pem_encode.h> +#include <rdn_parser.h> +#include <libxml2/libxml/uri.h> +#include <libgen.h> +#include <cryptoutil.h> + +static uchar_t pkcs11_initialized = 0; +mutex_t init_lock = DEFAULTMUTEX; +extern int errno; + +typedef struct { + KMF_RETURN code; + char *message; +} kmf_error_map; + +static kmf_error_map kmf_errcodes[] = { + {KMF_OK, "KMF_OK"}, + {KMF_ERR_BAD_PARAMETER, "KMF_ERR_BAD_PARAMETER"}, + {KMF_ERR_BAD_KEY_FORMAT, "KMF_ERR_BAD_KEY_FORMAT"}, + {KMF_ERR_BAD_ALGORITHM, "KMF_ERR_BAD_ALGORITHM"}, + {KMF_ERR_MEMORY, "KMF_ERR_MEMORY"}, + {KMF_ERR_ENCODING, "KMF_ERR_ENCODING"}, + {KMF_ERR_PLUGIN_INIT, "KMF_ERR_PLUGIN_INIT"}, + {KMF_ERR_PLUGIN_NOTFOUND, "KMF_ERR_PLUGIN_NOTFOUND"}, + {KMF_ERR_INTERNAL, "KMF_ERR_INTERNAL"}, + {KMF_ERR_BAD_CERT_FORMAT, "KMF_ERR_BAD_CERT_FORMAT"}, + {KMF_ERR_KEYGEN_FAILED, "KMF_ERR_KEYGEN_FAILED"}, + {KMF_ERR_UNINITIALIZED, "KMF_ERR_UNINITIALIZED"}, + {KMF_ERR_ISSUER, "KMF_ERR_ISSUER"}, + {KMF_ERR_NOT_REVOKED, "KMF_ERR_NOT_REVOKED"}, + {KMF_ERR_CERT_NOT_FOUND, "KMF_ERR_CERT_NOT_FOUND"}, + {KMF_ERR_CRL_NOT_FOUND, "KMF_ERR_CRL_NOT_FOUND"}, + {KMF_ERR_RDN_PARSER, "KMF_ERR_RDN_PARSER"}, + {KMF_ERR_RDN_ATTR, "KMF_ERR_RDN_ATTR"}, + {KMF_ERR_SLOTNAME, "KMF_ERR_SLOTNAME"}, + {KMF_ERR_EMPTY_CRL, "KMF_ERR_EMPTY_CRL"}, + {KMF_ERR_BUFFER_SIZE, "KMF_ERR_BUFFER_SIZE"}, + {KMF_ERR_AUTH_FAILED, "KMF_ERR_AUTH_FAILED"}, + {KMF_ERR_TOKEN_SELECTED, "KMF_ERR_TOKEN_SELECTED"}, + {KMF_ERR_NO_TOKEN_SELECTED, "KMF_ERR_NO_TOKEN_SELECTED"}, + {KMF_ERR_TOKEN_NOT_PRESENT, "KMF_ERR_TOKEN_NOT_PRESENT"}, + {KMF_ERR_EXTENSION_NOT_FOUND, "KMF_ERR_EXTENSION_NOT_FOUND"}, + {KMF_ERR_POLICY_ENGINE, "KMF_ERR_POLICY_ENGINE"}, + {KMF_ERR_POLICY_DB_FORMAT, "KMF_ERR_POLICY_DB_FORMAT"}, + {KMF_ERR_POLICY_NOT_FOUND, "KMF_ERR_POLICY_NOT_FOUND"}, + {KMF_ERR_POLICY_DB_FILE, "KMF_ERR_POLICY_DB_FILE"}, + {KMF_ERR_POLICY_NAME, "KMF_ERR_POLICY_NAME"}, + {KMF_ERR_OCSP_POLICY, "KMF_ERR_OCSP_POLICY"}, + {KMF_ERR_TA_POLICY, "KMF_ERR_TA_POLICY"}, + {KMF_ERR_KEY_NOT_FOUND, "KMF_ERR_KEY_NOT_FOUND"}, + {KMF_ERR_OPEN_FILE, "KMF_ERR_OPEN_FILE"}, + {KMF_ERR_OCSP_BAD_ISSUER, "KMF_ERR_OCSP_BAD_ISSUER"}, + {KMF_ERR_OCSP_BAD_CERT, "KMF_ERR_OCSP_BAD_CERT"}, + {KMF_ERR_OCSP_CREATE_REQUEST, "KMF_ERR_OCSP_CREATE_REQUEST"}, + {KMF_ERR_CONNECT_SERVER, "KMF_ERR_CONNECT_SERVER"}, + {KMF_ERR_SEND_REQUEST, "KMF_ERR_SEND_REQUEST"}, + {KMF_ERR_OCSP_CERTID, "KMF_ERR_OCSP_CERTID"}, + {KMF_ERR_OCSP_MALFORMED_RESPONSE, "KMF_ERR_OCSP_MALFORMED_RESPONSE"}, + {KMF_ERR_OCSP_RESPONSE_STATUS, "KMF_ERR_OCSP_RESPONSE_STATUS"}, + {KMF_ERR_OCSP_NO_BASIC_RESPONSE, "KMF_ERR_OCSP_NO_BASIC_RESPONSE"}, + {KMF_ERR_OCSP_BAD_SIGNER, "KMF_ERR_OCSP_BAD_SIGNER"}, + {KMF_ERR_OCSP_RESPONSE_SIGNATURE, "KMF_ERR_OCSP_RESPONSE_SIGNATURE"}, + {KMF_ERR_OCSP_UNKNOWN_CERT, "KMF_ERR_OCSP_UNKNOWN_CERT"}, + {KMF_ERR_OCSP_STATUS_TIME_INVALID, "KMF_ERR_OCSP_STATUS_TIME_INVALID"}, + {KMF_ERR_BAD_HTTP_RESPONSE, "KMF_ERR_BAD_HTTP_RESPONSE"}, + {KMF_ERR_RECV_RESPONSE, "KMF_ERR_RECV_RESPONSE"}, + {KMF_ERR_RECV_TIMEOUT, "KMF_ERR_RECV_TIMEOUT"}, + {KMF_ERR_DUPLICATE_KEYFILE, "KMF_ERR_DUPLICATE_KEYFILE"}, + {KMF_ERR_AMBIGUOUS_PATHNAME, "KMF_ERR_AMBIGUOUS_PATHNAME"}, + {KMF_ERR_FUNCTION_NOT_FOUND, "KMF_ERR_FUNCTION_NOT_FOUND"}, + {KMF_ERR_PKCS12_FORMAT, "KMF_ERR_PKCS12_FORMAT"}, + {KMF_ERR_BAD_KEY_TYPE, "KMF_ERR_BAD_KEY_TYPE"}, + {KMF_ERR_BAD_KEY_CLASS, "KMF_ERR_BAD_KEY_CLASS"}, + {KMF_ERR_BAD_KEY_SIZE, "KMF_ERR_BAD_KEY_SIZE"}, + {KMF_ERR_BAD_HEX_STRING, "KMF_ERR_BAD_HEX_STRING"}, + {KMF_ERR_KEYUSAGE, "KMF_ERR_KEYUSAGE"}, + {KMF_ERR_VALIDITY_PERIOD, "KMF_ERR_VALIDITY_PERIOD"}, + {KMF_ERR_OCSP_REVOKED, "KMF_ERR_OCSP_REVOKED"}, + {KMF_ERR_CERT_MULTIPLE_FOUND, "KMF_ERR_CERT_MULTIPLE_FOUND"}, + {KMF_ERR_WRITE_FILE, "KMF_ERR_WRITE_FILE"}, + {KMF_ERR_BAD_URI, "KMF_ERR_BAD_URI"}, + {KMF_ERR_BAD_CRLFILE, "KMF_ERR_BAD_CRLFILE"}, + {KMF_ERR_BAD_CERTFILE, "KMF_ERR_BAD_CERTFILE"}, + {KMF_ERR_GETKEYVALUE_FAILED, "KMF_ERR_GETKEYVALUE_FAILED"}, + {KMF_ERR_BAD_KEYHANDLE, "KMF_ERR_BAD_KEYHANDLE"}, + {KMF_ERR_BAD_OBJECT_TYPE, "KMF_ERR_BAD_OBJECT_TYPE"}, + {KMF_ERR_OCSP_RESPONSE_LIFETIME, "KMF_ERR_OCSP_RESPONSE_LIFETIME"}, + {KMF_ERR_UNKNOWN_CSR_ATTRIBUTE, "KMF_ERR_UNKNOWN_CSR_ATTRIBUTE"}, + {KMF_ERR_UNINITIALIZED_TOKEN, "KMF_ERR_UNINITIALIZED_TOKEN"}, + {KMF_ERR_INCOMPLETE_TBS_CERT, "KMF_ERR_INCOMPLETE_TBS_CERT"}, + {KMF_ERR_MISSING_ERRCODE, "KMF_ERR_MISSING_ERRCODE"}, + {KMF_KEYSTORE_ALREADY_INITIALIZED, "KMF_KEYSTORE_ALREADY_INITIALIZED"} +}; + + +static void free_extensions(KMF_X509_EXTENSIONS *extns); + +int +is_pk11_ready() +{ + return (pkcs11_initialized); +} + +/* + * Private method for searching the plugin list for the correct + * Plugin to use. + */ +KMF_PLUGIN * +FindPlugin(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE kstype) +{ + KMF_PLUGIN_LIST *node; + + if (handle == NULL) + return (NULL); + + node = handle->plugins; + + while (node != NULL && node->plugin->type != kstype) + node = node->next; + + /* If it is NULL, that is indication enough of an error */ + return (node ? node->plugin : NULL); +} + +static KMF_RETURN +InitializePlugin(KMF_KEYSTORE_TYPE kstype, char *path, KMF_PLUGIN **plugin) +{ + KMF_PLUGIN *p = NULL; + KMF_PLUGIN_FUNCLIST *(*sym)(); + + if (path == NULL || plugin == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *plugin = NULL; + + p = (KMF_PLUGIN *)malloc(sizeof (KMF_PLUGIN)); + if (p == NULL) + return (KMF_ERR_MEMORY); + + p->type = kstype; + p->path = strdup(path); + if (p->path == NULL) { + free(p); + return (KMF_ERR_MEMORY); + } + p->dldesc = dlopen(path, RTLD_NOW | RTLD_GROUP | RTLD_PARENT); + if (p->dldesc == NULL) { + free(p->path); + free(p); + return (KMF_ERR_PLUGIN_INIT); + } + + sym = (KMF_PLUGIN_FUNCLIST *(*)())dlsym(p->dldesc, + KMF_PLUGIN_INIT_SYMBOL); + if (sym == NULL) { + (void) dlclose(p->dldesc); + free(p->path); + free(p); + return (KMF_ERR_PLUGIN_INIT); + } + + /* Get the function list */ + if ((p->funclist = (*sym)()) == NULL) { + (void) dlclose(p->dldesc); + free(p->path); + free(p); + return (KMF_ERR_PLUGIN_INIT); + } + + *plugin = p; + + return (KMF_OK); +} + +static KMF_RETURN +AddPlugin(KMF_HANDLE_T handle, KMF_PLUGIN *plugin) +{ + KMF_PLUGIN_LIST *n; + + if (handle == NULL || plugin == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the head is NULL, create it */ + if (handle->plugins == NULL) { + handle->plugins = (KMF_PLUGIN_LIST *)malloc( + sizeof (KMF_PLUGIN_LIST)); + if (handle->plugins == NULL) + return (KMF_ERR_MEMORY); + handle->plugins->plugin = plugin; + handle->plugins->next = NULL; + } else { + /* walk the list to find the tail */ + n = handle->plugins; + while (n->next != NULL) + n = n->next; + n->next = (KMF_PLUGIN_LIST *)malloc(sizeof (KMF_PLUGIN_LIST)); + if (n->next == NULL) + return (KMF_ERR_MEMORY); + + n->next->plugin = plugin; + n->next->next = NULL; + } + return (0); +} + +static void +DestroyPlugin(KMF_PLUGIN *plugin) +{ + if (plugin) { + if (plugin->path) + free(plugin->path); + free(plugin); + } +} + +static void +Cleanup_KMF_Handle(KMF_HANDLE_T handle) +{ + if (handle != NULL) { + while (handle->plugins != NULL) { + KMF_PLUGIN_LIST *next = handle->plugins->next; + + DestroyPlugin(handle->plugins->plugin); + + free(handle->plugins); + + handle->plugins = next; + } + + KMF_FreePolicyRecord(handle->policy); + free(handle->policy); + } + free(handle); +} + +void +Cleanup_PK11_Session(KMF_HANDLE_T handle) +{ + if (handle != NULL) { + /* Close active session on a pkcs11 token */ + if (handle->pk11handle != NULL) { + (void) C_CloseSession(handle->pk11handle); + handle->pk11handle = NULL; + } + } +} + +KMF_RETURN +KMF_Initialize(KMF_HANDLE_T *outhandle, char *policyfile, char *policyname) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *handle = NULL; + KMF_PLUGIN *pluginrec = NULL; + + if (outhandle == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *outhandle = NULL; + handle = (KMF_HANDLE *)malloc(sizeof (KMF_HANDLE)); + if (handle == NULL) + return (KMF_ERR_MEMORY); + + (void) memset(handle, 0, sizeof (KMF_HANDLE)); + handle->plugins = NULL; + + (void) mutex_lock(&init_lock); + if (!pkcs11_initialized) { + CK_RV rv = C_Initialize(NULL); + if ((rv != CKR_OK) && + (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { + ret = KMF_ERR_UNINITIALIZED; + (void) mutex_unlock(&init_lock); + goto errout; + } else { + pkcs11_initialized = 1; + } + } + (void) mutex_unlock(&init_lock); + + /* Initialize the handle with the policy */ + ret = KMF_SetPolicy((void *)handle, + policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile, + policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname); + if (ret != KMF_OK) + goto errout; + + /* Create a record for the plugin */ + if ((ret = InitializePlugin(KMF_KEYSTORE_NSS, + KMF_PLUGIN_PATH "kmf_nss.so.1", &pluginrec)) != KMF_OK) + goto errout; + + /* Add it to the handle */ + if (pluginrec != NULL) { + if ((ret = AddPlugin(handle, pluginrec))) + goto errout; + } + if ((ret = InitializePlugin(KMF_KEYSTORE_OPENSSL, + KMF_PLUGIN_PATH "kmf_openssl.so.1", &pluginrec)) != KMF_OK) + goto errout; + + /* Add it to the handle */ + if (pluginrec != NULL) + if ((ret = AddPlugin(handle, pluginrec))) + goto errout; + + if ((ret = InitializePlugin(KMF_KEYSTORE_PK11TOKEN, + KMF_PLUGIN_PATH "kmf_pkcs11.so.1", &pluginrec)) != KMF_OK) + goto errout; + + /* Add it to the handle */ + if (pluginrec != NULL) + if ((ret = AddPlugin(handle, pluginrec))) + goto errout; + + CLEAR_ERROR(handle, ret); +errout: + if (ret != KMF_OK) { + Cleanup_KMF_Handle(handle); + handle = NULL; + } + + *outhandle = (KMF_HANDLE_T)handle; + return (ret); +} + +KMF_RETURN +KMF_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, params->kstype); + if (plugin == NULL) + return (KMF_ERR_PLUGIN_NOTFOUND); + + if (plugin->funclist->ConfigureKeystore != NULL) + return (plugin->funclist->ConfigureKeystore(handle, params)); + else + /* return KMF_OK, if the plugin does not have an entry */ + return (KMF_OK); +} + +KMF_RETURN +KMF_Finalize(KMF_HANDLE_T handle) +{ + KMF_RETURN ret = KMF_OK; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (pkcs11_initialized) { + Cleanup_PK11_Session(handle); + } + Cleanup_KMF_Handle(handle); + + return (ret); +} + +KMF_RETURN +KMF_GetKMFErrorString(KMF_RETURN errcode, char **errmsg) +{ + KMF_RETURN ret = KMF_OK; + int i, maxerr; + + if (errmsg == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *errmsg = NULL; + maxerr = sizeof (kmf_errcodes) / sizeof (kmf_error_map); + + for (i = 0; i < maxerr && errcode != kmf_errcodes[i].code; i++); + + if (i == maxerr) + return (KMF_ERR_MISSING_ERRCODE); + else { + *errmsg = strdup(kmf_errcodes[i].message); + if ((*errmsg) == NULL) + return (KMF_ERR_MEMORY); + } + return (ret); +} + +KMF_RETURN +KMF_GetPluginErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_RETURN ret = KMF_OK; + KMF_PLUGIN *plugin; + + if (handle == NULL || msgstr == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *msgstr = NULL; + + if (handle->lasterr.errcode == 0) { + return (KMF_ERR_MISSING_ERRCODE); + } + + if (handle->lasterr.kstype == -1) { /* System error */ + char *str = strerror(handle->lasterr.errcode); + if (str != NULL) { + *msgstr = strdup(str); + if ((*msgstr) == NULL) + return (KMF_ERR_MEMORY); + } + return (KMF_OK); + } + + plugin = FindPlugin(handle, handle->lasterr.kstype); + if (plugin == NULL) + return (KMF_ERR_PLUGIN_NOTFOUND); + + if (plugin->funclist->GetErrorString != NULL) { + ret = plugin->funclist->GetErrorString(handle, msgstr); + } else { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (ret); +} + +KMF_RETURN +KMF_DNParser(char *string, KMF_X509_NAME *name) +{ + KMF_RETURN err; + + if (string == NULL || name == NULL) + return (KMF_ERR_BAD_PARAMETER); + + err = ParseDistinguishedName(string, (int)strlen(string), name); + return (err); +} + +KMF_RETURN +KMF_DN2Der(KMF_X509_NAME *dn, KMF_DATA *der) +{ + KMF_RETURN rv; + + if (dn == NULL || der == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = DerEncodeName(dn, der); + return (rv); +} + +#define SET_SYS_ERROR(h, c) h->lasterr.kstype = -1; h->lasterr.errcode = c; + +KMF_RETURN +KMF_ReadInputFile(KMF_HANDLE_T handle, char *filename, KMF_DATA *pdata) +{ + struct stat s; + long nread, total = 0; + int fd; + unsigned char *buf = NULL; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + + if (filename == NULL || pdata == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if ((fd = open(filename, O_RDONLY)) < 0) { + SET_SYS_ERROR(handle, errno); + return (KMF_ERR_OPEN_FILE); + } + + if (fstat(fd, &s) < 0) { + SET_SYS_ERROR(handle, errno); + (void) close(fd); + return (KMF_ERR_OPEN_FILE); + } + + if ((buf = (unsigned char *) malloc(s.st_size)) == NULL) { + (void) close(fd); + return (KMF_ERR_MEMORY); + } + + do { + nread = read(fd, buf+total, s.st_size-total); + if (nread < 0) { + SET_SYS_ERROR(handle, errno); + (void) close(fd); + free(buf); + return (KMF_ERR_INTERNAL); + } + total += nread; + } while (total < s.st_size); + + pdata->Data = buf; + pdata->Length = s.st_size; + (void) close(fd); + return (KMF_OK); +} + +/* + * + * Name: KMF_Der2Pem + * + * Description: + * Function for converting DER encoded format to PEM encoded format + * + * Parameters: + * type(input) - CERTIFICATE or CSR + * data(input) - pointer to the DER encoded data + * len(input) - length of input data + * out(output) - contains the output buffer address to be returned + * outlen(output) - pointer to the returned output length + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_Der2Pem(KMF_OBJECT_TYPE type, unsigned char *data, + int len, unsigned char **out, int *outlen) +{ + + KMF_RETURN err; + if (data == NULL || out == NULL || outlen == NULL) + return (KMF_ERR_BAD_PARAMETER); + + err = Der2Pem(type, data, len, out, outlen); + return (err); + +} + +/* + * + * Name: KMF_Pem2Der + * + * Description: + * Function for converting PEM encoded format to DER encoded format + * + * Parameters: + * in(input) - pointer to the PEM encoded data + * inlen(input) - length of input data + * out(output) - contains the output buffer address to be returned + * outlen(output) - pointer to the returned output length + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_Pem2Der(unsigned char *in, int inlen, + unsigned char **out, int *outlen) +{ + KMF_RETURN err; + if (in == NULL || out == NULL || outlen == NULL) + return (KMF_ERR_BAD_PARAMETER); + + err = Pem2Der(in, inlen, out, outlen); + return (err); +} + +char * +KMF_OID2String(KMF_OID *oid) +{ + char numstr[128]; + uint32_t number; + int numshift; + uint32_t i, string_length; + uchar_t *cp; + char *bp; + + /* First determine the size of the string */ + string_length = 0; + number = 0; + numshift = 0; + cp = (unsigned char *)oid->Data; + + number = (uint32_t)cp[0]; + (void) sprintf(numstr, "%d ", number/40); + + string_length += strlen(numstr); + (void) sprintf(numstr, "%d ", number%40); + + string_length += strlen(numstr); + + for (i = 1; i < oid->Length; i++) { + if ((uint32_t)(numshift+7) < (sizeof (uint32_t)*8)) { + number = (number << 7) | (cp[i] & 0x7f); + numshift += 7; + } else { + return (NULL); + } + + if ((cp[i] & 0x80) == 0) { + (void) sprintf(numstr, "%d ", number); + string_length += strlen(numstr); + number = 0; + numshift = 0; + } + } + /* + * If we get here, we've calculated the length of "n n n ... n ". Add 4 + * here for "{ " and "}\0". + */ + string_length += 4; + if ((bp = (char *)malloc(string_length))) { + number = (uint32_t)cp[0]; + + (void) sprintf(numstr, "%d.", number/40); + (void) strcpy(bp, numstr); + + (void) sprintf(numstr, "%d.", number%40); + (void) strcat(bp, numstr); + + number = 0; + cp = (unsigned char *) oid->Data; + for (i = 1; i < oid->Length; i++) { + number = (number << 7) | (cp[i] & 0x7f); + if ((cp[i] & 0x80) == 0) { + (void) sprintf(numstr, "%d", number); + (void) strcat(bp, numstr); + number = 0; + if (i+1 < oid->Length) + (void) strcat(bp, "."); + } + } + } + return (bp); +} + +KMF_RETURN +KMF_GetFileFormat(char *filename, KMF_ENCODE_FORMAT *fmt) +{ + int f; + KMF_RETURN ret = KMF_OK; + uchar_t buf[16]; + + if (filename == NULL || !strlen(filename) || fmt == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *fmt = 0; + if ((f = open(filename, O_RDONLY)) == -1) { + return (KMF_ERR_OPEN_FILE); + } + + if (read(f, buf, 8) != 8) { + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (memcmp(buf, "-----BEG", 8) == 0) { + *fmt = KMF_FORMAT_PEM; + } else if (buf[0] == 0x30 && (buf[1] & 0x80)) { + if ((buf[1] & 0xFF) == 0x80 && + (buf[2] & 0xFF) == 0x02 && + (buf[5] & 0xFF) == 0x30) { + *fmt = KMF_FORMAT_PKCS12; + } else if ((buf[1] & 0xFF) == 0x82 && + (buf[4] & 0xFF) == 0x02 && + (buf[7] & 0xFF) == 0x30) { + *fmt = KMF_FORMAT_PKCS12; + /* It is most likely a generic ASN.1 encoded file */ + } else { + *fmt = KMF_FORMAT_ASN1; + } + } else { + /* Cannot determine this file format */ + *fmt = 0; + ret = KMF_ERR_ENCODING; + } +end: + (void) close(f); + return (ret); +} + +KMF_RETURN +KMF_HexString2Bytes(unsigned char *hexstr, unsigned char **bytes, + size_t *outlen) +{ + KMF_RETURN ret = KMF_OK; + unsigned char *buf = NULL; + int len, stringlen; + int i; + unsigned char ch; + + if (hexstr == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (hexstr[0] == '0' && + ((hexstr[1] == 'x') || (hexstr[1] == 'X'))) + hexstr += 2; + + for (i = 0; i < strlen((char *)hexstr) && isxdigit(hexstr[i]); i++); + /* + * If all the characters are not legitimate hex chars, + * return an error. + */ + if (i != strlen((char *)hexstr)) + return (KMF_ERR_BAD_HEX_STRING); + stringlen = i; + len = (i / 2) + (i % 2); + + buf = malloc(len); + if (buf == NULL) { + return (KMF_ERR_MEMORY); + } + (void) memset(buf, 0, len); + + for (i = 0; i < stringlen; i++) { + ch = (unsigned char) *hexstr; + hexstr++; + if ((ch >= '0') && (ch <= '9')) + ch -= '0'; + else if ((ch >= 'A') && (ch <= 'F')) + ch = ch - 'A' + 10; + else if ((ch >= 'a') && (ch <= 'f')) + ch = ch - 'a' + 10; + else { + ret = KMF_ERR_BAD_HEX_STRING; + goto out; + } + + if (i & 1) { + buf[i/2] |= ch; + } else { + buf[i/2] = (ch << 4); + } + } + + *bytes = buf; + *outlen = len; +out: + if (buf != NULL && ret != KMF_OK) { + free(buf); + } + return (ret); +} + +void +KMF_FreeDN(KMF_X509_NAME *name) +{ + KMF_X509_RDN *newrdn = NULL; + KMF_X509_TYPE_VALUE_PAIR *av = NULL; + int i, j; + + if (name && name->numberOfRDNs) { + for (i = 0; i < name->numberOfRDNs; i++) { + newrdn = &name->RelativeDistinguishedName[i]; + for (j = 0; j < newrdn->numberOfPairs; j++) { + av = &newrdn->AttributeTypeAndValue[j]; + KMF_FreeData(&av->type); + KMF_FreeData(&av->value); + } + free(newrdn->AttributeTypeAndValue); + newrdn->numberOfPairs = 0; + newrdn->AttributeTypeAndValue = NULL; + } + free(name->RelativeDistinguishedName); + name->numberOfRDNs = 0; + name->RelativeDistinguishedName = NULL; + } +} + +void +KMF_FreeKMFCert(KMF_HANDLE_T handle, KMF_X509_DER_CERT *kmf_cert) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return; + + if (kmf_cert == NULL) + return; + + plugin = FindPlugin(handle, kmf_cert->kmf_private.keystore_type); + + if (plugin != NULL && plugin->funclist->FreeKMFCert != NULL) { + plugin->funclist->FreeKMFCert(handle, kmf_cert); + } +} + +void +KMF_FreeData(KMF_DATA *datablock) +{ + if (datablock != NULL && datablock->Data != NULL) { + free(datablock->Data); + datablock->Data = NULL; + datablock->Length = 0; + } +} + +void +KMF_FreeAlgOID(KMF_X509_ALGORITHM_IDENTIFIER *algoid) +{ + if (algoid == NULL) + return; + KMF_FreeData(&algoid->algorithm); + KMF_FreeData(&algoid->parameters); +} + +void +KMF_FreeExtension(KMF_X509_EXTENSION *exptr) +{ + if (exptr == NULL) + return; + + KMF_FreeData((KMF_DATA *)&exptr->extnId); + KMF_FreeData(&exptr->BERvalue); + + if (exptr->value.tagAndValue) { + KMF_FreeData(&exptr->value.tagAndValue->value); + free(exptr->value.tagAndValue); + } +} + +void +KMF_FreeTBSCSR(KMF_TBS_CSR *tbscsr) +{ + if (tbscsr) { + KMF_FreeData(&tbscsr->version); + + KMF_FreeDN(&tbscsr->subject); + + KMF_FreeAlgOID(&tbscsr->subjectPublicKeyInfo.algorithm); + KMF_FreeData(&tbscsr->subjectPublicKeyInfo.subjectPublicKey); + + free_extensions(&tbscsr->extensions); + } +} + +void +KMF_FreeSignedCSR(KMF_CSR_DATA *csr) +{ + if (csr) { + KMF_FreeTBSCSR(&csr->csr); + + KMF_FreeAlgOID(&csr->signature.algorithmIdentifier); + KMF_FreeData(&csr->signature.encrypted); + } +} + +static void +free_validity(KMF_X509_VALIDITY *validity) +{ + if (validity == NULL) + return; + KMF_FreeData(&validity->notBefore.time); + KMF_FreeData(&validity->notAfter.time); +} + +static void +free_extensions(KMF_X509_EXTENSIONS *extns) +{ + int i; + KMF_X509_EXTENSION *exptr; + + if (extns && extns->numberOfExtensions > 0) { + for (i = 0; i < extns->numberOfExtensions; i++) { + exptr = &extns->extensions[i]; + KMF_FreeExtension(exptr); + } + free(extns->extensions); + extns->numberOfExtensions = 0; + extns->extensions = NULL; + } +} + +void +KMF_FreeTBSCert(KMF_X509_TBS_CERT *tbscert) +{ + if (tbscert) { + KMF_FreeData(&tbscert->version); + KMF_FreeBigint(&tbscert->serialNumber); + KMF_FreeAlgOID(&tbscert->signature); + + KMF_FreeDN(&tbscert->issuer); + KMF_FreeDN(&tbscert->subject); + + free_validity(&tbscert->validity); + + KMF_FreeData(&tbscert->issuerUniqueIdentifier); + KMF_FreeData(&tbscert->subjectUniqueIdentifier); + + KMF_FreeAlgOID(&tbscert->subjectPublicKeyInfo.algorithm); + KMF_FreeData(&tbscert->subjectPublicKeyInfo.subjectPublicKey); + + free_extensions(&tbscert->extensions); + + KMF_FreeData(&tbscert->issuerUniqueIdentifier); + KMF_FreeData(&tbscert->subjectUniqueIdentifier); + } +} + +void +KMF_FreeSignedCert(KMF_X509_CERTIFICATE *certptr) +{ + if (!certptr) + return; + + KMF_FreeTBSCert(&certptr->certificate); + + KMF_FreeAlgOID(&certptr->signature.algorithmIdentifier); + KMF_FreeData(&certptr->signature.encrypted); +} + +void +KMF_FreeString(char *pstr) +{ + if (pstr != NULL) + free(pstr); +} + +void +free_keyidlist(KMF_OID *oidlist, int len) +{ + int i; + for (i = 0; i < len; i++) { + KMF_FreeData((KMF_DATA *)&oidlist[i]); + } + free(oidlist); +} + +void +KMF_FreeEKU(KMF_X509EXT_EKU *eptr) +{ + if (eptr && eptr->nEKUs > 0 && + eptr->keyPurposeIdList != NULL) + free_keyidlist(eptr->keyPurposeIdList, eptr->nEKUs); +} + +void +KMF_FreeSPKI(KMF_X509_SPKI *spki) +{ + if (spki != NULL) { + KMF_FreeAlgOID(&spki->algorithm); + KMF_FreeData(&spki->subjectPublicKey); + } +} + +void +KMF_FreeKMFKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return; + + if (key == NULL) + return; + + plugin = FindPlugin(handle, key->kstype); + if (plugin != NULL && plugin->funclist->DeleteKey != NULL) { + (void) plugin->funclist->DeleteKey(handle, NULL, key, FALSE); + } + + if (key == NULL) + return; + + if (key->keylabel) + free(key->keylabel); + + if (key->israw) { + KMF_FreeRawKey(key->keyp); + free(key->keyp); + } + + (void) memset(key, 0, sizeof (KMF_KEY_HANDLE)); +} + +void +KMF_FreeBigint(KMF_BIGINT *big) +{ + if (big != NULL && big->val != NULL) { + free(big->val); + big->val = NULL; + big->len = 0; + } +} + +static void +free_raw_rsa(KMF_RAW_RSA_KEY *key) +{ + if (key == NULL) + return; + KMF_FreeBigint(&key->mod); + KMF_FreeBigint(&key->pubexp); + KMF_FreeBigint(&key->priexp); + KMF_FreeBigint(&key->prime1); + KMF_FreeBigint(&key->prime2); + KMF_FreeBigint(&key->exp1); + KMF_FreeBigint(&key->exp2); + KMF_FreeBigint(&key->coef); +} + +static void +free_raw_dsa(KMF_RAW_DSA_KEY *key) +{ + if (key == NULL) + return; + KMF_FreeBigint(&key->prime); + KMF_FreeBigint(&key->subprime); + KMF_FreeBigint(&key->base); + KMF_FreeBigint(&key->value); +} + +static void +free_raw_sym(KMF_RAW_SYM_KEY *key) +{ + if (key == NULL) + return; + KMF_FreeBigint(&key->keydata); +} + +void +KMF_FreeRawKey(KMF_RAW_KEY_DATA *key) +{ + if (key == NULL) + return; + + switch (key->keytype) { + case KMF_RSA: + free_raw_rsa(&key->rawdata.rsa); + break; + case KMF_DSA: + free_raw_dsa(&key->rawdata.dsa); + break; + case KMF_AES: + case KMF_RC4: + case KMF_DES: + case KMF_DES3: + free_raw_sym(&key->rawdata.sym); + break; + } +} + +void +KMF_FreeRawSymKey(KMF_RAW_SYM_KEY *key) +{ + if (key == NULL) + return; + KMF_FreeBigint(&key->keydata); + free(key); +} + +/* + * This function frees the space allocated for the name portion of a + * KMF_CRL_DIST_POINT. + */ +void +free_dp_name(KMF_CRL_DIST_POINT *dp) +{ + KMF_GENERALNAMES *fullname; + KMF_DATA *urldata; + int i; + + if (dp == NULL) + return; + + /* For phase 1, we only need to free the fullname space. */ + fullname = &(dp->name.full_name); + if (fullname->number == 0) + return; + + for (i = 0; i < fullname->number; i++) { + urldata = &(fullname->namelist[fullname->number - 1].name); + KMF_FreeData(urldata); + } + + free(fullname->namelist); +} + +/* + * This function frees the space allocated for a KMF_CRL_DIST_POINT. + */ +void +free_dp(KMF_CRL_DIST_POINT *dp) +{ + if (dp == NULL) + return; + + free_dp_name(dp); + KMF_FreeData(&(dp->reasons)); + /* Need not to free crl_issuer space at phase 1 */ +} + +/* + * This function frees space for a KMF_X509EXT_CRLDISTPOINTS internally. + */ +void +KMF_FreeCRLDistributionPoints(KMF_X509EXT_CRLDISTPOINTS *crl_dps) +{ + int i; + + if (crl_dps == NULL) + return; + + for (i = 0; i < crl_dps->number; i++) + free_dp(&(crl_dps->dplist[i])); + + free(crl_dps->dplist); +} + +KMF_RETURN +KMF_CreateOCSPRequest(KMF_HANDLE_T handle, KMF_OCSPREQUEST_PARAMS *params, + char *reqfile) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*createReqFn)(void *, KMF_OCSPREQUEST_PARAMS *params, + char *reqfile); + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + + if (params == NULL || + reqfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * This framework function is actually implemented in the openssl + * plugin library, so we find the function address and call it. + */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + createReqFn = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_CreateOCSPRequest"); + if (createReqFn == NULL) { + return (KMF_ERR_FUNCTION_NOT_FOUND); + } + + return (createReqFn(handle, params, reqfile)); +} + +KMF_RETURN +KMF_GetOCSPStatusForCert(KMF_HANDLE_T handle, + KMF_OCSPRESPONSE_PARAMS_INPUT *params_in, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out) +{ + KMF_PLUGIN *plugin; + KMF_RETURN (*getCertStatusFn)(void *, + KMF_OCSPRESPONSE_PARAMS_INPUT *params_in, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out); + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + + if (params_in == NULL || + params_out == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * This framework function is actually implemented in the openssl + * plugin library, so we find the function address and call it. + */ + plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL); + if (plugin == NULL || plugin->dldesc == NULL) { + return (KMF_ERR_INTERNAL); + } + + getCertStatusFn = (KMF_RETURN(*)())dlsym(plugin->dldesc, + "OpenSSL_GetOCSPStatusForCert"); + if (getCertStatusFn == NULL) { + return (KMF_ERR_INTERNAL); + } + + return (getCertStatusFn(handle, params_in, params_out)); +} + +KMF_RETURN +KMF_String2OID(char *oidstring, KMF_OID *oid) +{ + KMF_RETURN rv = KMF_OK; + char *cp, *bp, *startp; + int numbuf; + int onumbuf; + int nbytes, index; + int len; + unsigned char *op; + + if (oidstring == NULL || oid == NULL) + return (KMF_ERR_BAD_PARAMETER); + + len = strlen(oidstring); + + bp = oidstring; + cp = bp; + /* Skip over leading space */ + while ((bp < &cp[len]) && isspace(*bp)) + bp++; + + startp = bp; + nbytes = 0; + + /* + * The first two numbers are chewed up by the first octet. + */ + if (sscanf(bp, "%d", &numbuf) != 1) + return (KMF_ERR_BAD_PARAMETER); + while ((bp < &cp[len]) && isdigit(*bp)) + bp++; + while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.')) + bp++; + if (sscanf(bp, "%d", &numbuf) != 1) + return (KMF_ERR_BAD_PARAMETER); + while ((bp < &cp[len]) && isdigit(*bp)) + bp++; + while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.')) + bp++; + nbytes++; + + while (isdigit(*bp)) { + if (sscanf(bp, "%d", &numbuf) != 1) + return (KMF_ERR_BAD_PARAMETER); + while (numbuf) { + nbytes++; + numbuf >>= 7; + } + while ((bp < &cp[len]) && isdigit(*bp)) + bp++; + while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.')) + bp++; + } + + oid->Length = nbytes; + oid->Data = malloc(oid->Length); + if (oid->Data == NULL) { + return (KMF_ERR_MEMORY); + } + (void) memset(oid->Data, 0, oid->Length); + + op = oid->Data; + + bp = startp; + (void) sscanf(bp, "%d", &numbuf); + + while (isdigit(*bp)) bp++; + while (isspace(*bp) || *bp == '.') bp++; + + onumbuf = 40 * numbuf; + (void) sscanf(bp, "%d", &numbuf); + onumbuf += numbuf; + *op = (unsigned char) onumbuf; + op++; + + while (isdigit(*bp)) bp++; + while (isspace(*bp) || *bp == '.') bp++; + while (isdigit(*bp)) { + (void) sscanf(bp, "%d", &numbuf); + nbytes = 0; + /* Have to fill in the bytes msb-first */ + onumbuf = numbuf; + while (numbuf) { + nbytes++; + numbuf >>= 7; + } + numbuf = onumbuf; + op += nbytes; + index = -1; + while (numbuf) { + op[index] = (unsigned char)numbuf & 0x7f; + if (index != -1) + op[index] |= 0x80; + index--; + numbuf >>= 7; + } + while (isdigit(*bp)) bp++; + while (isspace(*bp) || *bp == '.') bp++; + } + + return (rv); +} + +static KMF_RETURN +encode_rid(char *name, KMF_DATA *derdata) +{ + KMF_RETURN rv = KMF_OK; + + if (name == NULL || derdata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = KMF_String2OID(name, (KMF_OID *)derdata); + + return (rv); +} + +static KMF_RETURN +encode_ipaddr(char *name, KMF_DATA *derdata) +{ + KMF_RETURN rv = KMF_OK; + size_t len; + in_addr_t v4; + in6_addr_t v6; + uint8_t *ptr; + + if (name == NULL || derdata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + v4 = inet_addr(name); + if (v4 == (in_addr_t)-1) { + ptr = (uint8_t *)&v6; + if (inet_pton(AF_INET6, name, ptr) != 1) + return (KMF_ERR_ENCODING); + len = sizeof (v6); + } else { + ptr = (uint8_t *)&v4; + len = sizeof (v4); + } + + derdata->Data = malloc(len); + if (derdata->Data == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(derdata->Data, ptr, len); + derdata->Length = len; + + return (rv); +} + +static KMF_RETURN +verify_uri_format(char *uristring) +{ + KMF_RETURN ret = KMF_OK; + xmlURIPtr uriptr = NULL; + + /* Parse the URI string; get the hostname and port */ + uriptr = xmlParseURI(uristring); + if (uriptr == NULL) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + if (uriptr->scheme == NULL || !strlen(uriptr->scheme)) { + ret = KMF_ERR_BAD_URI; + goto out; + } + + if (uriptr->server == NULL || !strlen(uriptr->server)) { + ret = KMF_ERR_BAD_URI; + goto out; + } +out: + if (uriptr != NULL) + xmlFreeURI(uriptr); + return (ret); +} + +static KMF_RETURN +encode_altname(char *namedata, + KMF_GENERALNAMECHOICES nametype, KMF_DATA *encodedname) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_NAME dnname; + uchar_t tagval; + BerElement *asn1 = NULL; + BerValue *extdata; + + if (namedata == NULL || encodedname == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Encode the namedata according to rules in RFC 3280 for GeneralName. + * The input "namedata" is assumed to be an ASCII string representation + * of the AltName, we need to convert it to correct ASN.1 here before + * adding it to the cert. + */ + switch (nametype) { + case GENNAME_RFC822NAME: /* rfc 822 */ + /* IA5String, no encoding needed */ + encodedname->Data = (uchar_t *)strdup(namedata); + if (encodedname->Data == NULL) + return (KMF_ERR_MEMORY); + encodedname->Length = strlen(namedata); + tagval = (0x80 | nametype); + break; + case GENNAME_DNSNAME: /* rfc 1034 */ + encodedname->Data = (uchar_t *)strdup(namedata); + if (encodedname->Data == NULL) + return (KMF_ERR_MEMORY); + encodedname->Length = strlen(namedata); + tagval = (0x80 | nametype); + break; + case GENNAME_URI: /* rfc 1738 */ + ret = verify_uri_format(namedata); + if (ret != KMF_OK) + return (ret); + /* IA5String, no encoding needed */ + encodedname->Data = (uchar_t *)strdup(namedata); + if (encodedname->Data == NULL) + return (KMF_ERR_MEMORY); + encodedname->Length = strlen(namedata); + tagval = (0x80 | nametype); + break; + case GENNAME_IPADDRESS: + ret = encode_ipaddr(namedata, encodedname); + tagval = (0x80 | nametype); + break; + case GENNAME_REGISTEREDID: + ret = encode_rid(namedata, encodedname); + tagval = (0x80 | nametype); + break; + case GENNAME_DIRECTORYNAME: + ret = KMF_DNParser(namedata, &dnname); + if (ret == KMF_OK) { + ret = KMF_DN2Der(&dnname, encodedname); + } + (void) KMF_FreeDN(&dnname); + tagval = (0xA0 | nametype); + break; + default: + /* unsupported */ + return (KMF_ERR_BAD_PARAMETER); + + } + if (ret != KMF_OK) { + KMF_FreeData(encodedname); + return (ret); + } + + if ((asn1 = kmfder_alloc()) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(asn1, "Tl", + tagval, encodedname->Length) == -1) + goto cleanup; + + if (kmfber_write(asn1, (char *)encodedname->Data, + encodedname->Length, 0) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + if (kmfber_flatten(asn1, &extdata) == -1) { + ret = KMF_ERR_ENCODING; + goto cleanup; + } + + KMF_FreeData(encodedname); + encodedname->Data = (uchar_t *)extdata->bv_val; + encodedname->Length = extdata->bv_len; + + free(extdata); + +cleanup: + if (asn1) + kmfber_free(asn1, 1); + + if (ret != KMF_OK) + KMF_FreeData(encodedname); + + return (ret); +} + +KMF_X509_EXTENSION * +FindExtn(KMF_X509_EXTENSIONS *exts, KMF_OID *oid) +{ + KMF_X509_EXTENSION *foundextn = NULL; + int i; + + if (exts == NULL || oid == NULL) + return (NULL); + + for (i = 0; i < exts->numberOfExtensions; i++) { + if (IsEqualOid(oid, &exts->extensions[i].extnId)) { + foundextn = &exts->extensions[i]; + break; + } + } + return (foundextn); +} + +KMF_RETURN +GetSequenceContents(char *data, size_t len, + char **contents, size_t *outlen) +{ + KMF_RETURN ret = KMF_OK; + BerElement *exasn1 = NULL; + BerValue oldextn; + int tag; + size_t oldsize; + char *olddata = NULL; + + if (data == NULL || contents == NULL || outlen == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Decode the sequence of general names + */ + oldextn.bv_val = data; + oldextn.bv_len = len; + + if ((exasn1 = kmfder_init(&oldextn)) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + /* + * Unwrap the sequence to find the size of the block + * of GeneralName items in the set. + * + * Peek at the tag and length ("tl"), + * then consume them ("{"). + */ + if (kmfber_scanf(exasn1, "tl{", &tag, &oldsize) == KMFBER_DEFAULT || + oldsize == 0) { + ret = KMF_ERR_ENCODING; + goto out; + } + + olddata = malloc(oldsize); + if (olddata == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memset(olddata, 0, oldsize); + /* + * Read the entire blob of GeneralNames, we don't + * need to interpret them now. + */ + if (kmfber_read(exasn1, olddata, oldsize) != oldsize) { + ret = KMF_ERR_ENCODING; + goto out; + } +out: + if (exasn1 != NULL) + kmfber_free(exasn1, 1); + + if (ret != KMF_OK) { + *contents = NULL; + *outlen = 0; + if (olddata != NULL) + free(olddata); + } else { + *contents = olddata; + *outlen = oldsize; + } + return (ret); +} + +KMF_RETURN +add_an_extension(KMF_X509_EXTENSIONS *exts, KMF_X509_EXTENSION *newextn) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION *extlist; + + if (exts == NULL || newextn == NULL) + return (KMF_ERR_BAD_PARAMETER); + + extlist = malloc(sizeof (KMF_X509_EXTENSION) * + (exts->numberOfExtensions + 1)); + if (extlist == NULL) + return (KMF_ERR_MEMORY); + + (void) memcpy(extlist, exts->extensions, + exts->numberOfExtensions * sizeof (KMF_X509_EXTENSION)); + + (void) memcpy(&extlist[exts->numberOfExtensions], newextn, + sizeof (KMF_X509_EXTENSION)); + + free(exts->extensions); + exts->numberOfExtensions++; + exts->extensions = extlist; + + return (ret); +} + +KMF_RETURN +KMF_SetAltName(KMF_X509_EXTENSIONS *extensions, + KMF_OID *oid, + int critical, + KMF_GENERALNAMECHOICES nametype, + char *namedata) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_EXTENSION subjAltName; + KMF_DATA dername = { NULL, 0 }; + BerElement *asn1 = NULL; + BerValue *extdata; + char *olddata = NULL; + KMF_X509_EXTENSION *foundextn = NULL; + size_t oldsize = 0; + + if (extensions == NULL || oid == NULL || namedata == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = encode_altname(namedata, nametype, &dername); + + if (ret != KMF_OK) + return (ret); + + (void) memset(&subjAltName, 0, sizeof (subjAltName)); + + ret = copy_data(&subjAltName.extnId, oid); + if (ret != KMF_OK) + goto out; + /* + * Check to see if this cert already has a subjectAltName. + */ + foundextn = FindExtn(extensions, oid); + + if (foundextn != NULL) { + ret = GetSequenceContents( + (char *)foundextn->BERvalue.Data, + foundextn->BERvalue.Length, + &olddata, &oldsize); + if (ret != KMF_OK) + goto out; + } + + /* + * Assume (!!) that the namedata given is already properly encoded. + */ + if ((asn1 = kmfder_alloc()) == NULL) + return (KMF_ERR_MEMORY); + + if (kmfber_printf(asn1, "{") == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + /* Write the old extension data first */ + if (olddata != NULL && oldsize > 0) { + if (kmfber_write(asn1, olddata, oldsize, 0) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + } + + /* Now add the new name to the list */ + if (kmfber_write(asn1, (char *)dername.Data, dername.Length, 0) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + /* Now close the sequence */ + if (kmfber_printf(asn1, "}") == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + if (kmfber_flatten(asn1, &extdata) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + /* + * If we are just adding to an existing list of altNames, + * just replace the BER data associated with the found extension. + */ + if (foundextn != NULL) { + free(foundextn->BERvalue.Data); + foundextn->critical = critical; + foundextn->BERvalue.Data = (uchar_t *)extdata->bv_val; + foundextn->BERvalue.Length = extdata->bv_len; + } else { + subjAltName.critical = critical; + subjAltName.format = KMF_X509_DATAFORMAT_ENCODED; + subjAltName.BERvalue.Data = (uchar_t *)extdata->bv_val; + subjAltName.BERvalue.Length = extdata->bv_len; + ret = add_an_extension(extensions, &subjAltName); + if (ret != KMF_OK) + free(subjAltName.BERvalue.Data); + } + + free(extdata); +out: + if (olddata != NULL) + free(olddata); + + KMF_FreeData(&dername); + if (ret != KMF_OK) + KMF_FreeData(&subjAltName.extnId); + if (asn1 != NULL) + kmfber_free(asn1, 1); + return (ret); +} diff --git a/usr/src/lib/libkmf/libkmf/common/keyop.c b/usr/src/lib/libkmf/libkmf/common/keyop.c new file mode 100644 index 0000000000..abe0082306 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/keyop.c @@ -0,0 +1,375 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright(c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <link.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ber_der.h> +#include <kmfapiP.h> +#include <libgen.h> +#include <cryptoutil.h> + +/* + * + * Name: KMF_SignDataWithKey + * + * Description: + * This function signs a block of data using the private key + * and returns the signature in output + * + * Parameters: + * handle(input) - opaque handle for KMF session + * key(input) - contains private key handle needed for signing + * AlgOID(input) - contains algorithm to be used for signing + * tobesigned(input) - pointer to a KMF_DATA structure containing + * the data to be signed + * output(output) - pointer to the KMF_DATA structure containing the + * signed data + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SignDataWithKey(KMF_HANDLE_T handle, + KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, + KMF_DATA *tobesigned, + KMF_DATA *output) +{ + KMF_RETURN ret; + KMF_PLUGIN *plugin; + KMF_ALGORITHM_INDEX AlgId; + KMF_DATA signature = {0, NULL}; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (key == NULL || AlgOID == NULL || + tobesigned == NULL || output == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * The plugin must be based on the key since private keys + * cannot be extracted. + */ + plugin = FindPlugin(handle, key->kstype); + if (plugin != NULL && plugin->funclist->SignData != NULL) { + ret = plugin->funclist->SignData(handle, key, + AlgOID, tobesigned, output); + if (ret != KMF_OK) + goto cleanup; + + AlgId = X509_AlgorithmOidToAlgId(AlgOID); + + /* + * For DSA, NSS returns an encoded signature. Decode the + * signature as DSA signature should be 40-byte long. + */ + if ((AlgId == KMF_ALGID_SHA1WithDSA) && + (plugin->type == KMF_KEYSTORE_NSS)) { + ret = DerDecodeDSASignature(output, &signature); + if (ret != KMF_OK) { + goto cleanup; + } else { + output->Length = signature.Length; + (void) memcpy(output->Data, signature.Data, + signature.Length); + } + } else if (AlgId == KMF_ALGID_NONE) { + ret = KMF_ERR_BAD_ALGORITHM; + } + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + +cleanup: + if (signature.Data) + free(signature.Data); + return (ret); +} + +/* + * + * Name: KMF_VerifyDataWithKey + * + * Description: + * This function verifies the signature of a block of data + * using the input public key + * + * Parameters: + * handle(input) - opaque handle for KMF session + * KMFKey(input) - holds public key information for verification + * sigAlg(input) - algorithm to verify + * indata(input) - pointer to the block of data whose signature + * is to be verified + * insig(input) - pointer to the signature to be verified + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_VerifyDataWithKey(KMF_HANDLE_T handle, + KMF_KEY_HANDLE *KMFKey, + KMF_ALGORITHM_INDEX sigAlg, + KMF_DATA *indata, + KMF_DATA *insig) +{ + KMF_RETURN err; + KMF_DATA derkey = {0, NULL}; + KMF_PLUGIN *plugin; + + CLEAR_ERROR(handle, err); + if (err != KMF_OK) + return (err); + + if (KMFKey == NULL || + indata == NULL || insig == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, KMFKey->kstype); + + /* Retrieve public key data from keystore */ + if (plugin != NULL && plugin->funclist->EncodePubkeyData != NULL) { + err = plugin->funclist->EncodePubkeyData(handle, + KMFKey, &derkey); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } + + err = VerifyDataWithKey(handle, &derkey, sigAlg, indata, insig); + + if (derkey.Data != NULL) + free(derkey.Data); + + return (err); +} + +KMF_RETURN +KMF_CreateKeypair(KMF_HANDLE_T handle, + KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privKey, + KMF_KEY_HANDLE *pubKey) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL || + privKey == NULL || pubKey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(privKey, 0, sizeof (KMF_KEY_HANDLE)); + (void) memset(pubKey, 0, sizeof (KMF_KEY_HANDLE)); + plugin = FindPlugin(handle, params->kstype); + + if (plugin != NULL && plugin->funclist->CreateKeypair != NULL) { + return (plugin->funclist->CreateKeypair(handle, params, + privKey, pubKey)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_DeleteKeyFromKeystore(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key) +{ + KMF_RETURN rv = KMF_OK; + KMF_PLUGIN *plugin; + + CLEAR_ERROR(handle, rv); + if (rv != KMF_OK) + return (rv); + + if (key == NULL || params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, params->kstype); + if (plugin != NULL && plugin->funclist->DeleteKey != NULL) { + rv = plugin->funclist->DeleteKey(handle, params, key, TRUE); + } else { + rv = KMF_ERR_PLUGIN_NOTFOUND; + } + + if (rv == KMF_OK) { + if (key->keylabel != NULL) + free(key->keylabel); + + if (key->israw && key->keyp != NULL) { + if (key->keyclass == KMF_ASYM_PUB || + key->keyclass == KMF_ASYM_PRI) { + KMF_FreeRawKey(key->keyp); + free(key->keyp); + } else if (key->keyclass == KMF_SYMMETRIC) { + KMF_FreeRawSymKey(key->keyp); + } + /* Else we don't know how to free the memory. */ + } + + (void) memset(key, 0, sizeof (KMF_KEY_HANDLE)); + } + + return (rv); +} + +KMF_RETURN +KMF_SignCertRecord(KMF_HANDLE_T handle, KMF_KEY_HANDLE *kmfprikey, + KMF_X509_CERTIFICATE *CertData, KMF_DATA *signedCert) +{ + KMF_RETURN ret; + KMF_DATA unsignedCert; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (kmfprikey == NULL || + CertData == NULL || signedCert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = KMF_EncodeCertRecord(CertData, &unsignedCert); + if (ret == KMF_OK) + ret = KMF_SignCertWithKey(handle, &unsignedCert, kmfprikey, + signedCert); + + KMF_FreeData(&unsignedCert); + return (ret); +} + +KMF_RETURN +KMF_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms, + KMF_KEY_HANDLE *keys, uint32_t *numkeys) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (parms == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, parms->kstype); + + if (plugin != NULL && plugin->funclist->FindKey != NULL) { + return (plugin->funclist->FindKey(handle, parms, + keys, numkeys)); + } + + return (KMF_ERR_PLUGIN_NOTFOUND); +} + +KMF_RETURN +KMF_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *rawkey) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL || rawkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Find the private key from the keystore */ + plugin = FindPlugin(handle, params->kstype); + + if (plugin != NULL && plugin->funclist->StorePrivateKey != NULL) { + return (plugin->funclist->StorePrivateKey(handle, + params, rawkey)); + } + return (KMF_ERR_PLUGIN_NOTFOUND); +} + +KMF_RETURN +KMF_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (params == NULL || + symkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, params->kstype); + if (plugin != NULL && plugin->funclist->CreateSymKey != NULL) { + return (plugin->funclist->CreateSymKey(handle, params, + symkey)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} + +KMF_RETURN +KMF_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_PLUGIN *plugin; + KMF_RETURN ret; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + plugin = FindPlugin(handle, symkey->kstype); + if (plugin != NULL && + plugin->funclist->GetSymKeyValue != NULL) { + return (plugin->funclist->GetSymKeyValue(handle, + symkey, rkey)); + } else { + return (KMF_ERR_PLUGIN_NOTFOUND); + } +} diff --git a/usr/src/lib/libkmf/libkmf/common/kmfoids.c b/usr/src/lib/libkmf/libkmf/common/kmfoids.c new file mode 100644 index 0000000000..9f2e6dff14 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/kmfoids.c @@ -0,0 +1,375 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright(c) 1995-2000 Intel Corporation. All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapi.h> + +/* From X.520 */ +static uint8_t +OID_ObjectClass[] = { OID_ATTR_TYPE, 0 }, +OID_AliasedEntryName[] = { OID_ATTR_TYPE, 1 }, +OID_KnowledgeInformation[] = { OID_ATTR_TYPE, 2 }, +OID_CommonName[] = { OID_ATTR_TYPE, 3 }, +OID_Surname[] = { OID_ATTR_TYPE, 4 }, +OID_SerialNumber[] = { OID_ATTR_TYPE, 5 }, +OID_CountryName[] = { OID_ATTR_TYPE, 6 }, +OID_LocalityName[] = { OID_ATTR_TYPE, 7 }, +OID_StateProvinceName[] = { OID_ATTR_TYPE, 8 }, +OID_CollectiveStateProvinceName[] = { OID_ATTR_TYPE, 8, 1 }, +OID_StreetAddress[] = { OID_ATTR_TYPE, 9 }, +OID_CollectiveStreetAddress[] = { OID_ATTR_TYPE, 9, 1 }, +OID_OrganizationName[] = { OID_ATTR_TYPE, 10 }, +OID_CollectiveOrganizationName[] = { OID_ATTR_TYPE, 10, 1 }, +OID_OrganizationalUnitName[] = { OID_ATTR_TYPE, 11 }, +OID_CollectiveOrganizationalUnitName[] = { OID_ATTR_TYPE, 11, 1 }, +OID_Title[] = { OID_ATTR_TYPE, 12 }, +OID_Description[] = { OID_ATTR_TYPE, 13 }, +OID_SearchGuide[] = { OID_ATTR_TYPE, 14 }, +OID_BusinessCategory[] = { OID_ATTR_TYPE, 15 }, +OID_PostalAddress[] = { OID_ATTR_TYPE, 16 }, +OID_CollectivePostalAddress[] = { OID_ATTR_TYPE, 16, 1 }, +OID_PostalCode[] = { OID_ATTR_TYPE, 17 }, +OID_CollectivePostalCode[] = { OID_ATTR_TYPE, 17, 1 }, +OID_PostOfficeBox[] = { OID_ATTR_TYPE, 18 }, +OID_CollectivePostOfficeBox[] = { OID_ATTR_TYPE, 18, 1 }, +OID_PhysicalDeliveryOfficeName[] = { OID_ATTR_TYPE, 19 }, +OID_CollectivePhysicalDeliveryOfficeName[] = { OID_ATTR_TYPE, 19, 1 }, +OID_TelephoneNumber[] = { OID_ATTR_TYPE, 20 }, +OID_CollectiveTelephoneNumber[] = { OID_ATTR_TYPE, 20, 1 }, +OID_TelexNumber[] = { OID_ATTR_TYPE, 21 }, +OID_CollectiveTelexNumber[] = { OID_ATTR_TYPE, 21, 1 }, +OID_TelexTerminalIdentifier[] = { OID_ATTR_TYPE, 22 }, +OID_CollectiveTelexTerminalIdentifier[] = { OID_ATTR_TYPE, 22, 1 }, +OID_FacsimileTelephoneNumber[] = { OID_ATTR_TYPE, 23 }, +OID_CollectiveFacsimileTelephoneNumber[] = { OID_ATTR_TYPE, 23, 1 }, +OID_X_121Address[] = { OID_ATTR_TYPE, 24 }, +OID_InternationalISDNNumber[] = { OID_ATTR_TYPE, 25 }, +OID_CollectiveInternationalISDNNumber[] = { OID_ATTR_TYPE, 25, 1 }, +OID_RegisteredAddress[] = { OID_ATTR_TYPE, 26 }, +OID_DestinationIndicator[] = { OID_ATTR_TYPE, 27 }, +OID_PreferredDeliveryMethod[] = { OID_ATTR_TYPE, 28 }, +OID_PresentationAddress[] = { OID_ATTR_TYPE, 29 }, +OID_SupportedApplicationContext[] = { OID_ATTR_TYPE, 30 }, +OID_Member[] = { OID_ATTR_TYPE, 31 }, +OID_Owner[] = { OID_ATTR_TYPE, 32 }, +OID_RoleOccupant[] = { OID_ATTR_TYPE, 33 }, +OID_SeeAlso[] = { OID_ATTR_TYPE, 34 }, +OID_UserPassword[] = { OID_ATTR_TYPE, 35 }, +OID_UserCertificate[] = { OID_ATTR_TYPE, 36 }, +OID_CACertificate[] = { OID_ATTR_TYPE, 37 }, +OID_AuthorityRevocationList[] = { OID_ATTR_TYPE, 38 }, +OID_CertificateRevocationList[] = { OID_ATTR_TYPE, 39 }, +OID_CrossCertificatePair[] = { OID_ATTR_TYPE, 40 }, +OID_Name[] = { OID_ATTR_TYPE, 41 }, +OID_GivenName[] = { OID_ATTR_TYPE, 42 }, +OID_Initials[] = { OID_ATTR_TYPE, 43 }, +OID_GenerationQualifier[] = { OID_ATTR_TYPE, 44 }, +OID_UniqueIdentifier[] = { OID_ATTR_TYPE, 45 }, +OID_DNQualifier[] = { OID_ATTR_TYPE, 46 }, +OID_EnhancedSearchGuide[] = { OID_ATTR_TYPE, 47 }, +OID_ProtocolInformation[] = { OID_ATTR_TYPE, 48 }, +OID_DistinguishedName[] = { OID_ATTR_TYPE, 49 }, +OID_UniqueMember[] = { OID_ATTR_TYPE, 50 }, +OID_HouseIdentifier[] = { OID_ATTR_TYPE, 51 } +/* OID_SupportedAlgorithms[] = { OID_ATTR_TYPE, 52 }, */ +/* OID_DeltaRevocationList[] = { OID_ATTR_TYPE, 53 }, */ +/* OID_AttributeCertificate[] = { OID_ATTR_TYPE, 58 } */ +; + +/* From PKCS 9 */ +static uint8_t +OID_EmailAddress[] = { OID_PKCS_9, 1 }, +OID_UnstructuredName[] = { OID_PKCS_9, 2 }, +OID_ContentType[] = { OID_PKCS_9, 3 }, +OID_MessageDigest[] = { OID_PKCS_9, 4 }, +OID_SigningTime[] = { OID_PKCS_9, 5 }, +OID_CounterSignature[] = { OID_PKCS_9, 6 }, +OID_ChallengePassword[] = { OID_PKCS_9, 7 }, +OID_UnstructuredAddress[] = { OID_PKCS_9, 8 }, +OID_ExtendedCertificateAttributes[] = { OID_PKCS_9, 9 }, +OID_ExtensionRequest[] = { OID_PKCS_9, 14 }; + +/* From PKIX 1 */ +/* Standard Extensions */ +static uint8_t +OID_SubjectDirectoryAttributes[] = { OID_EXTENSION, 9 }, +OID_SubjectKeyIdentifier[] = { OID_EXTENSION, 14 }, +OID_KeyUsage[] = { OID_EXTENSION, 15 }, +OID_PrivateKeyUsagePeriod[] = { OID_EXTENSION, 16 }, +OID_SubjectAltName[] = { OID_EXTENSION, 17 }, +OID_IssuerAltName[] = { OID_EXTENSION, 18 }, +OID_BasicConstraints[] = { OID_EXTENSION, 19 }, +OID_CrlNumber[] = { OID_EXTENSION, 20 }, +OID_CrlReason[] = { OID_EXTENSION, 21 }, +OID_HoldInstructionCode[] = { OID_EXTENSION, 23 }, +OID_InvalidityDate[] = { OID_EXTENSION, 24 }, +OID_DeltaCrlIndicator[] = { OID_EXTENSION, 27 }, +OID_IssuingDistributionPoints[] = { OID_EXTENSION, 28 }, + +/* OID_CertificateIssuer[] = { OID_EXTENSION, 29 }, */ +OID_NameConstraints[] = { OID_EXTENSION, 30 }, +OID_CrlDistributionPoints[] = { OID_EXTENSION, 31 }, +OID_CertificatePolicies[] = { OID_EXTENSION, 32 }, +OID_PolicyMappings[] = { OID_EXTENSION, 33 }, +/* 34 deprecated */ +OID_AuthorityKeyIdentifier[] = { OID_EXTENSION, 35 }, +OID_PolicyConstraints[] = { OID_EXTENSION, 36 }, +OID_ExtKeyUsage[] = { OID_EXTENSION, 37 } +; + +/* PKIX-defined extended key purpose OIDs */ +static uint8_t +OID_QT_CPSuri[] = { OID_PKIX_QT_CPS }, +OID_QT_Unotice[] = { OID_PKIX_QT_UNOTICE }, + +OID_KP_ServerAuth[] = { OID_PKIX_KP, 1 }, +OID_KP_ClientAuth[] = { OID_PKIX_KP, 2 }, +OID_KP_CodeSigning[] = { OID_PKIX_KP, 3 }, +OID_KP_EmailProtection[] = { OID_PKIX_KP, 4 }, +OID_KP_IPSecEndSystem[] = { OID_PKIX_KP, 5 }, +OID_KP_IPSecTunnel[] = { OID_PKIX_KP, 6 }, +OID_KP_IPSecUser[] = { OID_PKIX_KP, 7 }, +OID_KP_TimeStamping[] = { OID_PKIX_KP, 8 }, +OID_KP_OCSPSigning[] = { OID_PKIX_KP, 9 } +; + +/* From PKIX 1 */ +static uint8_t +OID_AuthorityInfoAccess[] = { OID_PKIX_PE, 1}; + +const KMF_OID +KMFOID_AuthorityInfoAccess = {OID_PKIX_LENGTH + 2, OID_AuthorityInfoAccess}; + +static uint8_t +OID_PkixAdOcsp[] = {OID_PKIX_AD, 1}; + +const KMF_OID +KMFOID_PkixAdOcsp = {OID_PKIX_AD_LENGTH + 1, OID_PkixAdOcsp}; + +static uint8_t +OID_PkixAdCaIssuers[] = {OID_PKIX_AD, 2}; + +const KMF_OID +KMFOID_PkixAdCaIssuers = {OID_PKIX_AD_LENGTH + 1, OID_PkixAdCaIssuers}; + +/* + * From RFC 1274 + */ +static uint8_t +OID_userid[] = {OID_PILOT, 1}, +OID_RFC822mailbox[] = {OID_PILOT, 3}, +OID_domainComponent[] = {OID_PILOT, 25}; + +const KMF_OID +KMFOID_userid = {OID_PILOT_LENGTH + 1, OID_userid}, +KMFOID_RFC822mailbox = {OID_PILOT_LENGTH + 1, OID_RFC822mailbox}, +KMFOID_domainComponent = {OID_PILOT_LENGTH + 1, OID_domainComponent}, +KMFOID_ObjectClass = {OID_ATTR_TYPE_LENGTH+1, OID_ObjectClass}, +KMFOID_AliasedEntryName = {OID_ATTR_TYPE_LENGTH+1, OID_AliasedEntryName}, +KMFOID_KnowledgeInformation = {OID_ATTR_TYPE_LENGTH+1, + OID_KnowledgeInformation}, +KMFOID_CommonName = {OID_ATTR_TYPE_LENGTH+1, OID_CommonName}, +KMFOID_Surname = {OID_ATTR_TYPE_LENGTH+1, OID_Surname}, +KMFOID_SerialNumber = {OID_ATTR_TYPE_LENGTH+1, OID_SerialNumber}, +KMFOID_CountryName = {OID_ATTR_TYPE_LENGTH+1, OID_CountryName}, +KMFOID_LocalityName = {OID_ATTR_TYPE_LENGTH+1, OID_LocalityName}, +KMFOID_StateProvinceName = {OID_ATTR_TYPE_LENGTH+1, OID_StateProvinceName}, +KMFOID_CollectiveStateProvinceName = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveStateProvinceName}, +KMFOID_StreetAddress = {OID_ATTR_TYPE_LENGTH+1, OID_StreetAddress}, +KMFOID_CollectiveStreetAddress = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveStreetAddress}, +KMFOID_OrganizationName = {OID_ATTR_TYPE_LENGTH+1, OID_OrganizationName}, +KMFOID_CollectiveOrganizationName = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveOrganizationName}, +KMFOID_OrganizationalUnitName = {OID_ATTR_TYPE_LENGTH+1, + OID_OrganizationalUnitName}, +KMFOID_CollectiveOrganizationalUnitName = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveOrganizationalUnitName}, +KMFOID_Title = {OID_ATTR_TYPE_LENGTH+1, OID_Title}, +KMFOID_Description = {OID_ATTR_TYPE_LENGTH+1, OID_Description}, +KMFOID_SearchGuide = {OID_ATTR_TYPE_LENGTH+1, OID_SearchGuide}, +KMFOID_BusinessCategory = {OID_ATTR_TYPE_LENGTH+1, OID_BusinessCategory}, +KMFOID_PostalAddress = {OID_ATTR_TYPE_LENGTH+1, OID_PostalAddress}, +KMFOID_CollectivePostalAddress = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectivePostalAddress}, +KMFOID_PostalCode = {OID_ATTR_TYPE_LENGTH+1, OID_PostalCode}, +KMFOID_CollectivePostalCode = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectivePostalCode}, +KMFOID_PostOfficeBox = {OID_ATTR_TYPE_LENGTH+1, OID_PostOfficeBox}, +KMFOID_CollectivePostOfficeBox = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectivePostOfficeBox}, +KMFOID_PhysicalDeliveryOfficeName = {OID_ATTR_TYPE_LENGTH+1, + OID_PhysicalDeliveryOfficeName}, +KMFOID_CollectivePhysicalDeliveryOfficeName = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectivePhysicalDeliveryOfficeName}, +KMFOID_TelephoneNumber = {OID_ATTR_TYPE_LENGTH+1, OID_TelephoneNumber}, +KMFOID_CollectiveTelephoneNumber = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveTelephoneNumber}, +KMFOID_TelexNumber = {OID_ATTR_TYPE_LENGTH+1, OID_TelexNumber}, +KMFOID_CollectiveTelexNumber = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveTelexNumber}, +KMFOID_TelexTerminalIdentifier = {OID_ATTR_TYPE_LENGTH+1, + OID_TelexTerminalIdentifier}, +KMFOID_CollectiveTelexTerminalIdentifier = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveTelexTerminalIdentifier}, +KMFOID_FacsimileTelephoneNumber = {OID_ATTR_TYPE_LENGTH+1, + OID_FacsimileTelephoneNumber}, +KMFOID_CollectiveFacsimileTelephoneNumber = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveFacsimileTelephoneNumber}, +KMFOID_X_121Address = {OID_ATTR_TYPE_LENGTH+1, OID_X_121Address}, +KMFOID_InternationalISDNNumber = {OID_ATTR_TYPE_LENGTH+1, + OID_InternationalISDNNumber}, +KMFOID_CollectiveInternationalISDNNumber = {OID_ATTR_TYPE_LENGTH+2, + OID_CollectiveInternationalISDNNumber}, +KMFOID_RegisteredAddress = {OID_ATTR_TYPE_LENGTH+1, OID_RegisteredAddress}, +KMFOID_DestinationIndicator = {OID_ATTR_TYPE_LENGTH+1, + OID_DestinationIndicator}, +KMFOID_PreferredDeliveryMethod = {OID_ATTR_TYPE_LENGTH+1, + OID_PreferredDeliveryMethod}, +KMFOID_PresentationAddress = {OID_ATTR_TYPE_LENGTH+1, + OID_PresentationAddress}, +KMFOID_SupportedApplicationContext = {OID_ATTR_TYPE_LENGTH+1, + OID_SupportedApplicationContext}, +KMFOID_Member = {OID_ATTR_TYPE_LENGTH+1, OID_Member}, +KMFOID_Owner = {OID_ATTR_TYPE_LENGTH+1, OID_Owner}, +KMFOID_RoleOccupant = {OID_ATTR_TYPE_LENGTH+1, OID_RoleOccupant}, +KMFOID_SeeAlso = {OID_ATTR_TYPE_LENGTH+1, OID_SeeAlso}, +KMFOID_UserPassword = {OID_ATTR_TYPE_LENGTH+1, OID_UserPassword}, +KMFOID_UserCertificate = {OID_ATTR_TYPE_LENGTH+1, OID_UserCertificate}, +KMFOID_CACertificate = {OID_ATTR_TYPE_LENGTH+1, OID_CACertificate}, +KMFOID_AuthorityRevocationList = {OID_ATTR_TYPE_LENGTH+1, + OID_AuthorityRevocationList}, +KMFOID_CertificateRevocationList = {OID_ATTR_TYPE_LENGTH+1, + OID_CertificateRevocationList}, +KMFOID_CrossCertificatePair = {OID_ATTR_TYPE_LENGTH+1, + OID_CrossCertificatePair}, +KMFOID_Name = {OID_ATTR_TYPE_LENGTH+1, OID_Name}, +KMFOID_GivenName = {OID_ATTR_TYPE_LENGTH+1, OID_GivenName}, +KMFOID_Initials = {OID_ATTR_TYPE_LENGTH+1, OID_Initials}, +KMFOID_GenerationQualifier = {OID_ATTR_TYPE_LENGTH+1, OID_GenerationQualifier}, +KMFOID_UniqueIdentifier = {OID_ATTR_TYPE_LENGTH+1, OID_UniqueIdentifier}, +KMFOID_DNQualifier = {OID_ATTR_TYPE_LENGTH+1, OID_DNQualifier}, +KMFOID_EnhancedSearchGuide = {OID_ATTR_TYPE_LENGTH+1, OID_EnhancedSearchGuide}, +KMFOID_ProtocolInformation = {OID_ATTR_TYPE_LENGTH+1, OID_ProtocolInformation}, +KMFOID_DistinguishedName = {OID_ATTR_TYPE_LENGTH+1, OID_DistinguishedName}, +KMFOID_UniqueMember = {OID_ATTR_TYPE_LENGTH+1, OID_UniqueMember}, +KMFOID_HouseIdentifier = {OID_ATTR_TYPE_LENGTH+1, OID_HouseIdentifier}, +KMFOID_EmailAddress = {OID_PKCS_9_LENGTH+1, OID_EmailAddress}, +KMFOID_UnstructuredName = {OID_PKCS_9_LENGTH+1, OID_UnstructuredName}, +KMFOID_ContentType = {OID_PKCS_9_LENGTH+1, OID_ContentType}, +KMFOID_MessageDigest = {OID_PKCS_9_LENGTH+1, OID_MessageDigest}, +KMFOID_SigningTime = {OID_PKCS_9_LENGTH+1, OID_SigningTime}, +KMFOID_CounterSignature = {OID_PKCS_9_LENGTH+1, OID_CounterSignature}, +KMFOID_ChallengePassword = {OID_PKCS_9_LENGTH+1, OID_ChallengePassword}, +KMFOID_UnstructuredAddress = {OID_PKCS_9_LENGTH+1, OID_UnstructuredAddress}, +KMFOID_ExtendedCertificateAttributes = {OID_PKCS_9_LENGTH+1, + OID_ExtendedCertificateAttributes}, +KMFOID_ExtensionRequest = {OID_PKCS_9_LENGTH + 1, OID_ExtensionRequest}; + +static uint8_t +OID_AuthorityKeyID[] = { OID_EXTENSION, 1 }, +OID_VerisignCertificatePolicy[] = { OID_EXTENSION, 3 }, +OID_KeyUsageRestriction[] = { OID_EXTENSION, 4 }; + +const KMF_OID +KMFOID_AuthorityKeyID = {OID_EXTENSION_LENGTH+1, OID_AuthorityKeyID}, + +KMFOID_VerisignCertificatePolicy = {OID_EXTENSION_LENGTH+1, + OID_VerisignCertificatePolicy}, + +KMFOID_KeyUsageRestriction = {OID_EXTENSION_LENGTH+1, + OID_KeyUsageRestriction}, + +KMFOID_SubjectDirectoryAttributes = {OID_EXTENSION_LENGTH+1, + OID_SubjectDirectoryAttributes}, + +KMFOID_SubjectKeyIdentifier = {OID_EXTENSION_LENGTH+1, + OID_SubjectKeyIdentifier }, +KMFOID_KeyUsage = {OID_EXTENSION_LENGTH+1, OID_KeyUsage }, + +KMFOID_PrivateKeyUsagePeriod = {OID_EXTENSION_LENGTH+1, + OID_PrivateKeyUsagePeriod}, +KMFOID_SubjectAltName = {OID_EXTENSION_LENGTH+1, OID_SubjectAltName }, +KMFOID_IssuerAltName = {OID_EXTENSION_LENGTH+1, OID_IssuerAltName }, +KMFOID_BasicConstraints = {OID_EXTENSION_LENGTH+1, OID_BasicConstraints }, + +KMFOID_CrlNumber = {OID_EXTENSION_LENGTH+1, OID_CrlNumber}, + +KMFOID_CrlReason = {OID_EXTENSION_LENGTH+1, OID_CrlReason}, + +KMFOID_HoldInstructionCode = {OID_EXTENSION_LENGTH+1, OID_HoldInstructionCode}, + +KMFOID_InvalidityDate = {OID_EXTENSION_LENGTH+1, OID_InvalidityDate}, + +KMFOID_DeltaCrlIndicator = {OID_EXTENSION_LENGTH+1, OID_DeltaCrlIndicator}, + +KMFOID_IssuingDistributionPoints = {OID_EXTENSION_LENGTH+1, + OID_IssuingDistributionPoints}, + +KMFOID_NameConstraints = {OID_EXTENSION_LENGTH+1, + OID_NameConstraints}, + +KMFOID_CrlDistributionPoints = {OID_EXTENSION_LENGTH+1, + OID_CrlDistributionPoints}, + +KMFOID_CertificatePolicies = {OID_EXTENSION_LENGTH+1, + OID_CertificatePolicies}, + +KMFOID_PolicyMappings = {OID_EXTENSION_LENGTH+1, OID_PolicyMappings}, + +KMFOID_PolicyConstraints = {OID_EXTENSION_LENGTH+1, OID_PolicyConstraints}, + +KMFOID_AuthorityKeyIdentifier = {OID_EXTENSION_LENGTH+1, + OID_AuthorityKeyIdentifier}, + +KMFOID_ExtendedKeyUsage = {OID_EXTENSION_LENGTH+1, OID_ExtKeyUsage}, + +KMFOID_PKIX_PQ_CPSuri = {OID_PKIX_QT_CPS_LENGTH, OID_QT_CPSuri}, + +KMFOID_PKIX_PQ_Unotice = {OID_PKIX_QT_UNOTICE_LENGTH, OID_QT_Unotice}, + +/* Extended Key Usage OIDs */ +KMFOID_PKIX_KP_ServerAuth = {OID_PKIX_KP_LENGTH + 1, OID_KP_ServerAuth}, + +KMFOID_PKIX_KP_ClientAuth = {OID_PKIX_KP_LENGTH + 1, OID_KP_ClientAuth}, + +KMFOID_PKIX_KP_CodeSigning = {OID_PKIX_KP_LENGTH + 1, OID_KP_CodeSigning}, + +KMFOID_PKIX_KP_EmailProtection = {OID_PKIX_KP_LENGTH + 1, + OID_KP_EmailProtection}, + +KMFOID_PKIX_KP_IPSecEndSystem = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecEndSystem}, + +KMFOID_PKIX_KP_IPSecTunnel = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecTunnel}, + +KMFOID_PKIX_KP_IPSecUser = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecUser}, + +KMFOID_PKIX_KP_TimeStamping = {OID_PKIX_KP_LENGTH + 1, OID_KP_TimeStamping}, + +KMFOID_PKIX_KP_OCSPSigning = {OID_PKIX_KP_LENGTH + 1, OID_KP_OCSPSigning}; diff --git a/usr/src/cmd/cmd-crypto/pktool/derparse.h b/usr/src/lib/libkmf/libkmf/common/llib-lkmf index 2ff36d2163..114e823e4d 100644 --- a/usr/src/cmd/cmd-crypto/pktool/derparse.h +++ b/usr/src/lib/libkmf/libkmf/common/llib-lkmf @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,36 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _PKTOOL_DERPARSE_H -#define _PKTOOL_DERPARSE_H - #pragma ident "%Z%%M% %I% %E% SMI" -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef LBER_OID -#define LBER_OID 0x06 -#endif - -#ifndef LBER_PRINTABLE_STRING -#define LBER_PRINTABLE_STRING 0x13 -#endif - -#ifndef LBER_IA5STRING -#define LBER_IA5STRING 0x16 -#endif - -extern void rdnseq_to_str(uchar_t *from, size_t from_sz, char *to, - size_t to_sz); - -#ifdef __cplusplus -} -#endif - -#endif /* _PKTOOL_DERPARSE_H */ +/* LINTLIBRARY */ +/* PROTOLIB1 */ +#include <kmfapi.h> +#include <kmfpolicy.h> diff --git a/usr/src/lib/libkmf/libkmf/common/mapfile-vers b/usr/src/lib/libkmf/libkmf/common/mapfile-vers new file mode 100644 index 0000000000..6de1bf01f5 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/mapfile-vers @@ -0,0 +1,288 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + DigestData; + GetIDFromSPKI; + KMF_AddCertEKU; + KMF_AddPolicyToDB; + KMF_CheckCRLDate; + KMF_CheckCertDate; + KMF_CompareRDNs; + KMF_ConfigureKeystore; + KMF_CreateCSRFile; + KMF_CreateCertFile; + KMF_CreateKeypair; + KMF_CreateOCSPRequest; + KMF_CreateSymKey; + KMF_DN2Der; + KMF_DNParser; + KMF_DecryptWithCert; + KMF_DeleteCRL; + KMF_DeleteCertFromKeystore; + KMF_DeleteKeyFromKeystore; + KMF_DeletePolicyFromDB; + KMF_Der2Pem; + KMF_DownloadCRL; + KMF_DownloadCert; + KMF_EncodeCertRecord; + KMF_EncryptWithCert; + KMF_ExportPK12; + KMF_Finalize; + KMF_FindCRL; + KMF_FindCert; + KMF_FindCertInCRL; + KMF_FindKey; + KMF_FreeAlgOID; + KMF_FreeBigint; + KMF_FreeCRLDistributionPoints; + KMF_FreeDN; + KMF_FreeData; + KMF_FreeEKU; + KMF_FreeEKUPolicy; + KMF_FreeExtension; + KMF_FreeKMFCert; + KMF_FreeKMFKey; + KMF_FreePolicyRecord; + KMF_FreeRawKey; + KMF_FreeRawSymKey; + KMF_FreeSPKI; + KMF_FreeSignedCSR; + KMF_FreeSignedCert; + KMF_FreeString; + KMF_FreeTBSCSR; + KMF_FreeTBSCert; + KMF_GetCertAuthInfoAccessExt; + KMF_GetCertBasicConstraintExt; + KMF_GetCertCriticalExtensions; + KMF_GetCertCRLDistributionPointsExt; + KMF_GetCertEKU; + KMF_GetCertEmailString; + KMF_GetCertEndDateString; + KMF_GetCertExtensionData; + KMF_GetCertExtensionString; + KMF_GetCertIDData; + KMF_GetCertIDString; + KMF_GetCertIssuerNameString; + KMF_GetCertKeyUsageExt; + KMF_GetCertNonCriticalExtensions; + KMF_GetCertPoliciesExt; + KMF_GetCertPubKeyAlgString; + KMF_GetCertPubKeyDataString; + KMF_GetCertSerialNumberString; + KMF_GetCertSignatureAlgString; + KMF_GetCertStartDateString; + KMF_GetCertSubjectNameString; + KMF_GetCertValidity; + KMF_GetCertVersionString; + KMF_GetEncodedOCSPResponse; + KMF_GetFileFormat; + KMF_GetKMFErrorString; + KMF_GetOCSPForCert; + KMF_GetOCSPStatusForCert; + KMF_GetPluginErrorString; + KMF_GetPolicy; + KMF_GetSymKeyValue; + KMF_HexString2Bytes; + KMF_ImportCRL; + KMF_ImportCert; + KMF_ImportPK12; + KMF_Initialize; + KMF_IsCRLFile; + KMF_IsCertFile; + KMF_ListCRL; + KMF_OID2EKUString; + KMF_OID2String; + KMF_PK11TokenLookup; + KMF_Pem2Der; + KMF_ReadInputFile; + KMF_SelectToken; + KMF_SetCSRExtension; + KMF_SetCSRKeyUsage; + KMF_SetCSRPubKey; + KMF_SetCSRSignatureAlgorithm; + KMF_SetCSRSubjectAltName; + KMF_SetCSRSubjectName; + KMF_SetCSRVersion; + KMF_SetCertBasicConstraintExt; + KMF_SetCertExtension; + KMF_SetCertIssuerAltName; + KMF_SetCertIssuerName; + KMF_SetCertKeyUsage; + KMF_SetCertPubKey; + KMF_SetCertSerialNumber; + KMF_SetCertSignatureAlgorithm; + KMF_SetCertSubjectAltName; + KMF_SetCertSubjectName; + KMF_SetCertValidityTimes; + KMF_SetCertVersion; + KMF_SetPolicy; + KMF_SetTokenPin; + KMF_SignCSR; + KMF_SignCertRecord; + KMF_SignCertWithCert; + KMF_SignCertWithKey; + KMF_SignDataWithCert; + KMF_SignDataWithKey; + KMF_StoreCert; + KMF_StorePrivateKey; + KMF_String2OID; + KMF_StringToKeyUsage; + KMF_ValidateCert; + KMF_VerifyCRLFile; + KMF_VerifyCertWithCert; + KMF_VerifyCertWithKey; + KMF_VerifyDataWithCert; + KMF_VerifyDataWithKey; + KMF_VerifyPolicy; + KMFOID_AliasedEntryName; + KMFOID_AuthorityInfoAccess; + KMFOID_AuthorityKeyID; + KMFOID_AuthorityKeyIdentifier; + KMFOID_AuthorityRevocationList; + KMFOID_BasicConstraints; + KMFOID_BusinessCategory; + KMFOID_CACertificate; + KMFOID_CertificatePolicies; + KMFOID_CertificateRevocationList; + KMFOID_ChallengePassword; + KMFOID_CollectiveFacsimileTelephoneNumber; + KMFOID_CollectiveInternationalISDNNumber; + KMFOID_CollectiveOrganizationName; + KMFOID_CollectiveOrganizationalUnitName; + KMFOID_CollectivePhysicalDeliveryOfficeName; + KMFOID_CollectivePostOfficeBox; + KMFOID_CollectivePostalAddress; + KMFOID_CollectivePostalCode; + KMFOID_CollectiveStateProvinceName; + KMFOID_CollectiveStreetAddress; + KMFOID_CollectiveTelephoneNumber; + KMFOID_CollectiveTelexNumber; + KMFOID_CollectiveTelexTerminalIdentifier; + KMFOID_CommonName; + KMFOID_ContentType; + KMFOID_CounterSignature; + KMFOID_CountryName; + KMFOID_CrlDistributionPoints; + KMFOID_CrlNumber; + KMFOID_CrlReason; + KMFOID_CrossCertificatePair; + KMFOID_DNQualifier; + KMFOID_DeltaCrlIndicator; + KMFOID_Description; + KMFOID_DestinationIndicator; + KMFOID_DistinguishedName; + KMFOID_EmailAddress; + KMFOID_EnhancedSearchGuide; + KMFOID_ExtendedCertificateAttributes; + KMFOID_ExtendedKeyUsage; + KMFOID_ExtensionRequest; + KMFOID_FacsimileTelephoneNumber; + KMFOID_GenerationQualifier; + KMFOID_GivenName; + KMFOID_HoldInstructionCode; + KMFOID_HouseIdentifier; + KMFOID_Initials; + KMFOID_InternationalISDNNumber; + KMFOID_InvalidityDate; + KMFOID_IssuerAltName; + KMFOID_IssuingDistributionPoints; + KMFOID_KeyUsage; + KMFOID_KeyUsageRestriction; + KMFOID_KnowledgeInformation; + KMFOID_LocalityName; + KMFOID_Member; + KMFOID_MessageDigest; + KMFOID_Name; + KMFOID_NameConstraints; + KMFOID_ObjectClass; + KMFOID_OrganizationName; + KMFOID_OrganizationalUnitName; + KMFOID_Owner; + KMFOID_PKIX_KP_ClientAuth; + KMFOID_PKIX_KP_CodeSigning; + KMFOID_PKIX_KP_EmailProtection; + KMFOID_PKIX_KP_IPSecEndSystem; + KMFOID_PKIX_KP_IPSecTunnel; + KMFOID_PKIX_KP_IPSecUser; + KMFOID_PKIX_KP_OCSPSigning; + KMFOID_PKIX_KP_ServerAuth; + KMFOID_PKIX_KP_TimeStamping; + KMFOID_PKIX_PQ_CPSuri; + KMFOID_PKIX_PQ_Unotice; + KMFOID_PhysicalDeliveryOfficeName; + KMFOID_PkixAdCaIssuers; + KMFOID_PkixAdOcsp; + KMFOID_PolicyConstraints; + KMFOID_PolicyMappings; + KMFOID_PostOfficeBox; + KMFOID_PostalAddress; + KMFOID_PostalCode; + KMFOID_PreferredDeliveryMethod; + KMFOID_PresentationAddress; + KMFOID_PrivateKeyUsagePeriod; + KMFOID_ProtocolInformation; + KMFOID_RFC822mailbox; + KMFOID_RegisteredAddress; + KMFOID_RoleOccupant; + KMFOID_SearchGuide; + KMFOID_SeeAlso; + KMFOID_SerialNumber; + KMFOID_SigningTime; + KMFOID_StateProvinceName; + KMFOID_StreetAddress; + KMFOID_SubjectAltName; + KMFOID_SubjectDirectoryAttributes; + KMFOID_SubjectKeyIdentifier; + KMFOID_SupportedApplicationContext; + KMFOID_Surname; + KMFOID_TelephoneNumber; + KMFOID_TelexNumber; + KMFOID_TelexTerminalIdentifier; + KMFOID_Title; + KMFOID_UniqueIdentifier; + KMFOID_UniqueMember; + KMFOID_UnstructuredAddress; + KMFOID_UnstructuredName; + KMFOID_UserCertificate; + KMFOID_UserPassword; + KMFOID_VerisignCertificatePolicy; + KMFOID_X_121Address; + KMFOID_domainComponent; + KMFOID_userid; + PKCS_GetDefaultSignatureMode; + PKCS_GetAlgorithmMap; + X509_AlgIdToAlgorithmOid; + X509_AlgorithmOidToAlgId; + kmf_ekuname2oid; + kmf_string2oid; + ku2str; + parsePolicyElement; + local: + *; +}; diff --git a/usr/src/lib/libkmf/libkmf/common/pem_encode.c b/usr/src/lib/libkmf/libkmf/common/pem_encode.c new file mode 100644 index 0000000000..cc19a852f5 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/pem_encode.c @@ -0,0 +1,628 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* pem_encode.c - PEM encoding routines */ + +#include <stdlib.h> +#include <strings.h> +#include <sys/types.h> +#include <kmfapi.h> +#include <pem_encode.h> + +static unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ +abcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned char data_ascii2bin[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, + 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, + 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f]) +#define conv_ascii2bin(a) (data_ascii2bin[(a)&0x7f]) + + +void +PEM_EncodeInit(PEM_ENCODE_CTX *ctx) +{ + ctx->length = 48; + ctx->num = 0; + ctx->line_num = 0; +} + +int +PEM_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen) +{ + int i, ret = 0; + unsigned long l; + + for (i = dlen; i > 0; i -= 3) { + if (i >= 3) { + l = (((unsigned long)f[0])<<16L)| + (((unsigned long)f[1])<< 8L)|f[2]; + *(t++) = conv_bin2ascii(l>>18L); + *(t++) = conv_bin2ascii(l>>12L); + *(t++) = conv_bin2ascii(l>> 6L); + *(t++) = conv_bin2ascii(l); + } else { + l = ((unsigned long)f[0])<<16L; + if (i == 2) + l |= ((unsigned long)f[1]<<8L); + + *(t++) = conv_bin2ascii(l>>18L); + *(t++) = conv_bin2ascii(l>>12L); + *(t++) = (i == 1)?'=':conv_bin2ascii(l>> 6L); + *(t++) = '='; + } + ret += 4; + f += 3; + } + + *t = '\0'; + return (ret); +} + +void +PEM_EncodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl, + unsigned char *in, int inl) +{ + int i, j; + unsigned int total = 0; + + *outl = 0; + if (inl == 0) + return; + if ((ctx->num+inl) < ctx->length) { + (void) memcpy(&(ctx->enc_data[ctx->num]), in, inl); + ctx->num += inl; + return; + } + if (ctx->num != 0) { + i = ctx->length-ctx->num; + (void) memcpy(&(ctx->enc_data[ctx->num]), in, i); + in += i; + inl -= i; + j = PEM_EncodeBlock(out, ctx->enc_data, ctx->length); + ctx->num = 0; + out += j; + *(out++) = '\n'; + *out = '\0'; + total = j+1; + } + + while (inl >= ctx->length) { + j = PEM_EncodeBlock(out, in, ctx->length); + in += ctx->length; + inl -= ctx->length; + out += j; + *(out++) = '\n'; + *out = '\0'; + total += j+1; + } + + if (inl != 0) + (void) memcpy(&(ctx->enc_data[0]), in, inl); + ctx->num = inl; + *outl = total; +} + +void +PEM_EncodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl) +{ + unsigned int ret = 0; + + if (ctx->num != 0) { + ret = PEM_EncodeBlock(out, ctx->enc_data, ctx->num); + out[ret++] = '\n'; + out[ret] = '\0'; + ctx->num = 0; + } + *outl = ret; +} + +KMF_RETURN +Der2Pem(KMF_OBJECT_TYPE type, unsigned char *data, + int len, unsigned char **out, int *outlen) +{ + + + int nlen, n, i, j, outl; + unsigned char *buf = NULL, *p = NULL; + PEM_ENCODE_CTX ctx; + char *name = NULL; + + if (data == NULL || len == 0 || out == NULL || outlen == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (type == KMF_CERT) + name = PEM_STRING_X509; + else if (type == KMF_CSR) + name = PEM_STRING_X509_REQ; + else if (type == KMF_CRL) + name = PEM_STRING_X509_CRL; + else + return (KMF_ERR_BAD_OBJECT_TYPE); + + + PEM_EncodeInit(&ctx); + nlen = strlen(name); + + buf = malloc(PEM_BUFSIZE*8); + if (buf == NULL) { + return (KMF_ERR_MEMORY); + } + + p = buf; + (void) memcpy(p, "-----BEGIN ", 11); + p += 11; + (void) memcpy(p, name, nlen); + p += nlen; + (void) memcpy(p, "-----\n", 6); + p += 6; + + i = j = 0; + while (len > 0) { + n = (int)((len > (PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len); + PEM_EncodeUpdate(&ctx, p, &outl, &(data[j]), n); + i += outl; + len -= n; + j += n; + p += outl; + } + + PEM_EncodeFinal(&ctx, p, &outl); + + if (outl > 0) + p += outl; + + (void) memcpy(p, "-----END ", 9); + p += 9; + (void) memcpy(p, name, nlen); + p += nlen; + (void) memcpy(p, "-----\n", 6); + p += 6; + + *out = buf; + *outlen = i+outl+nlen*2+11+6+9+6; + + return (KMF_OK); + +} + +int +PEM_DecodeBlock(unsigned char *t, const unsigned char *f, int n) +{ + int i, ret = 0, a, b, c, d; + unsigned long l; + + /* trim white space from the start of the line. */ + while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) { + f++; + n--; + } + + /* + * strip off stuff at the end of the line + * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF + */ + while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1])))) + n--; + + if (n%4 != 0) { + return (-1); + } + + for (i = 0; i < n; i += 4) { + a = conv_ascii2bin(*(f++)); + b = conv_ascii2bin(*(f++)); + c = conv_ascii2bin(*(f++)); + d = conv_ascii2bin(*(f++)); + if ((a & 0x80) || (b & 0x80) || + (c & 0x80) || (d & 0x80)) + return (-1); + l = ((((unsigned long)a)<<18L)| + (((unsigned long)b)<<12L)| + (((unsigned long)c)<< 6L)| + (((unsigned long)d))); + *(t++) = (unsigned char)(l>>16L)&0xff; + *(t++) = (unsigned char)(l>> 8L)&0xff; + *(t++) = (unsigned char)(l)&0xff; + ret += 3; + } + return (ret); +} + +void +PEM_DecodeInit(PEM_ENCODE_CTX *ctx) +{ + ctx->length = 30; + ctx->num = 0; + ctx->line_num = 0; + ctx->expect_nl = 0; +} + +/* + * -1 for error + * 0 for last line + * 1 for full line + */ +int +PEM_DecodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl, + unsigned char *in, int inl) +{ + int seof = -1, eof = 0, rv = -1, ret = 0; + int i, v, tmp, n, ln, exp_nl; + unsigned char *d; + + n = ctx->num; + d = ctx->enc_data; + ln = ctx->line_num; + exp_nl = ctx->expect_nl; + + /* last line of input. */ + if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) { + rv = 0; + goto end; + } + + /* We parse the input data */ + for (i = 0; i < inl; i++) { + /* If the current line is > 80 characters, scream alot */ + if (ln >= 80) { + rv = -1; + goto end; + } + + /* Get char and put it into the buffer */ + tmp = *(in++); + v = conv_ascii2bin(tmp); + /* only save the good data :-) */ + if (!B64_NOT_BASE64(v)) { + d[n++] = tmp; + ln++; + } else if (v == B64_ERROR) { + rv = -1; + goto end; + } + + /* + * have we seen a '=' which is 'definitly' the last + * input line. seof will point to the character that + * holds it. and eof will hold how many characters to + * chop off. + */ + if (tmp == '=') { + if (seof == -1) seof = n; + eof++; + } + + if (v == B64_CR) { + ln = 0; + if (exp_nl) + continue; + } + + /* eoln */ + if (v == B64_EOLN) { + ln = 0; + if (exp_nl) { + exp_nl = 0; + continue; + } + } + exp_nl = 0; + + /* + * If we are at the end of input and it looks like a + * line, process it. + */ + if (((i+1) == inl) && (((n&3) == 0) || eof)) { + v = B64_EOF; + /* + * In case things were given us in really small + * records (so two '=' were given in separate + * updates), eof may contain the incorrect number + * of ending bytes to skip, so let's redo the count + */ + eof = 0; + if (d[n-1] == '=') eof++; + if (d[n-2] == '=') eof++; + /* There will never be more than two '=' */ + } + + if ((v == B64_EOF) || (n >= 64)) { + /* + * This is needed to work correctly on 64 byte input + * lines. We process the line and then need to + * accept the '\n' + */ + if ((v != B64_EOF) && (n >= 64)) + exp_nl = 1; + if (n > 0) { + v = PEM_DecodeBlock(out, d, n); + if (v < 0) { + rv = 0; + goto end; + } + n = 0; + ret += (v-eof); + } else { + eof = 1; + v = 0; + } + + /* + * This is the case where we have had a short + * but valid input line + */ + if ((v < ctx->length) && eof) { + rv = 0; + goto end; + } else + ctx->length = v; + + if (seof >= 0) { + rv = 0; + goto end; + } + out += v; + } + } + rv = 1; +end: + *outl = ret; + ctx->num = n; + ctx->line_num = ln; + ctx->expect_nl = exp_nl; + return (rv); +} + +int +PEM_DecodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl) +{ + int i; + + *outl = 0; + if (ctx->num != 0) { + i = PEM_DecodeBlock(out, ctx->enc_data, ctx->num); + if (i < 0) + return (-1); + ctx->num = 0; + *outl = i; + return (1); + } else + return (1); +} + +static int +get_line(unsigned char *in, char *buf) +{ + + int i = 0; + int len = 0; + + while ((in[i] != '\n')) { + buf[i] = in[i]; + i++; + len++; + } + + return (len); +} + +KMF_RETURN +Pem2Der(unsigned char *in, int inlen, + unsigned char **out, int *outlen) +{ + int kmf_rv = 0; + PEM_ENCODE_CTX ctx; + int i, k, bl = 0; + char buf[2048]; + char *nameB; + unsigned char *dataB; + int total = 0; + + if (in == NULL || inlen == 0 || out == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(buf, 0, sizeof (buf)); + + for (;;) { + /* + * get a line (ended at '\n'), which returns + * number of bytes in the line + */ + i = get_line(in, buf); + if (i <= 0) { + kmf_rv = KMF_ERR_ENCODING; + goto err; + } + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i] = '\n'; + buf[++i] = '\0'; + total += i; + + if (strncmp(buf, "-----BEGIN ", 11) == 0) { + i = strlen(&(buf[11])); + if (strncmp(&(buf[11+i-6]), "-----\n", 6) != 0) { + continue; + } + + if ((nameB = malloc(i+9)) == NULL) { + kmf_rv = KMF_ERR_MEMORY; + goto err; + } + + (void) memcpy(nameB, &(buf[11]), i-6); + nameB[i-6] = '\0'; + break; + } + } + + bl = 0; + if ((dataB = malloc(2048)) == NULL) { + kmf_rv = KMF_ERR_MEMORY; + goto err; + } + + dataB[0] = '\0'; + + for (;;) { + (void) memset(buf, 0, 1024); + i = get_line(in+total, buf); + + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) + i--; + + buf[++i] = '\n'; + buf[++i] = '\0'; + total += i; + + if (buf[0] == '\n') break; + if ((dataB = realloc(dataB, bl+i+9)) == NULL) { + kmf_rv = KMF_ERR_MEMORY; + goto err; + } + + if (strncmp(buf, "-----END ", 9) == 0) { + break; + } + + (void) memcpy(&(dataB[bl]), buf, i); + dataB[bl+i] = '\0'; + bl += i; + } + + i = strlen(nameB); + if ((strncmp(buf, "-----END ", 9) != 0) || + (strncmp(nameB, &(buf[9]), i) != 0) || + (strncmp(&(buf[9+i]), "-----", 5) != 0)) { + kmf_rv = KMF_ERR_ENCODING; + goto err; + } + + PEM_DecodeInit(&ctx); + i = PEM_DecodeUpdate(&ctx, + (unsigned char *)dataB, &bl, (unsigned char *)dataB, bl); + + if (i < 0) { + kmf_rv = KMF_ERR_ENCODING; + goto err; + } + + i = PEM_DecodeFinal(&ctx, (unsigned char *)&(dataB[bl]), &k); + if (i < 0) { + kmf_rv = KMF_ERR_ENCODING; + goto err; + } + bl += k; + + if (bl == 0) goto err; + *out = (unsigned char *)dataB; + *outlen = bl; + +err: + free(nameB); + if (kmf_rv != KMF_OK) + free(dataB); + + return (kmf_rv); +} diff --git a/usr/src/lib/libkmf/libkmf/common/pk11keys.c b/usr/src/lib/libkmf/libkmf/common/pk11keys.c new file mode 100644 index 0000000000..adbcf64224 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/pk11keys.c @@ -0,0 +1,735 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * File: KEYS.C + * + * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapiP.h> +#include <security/cryptoki.h> + +#include <algorithm.h> +#include <ber_der.h> + +#define MAX_PUBLIC_KEY_TEMPLATES (20) +#define MAX_PRIVATE_KEY_TEMPLATES (24) +#define MAX_SECRET_KEY_TEMPLATES (24) + +static KMF_RETURN +create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech, + CK_FLAGS wanted_flags) +{ + CK_RV rv; + KMF_RETURN kmf_rv = KMF_OK; + CK_SLOT_ID_PTR pSlotList; + CK_ULONG pulCount; + CK_MECHANISM_INFO info; + int i; + + if (!is_pk11_ready()) { + rv = C_Initialize(NULL); + if ((rv != CKR_OK) && + (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { + kmf_rv = KMF_ERR_UNINITIALIZED; + goto out; + } + } + + rv = C_GetSlotList(0, NULL, &pulCount); + if (rv != CKR_OK) { + kmf_rv = KMF_ERR_UNINITIALIZED; + goto out; + } + + pSlotList = (CK_SLOT_ID_PTR) malloc(pulCount * sizeof (CK_SLOT_ID)); + if (pSlotList == NULL) { + kmf_rv = KMF_ERR_MEMORY; + goto out; + } + + rv = C_GetSlotList(0, pSlotList, &pulCount); + if (rv != CKR_OK) { + kmf_rv = KMF_ERR_UNINITIALIZED; + goto out; + } + + for (i = 0; i < pulCount; i++) { + rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info); + if (rv == CKR_OK && (info.flags & wanted_flags)) + break; + } + if (i < pulCount) { + rv = C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION, + NULL, NULL, sessionp); + + if (rv != CKR_OK) { + kmf_rv = KMF_ERR_UNINITIALIZED; + } + } else { + kmf_rv = KMF_ERR_UNINITIALIZED; + } + +out: + if (pSlotList != NULL) + free(pSlotList); + return (kmf_rv); + +} + +/* + * Name: PKCS_AddTemplate + * + * Description: + * Adds a CK_ATTRIBUTE value to an existing array of CK_ATTRIBUTES. Will + * not expand the array beyond the maximum specified size. + * + * Returns: + * TRUE - Attribute value succesfully added. + * FALSE - Maximum array size would be exceded. + */ +static int +PKCS_AddTemplate(CK_ATTRIBUTE *pTemplate, + CK_ULONG *ckNumTemplates, + CK_ULONG ckMaxTemplates, + CK_ATTRIBUTE_TYPE ckAttribCode, + CK_BYTE * pckBuffer, + CK_ULONG ckBufferLen) +{ + if (*ckNumTemplates >= ckMaxTemplates) { + return (FALSE); + } + + pTemplate[*ckNumTemplates].type = ckAttribCode; + pTemplate[*ckNumTemplates].pValue = pckBuffer; + pTemplate[*ckNumTemplates].ulValueLen = ckBufferLen; + (*ckNumTemplates)++; + + return (TRUE); +} + +/* + * Convert an SPKI data record to PKCS#11 + * public key object. + */ +static KMF_RETURN +PKCS_CreatePublicKey( + const KMF_X509_SPKI *pKey, + CK_SESSION_HANDLE ckSession, + CK_OBJECT_HANDLE *pckPublicKey) +{ + KMF_RETURN mrReturn = KMF_OK; + CK_RV ckRv; + + CK_ATTRIBUTE ckTemplate[MAX_PUBLIC_KEY_TEMPLATES]; + CK_ULONG ckNumTemplates = 0; + + /* Common object attributes */ + CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY; + CK_BBOOL ckToken = 0; + CK_BBOOL ckPrivate = 0; + + /* Common key attributes */ + CK_KEY_TYPE ckKeyType; + CK_BBOOL ckDerive = CK_FALSE; + + /* Common public key attributes */ + CK_BBOOL ckEncrypt = 1; + CK_BBOOL ckVerify = 1; + + CK_BBOOL ckVerifyRecover = CK_FALSE; + CK_BBOOL ckWrap = CK_FALSE; + + /* Key part array */ + KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS]; + uint32_t i, uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS; + KMF_ALGORITHM_INDEX AlgorithmId; + + /* Parse the keyblob */ + (void) memset(KeyParts, 0, sizeof (KeyParts)); + + AlgorithmId = X509_AlgorithmOidToAlgId((KMF_OID *) + &pKey->algorithm.algorithm); + + mrReturn = ExtractSPKIData(pKey, AlgorithmId, KeyParts, &uNumKeyParts); + + if (mrReturn != KMF_OK) + return (mrReturn); + + /* Fill in the common object attributes */ + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_CLASS, + (CK_BYTE *)&ckObjClass, + sizeof (ckObjClass)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_TOKEN, + (CK_BYTE *)&ckToken, + sizeof (ckToken)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_PRIVATE, + (CK_BYTE *)&ckPrivate, + sizeof (ckPrivate))) { + mrReturn = KMF_ERR_INTERNAL; + goto cleanup; + } + + /* Fill in the common key attributes */ + if (!PKCS_ConvertAlgorithmId2PKCSKeyType(AlgorithmId, + &ckKeyType)) { + goto cleanup; + } + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_KEY_TYPE, + (CK_BYTE *)&ckKeyType, + sizeof (ckKeyType)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_DERIVE, + (CK_BYTE *)&ckDerive, + sizeof (ckDerive))) { + mrReturn = KMF_ERR_INTERNAL; + goto cleanup; + } + + /* Add common public key attributes */ + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_ENCRYPT, + (CK_BYTE *)&ckEncrypt, + sizeof (ckEncrypt)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_VERIFY, + (CK_BYTE *)&ckVerify, + sizeof (ckVerify)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_VERIFY_RECOVER, + (CK_BYTE *)&ckVerifyRecover, + sizeof (ckVerifyRecover)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_WRAP, + (CK_BYTE *)&ckWrap, + sizeof (ckWrap))) { + mrReturn = KMF_ERR_INTERNAL; + goto cleanup; + } + + /* Add algorithm specific attributes */ + switch (ckKeyType) { + case CKK_RSA: + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_MODULUS, + (CK_BYTE *)KeyParts[KMF_RSA_MODULUS].Data, + (CK_ULONG)KeyParts[KMF_RSA_MODULUS].Length) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_PUBLIC_EXPONENT, + (CK_BYTE *)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Data, + (CK_ULONG)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Length)) { + mrReturn = KMF_ERR_INTERNAL; + goto cleanup; + } + break; + case CKK_DSA: + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_PRIME, + (CK_BYTE *)KeyParts[KMF_DSA_PRIME].Data, + (CK_ULONG)KeyParts[KMF_DSA_PRIME].Length) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_SUBPRIME, + (CK_BYTE *)KeyParts[KMF_DSA_SUB_PRIME].Data, + (CK_ULONG)KeyParts[KMF_DSA_SUB_PRIME].Length) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_BASE, + (CK_BYTE *)KeyParts[KMF_DSA_BASE].Data, + (CK_ULONG)KeyParts[KMF_DSA_BASE].Length) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, + CKA_VALUE, + (CK_BYTE *)KeyParts[KMF_DSA_PUBLIC_VALUE].Data, + (CK_ULONG)KeyParts[KMF_DSA_PUBLIC_VALUE].Length)) { + mrReturn = KMF_ERR_INTERNAL; + goto cleanup; + } + break; + default: + mrReturn = KMF_ERR_BAD_PARAMETER; + } + + if (mrReturn == KMF_OK) { + /* Instantiate the object */ + ckRv = C_CreateObject(ckSession, + ckTemplate, + ckNumTemplates, + pckPublicKey); + if (ckRv != CKR_OK) + mrReturn = KMF_ERR_INTERNAL; + } + +cleanup: + for (i = 0; i < uNumKeyParts; i++) { + KMF_FreeData(&KeyParts[i]); + } + + return (mrReturn); +} + +/* + * PKCS_AcquirePublicKeyHandle + * + * Given an assymetric key keyblob, attempts to find the appropriate + * public key. + * + * Methods of finding the public key: + * - Public Key with data present: + * Parses the key and creates a temporary session object. + * - Public Key with handle: + * The handle is type converted and returned. Validity of the handle is + * not checked. + * - Public Key with label: + * Attempts to find a public key with the corresponding label. + */ +static KMF_RETURN +PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, + const KMF_X509_SPKI *pKey, + CK_KEY_TYPE ckRequestedKeyType, + CK_OBJECT_HANDLE *pckKeyHandle, + KMF_BOOL *pbTemporary) +{ + KMF_RETURN mrReturn = KMF_OK; + + + /* Key searching variables */ + CK_OBJECT_HANDLE ckKeyHandle; + CK_OBJECT_CLASS ckObjClass; + CK_KEY_TYPE ckKeyType; + CK_ATTRIBUTE ckTemplate[3]; + CK_ULONG ckNumTemplates; + static const CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) / + sizeof (CK_ATTRIBUTE)); + CK_RV ckRv; + + /* Extract the data from the SPKI into individual fields */ + mrReturn = PKCS_CreatePublicKey(pKey, ckSession, &ckKeyHandle); + if (mrReturn != KMF_OK) + return (mrReturn); + + *pbTemporary = KMF_TRUE; + + /* Fetch the key class and algorithm from the object */ + ckNumTemplates = 0; + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + ckMaxTemplates, + CKA_CLASS, + (CK_BYTE *)&ckObjClass, + sizeof (ckObjClass)) || + !PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + ckMaxTemplates, + CKA_KEY_TYPE, + (CK_BYTE *)&ckKeyType, + sizeof (ckKeyType))) { + return (KMF_ERR_INTERNAL); + } + ckRv = C_GetAttributeValue(ckSession, + ckKeyHandle, + ckTemplate, + ckNumTemplates); + if (ckRv != CKR_OK) { + return (ckRv); + } + + /* Make sure the results match the expected values */ + if ((ckKeyType != ckRequestedKeyType) || + (ckObjClass != CKO_PUBLIC_KEY)) { + if (*pbTemporary == KMF_TRUE) { + (void) C_DestroyObject(ckSession, ckKeyHandle); + } + + return (KMF_ERR_BAD_KEY_FORMAT); + } + + /* Set the return values */ + *pckKeyHandle = ckKeyHandle; + + return (KMF_OK); +} + +KMF_SIGNATURE_MODE +PKCS_GetDefaultSignatureMode(KMF_ALGORITHM_INDEX AlgId) +{ + KMF_SIGNATURE_MODE AlgMode; + + switch (AlgId) { + case KMF_ALGID_RSA: + case KMF_ALGID_MD5WithRSA: + case KMF_ALGID_MD2WithRSA: + case KMF_ALGID_SHA1WithRSA: + AlgMode = KMF_ALGMODE_PKCS1_EMSA_V15; + break; + default: + AlgMode = KMF_ALGMODE_NONE; + break; + } + + return (AlgMode); +} + +KMF_RETURN +PKCS_VerifyData(KMF_HANDLE_T kmfh, + KMF_ALGORITHM_INDEX AlgorithmId, + KMF_X509_SPKI *keyp, + KMF_DATA *data, + KMF_DATA *signed_data) +{ + KMF_RETURN rv = KMF_OK; + PKCS_ALGORITHM_MAP *pAlgMap = NULL; + CK_RV ckRv; + CK_MECHANISM ckMechanism; + CK_OBJECT_HANDLE ckKeyHandle; + KMF_BOOL bTempKey; + CK_SESSION_HANDLE ckSession = 0; + + if (AlgorithmId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_ALGORITHM); + + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId)); + + if (!pAlgMap) + return (KMF_ERR_BAD_ALGORITHM); + + rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism, + CKF_VERIFY); + + if (rv != KMF_OK) + return (rv); + + /* Fetch the verifying key */ + rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp, + pAlgMap->key_type, &ckKeyHandle, &bTempKey); + + if (rv != KMF_OK) { + (void) C_CloseSession(ckSession); + return (rv); + } + + ckMechanism.mechanism = pAlgMap->pkcs_mechanism; + ckMechanism.pParameter = NULL; + ckMechanism.ulParameterLen = 0; + + ckRv = C_VerifyInit(ckSession, &ckMechanism, ckKeyHandle); + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + + ckRv = C_Verify(ckSession, + (CK_BYTE *)data->Data, + (CK_ULONG)data->Length, + (CK_BYTE *)signed_data->Data, + (CK_ULONG)signed_data->Length); + + if (ckRv != CKR_OK) { + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + rv = KMF_ERR_INTERNAL; + } + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + + (void) C_CloseSession(ckSession); + return (rv); + +} + +KMF_RETURN +PKCS_EncryptData(KMF_HANDLE_T kmfh, + KMF_ALGORITHM_INDEX AlgorithmId, + KMF_X509_SPKI *keyp, + KMF_DATA *plaintext, + KMF_DATA *ciphertext) +{ + KMF_RETURN rv = KMF_OK; + PKCS_ALGORITHM_MAP *pAlgMap = NULL; + CK_RV ckRv; + CK_MECHANISM ckMechanism; + CK_OBJECT_HANDLE ckKeyHandle; + KMF_BOOL bTempKey; + CK_SESSION_HANDLE ckSession = NULL; + CK_ULONG out_len = 0, in_len = 0, total_encrypted = 0; + uint8_t *in_data, *out_data; + int i, blocks, block_size; + CK_ATTRIBUTE ckTemplate[2]; + CK_ULONG ckNumTemplates; + CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) / + sizeof (CK_ATTRIBUTE)); + + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId)); + + if (!pAlgMap) + return (KMF_ERR_BAD_ALGORITHM); + + rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism, + CKF_ENCRYPT); + + if (rv != KMF_OK) + return (rv); + + /* Get the public key used in encryption */ + rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp, + pAlgMap->key_type, &ckKeyHandle, &bTempKey); + + if (rv != KMF_OK) { + (void) C_CloseSession(ckSession); + return (rv); + } + + /* Get the modulus length */ + ckNumTemplates = 0; + if (!PKCS_AddTemplate(ckTemplate, + &ckNumTemplates, + ckMaxTemplates, + CKA_MODULUS, + (CK_BYTE *)NULL, + sizeof (CK_ULONG))) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + + ckRv = C_GetAttributeValue(ckSession, + ckKeyHandle, + ckTemplate, + ckNumTemplates); + + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + out_len = ckTemplate[0].ulValueLen; + + if (out_len > ciphertext->Length) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + (void) C_CloseSession(ckSession); + return (KMF_ERR_BUFFER_SIZE); + } + + ckMechanism.mechanism = pAlgMap->pkcs_mechanism; + ckMechanism.pParameter = NULL_PTR; + ckMechanism.ulParameterLen = 0; + + /* Compute the fixed input data length for single-part encryption */ + block_size = out_len - 11; + + in_data = plaintext->Data; + out_data = ciphertext->Data; + + blocks = plaintext->Length/block_size; + + for (i = 0; i < blocks; i++) { + ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle); + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, block_size, + (CK_BYTE_PTR)out_data, &out_len); + + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + + out_data += out_len; + total_encrypted += out_len; + in_data += block_size; + } + + if (plaintext->Length % block_size) { + /* Encrypt the remaining data */ + ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle); + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + + in_len = plaintext->Length % block_size; + ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, in_len, + (CK_BYTE_PTR)out_data, &out_len); + + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + (void) C_CloseSession(ckSession); + return (KMF_ERR_INTERNAL); + } + + out_data += out_len; + total_encrypted += out_len; + in_data += in_len; + } + + ciphertext->Length = total_encrypted; + + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + + (void) C_CloseSession(ckSession); + return (rv); + +} + +CK_RV +DigestData(CK_SESSION_HANDLE hSession, + KMF_DATA *IDInput, KMF_DATA *IDOutput) +{ + CK_RV rv = KMF_OK; + CK_MECHANISM mechanism = {CKM_SHA_1, NULL, 0}; + + rv = C_DigestInit(hSession, &mechanism); + if (rv != CKR_OK) + return (rv); + + rv = C_Digest(hSession, + IDInput->Data, IDInput->Length, + IDOutput->Data, (CK_ULONG *)&IDOutput->Length); + + return (rv); +} + +KMF_RETURN +GetIDFromSPKI(KMF_X509_SPKI *spki, + KMF_DATA *ID) +{ + KMF_RETURN rv = KMF_OK; + KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS]; + uint32_t uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS; + KMF_ALGORITHM_INDEX algId; + CK_SESSION_HANDLE hSession = NULL; + int i; + + if (ID == NULL || spki == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ID->Data = (uchar_t *)malloc(SHA1_HASH_LENGTH); + if (ID->Data == NULL) + return (KMF_ERR_MEMORY); + + ID->Length = SHA1_HASH_LENGTH; + + algId = X509_AlgorithmOidToAlgId(&spki->algorithm.algorithm); + + rv = ExtractSPKIData(spki, algId, KeyParts, &uNumKeyParts); + if (rv != KMF_OK) + return (rv); + + rv = create_pk11_session(&hSession, CKM_SHA_1, CKF_DIGEST); + + if (rv != KMF_OK) + return (rv); + + /* Check the KEY algorithm */ + if (algId == KMF_ALGID_RSA) { + rv = DigestData(hSession, + &KeyParts[KMF_RSA_MODULUS], + ID); + } else if (algId == KMF_ALGID_DSA) { + rv = DigestData(hSession, + &KeyParts[KMF_DSA_PUBLIC_VALUE], + ID); + } else { + /* We only support RSA and DSA keys for now */ + rv = KMF_ERR_BAD_ALGORITHM; + } + + + for (i = 0; i < uNumKeyParts; i++) { + if (KeyParts[i].Data != NULL) + free(KeyParts[i].Data); + } + + if (rv != KMF_OK && ID->Data != NULL) { + free(ID->Data); + ID->Data = NULL; + ID->Length = 0; + } + + (void) C_CloseSession(hSession); + return (rv); +} diff --git a/usr/src/lib/libkmf/libkmf/common/pk11tokens.c b/usr/src/lib/libkmf/libkmf/common/pk11tokens.c new file mode 100644 index 0000000000..f5e9c62c61 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/pk11tokens.c @@ -0,0 +1,531 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <security/cryptoki.h> +#include <kmfapi.h> +#include <kmfapiP.h> +#include <cryptoutil.h> + +/* + * memcmp_pad_max() is a specialized version of memcmp() which + * compares two pieces of data up to a maximum length. If the + * the two data match up the maximum length, they are considered + * matching. Trailing blanks do not cause the match to fail if + * one of the data is shorted. + * + * Examples of matches: + * "one" | + * "one " | + * ^maximum length + * + * "Number One | X" (X is beyond maximum length) + * "Number One " | + * ^maximum length + * + * Examples of mismatches: + * " one" + * "one" + * + * "Number One X|" + * "Number One |" + * ^maximum length + */ +static int +memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz) +{ + uint_t len, extra_len; + char *marker; + + /* No point in comparing anything beyond max_sz */ + if (d1_len > max_sz) + d1_len = max_sz; + if (d2_len > max_sz) + d2_len = max_sz; + + /* Find shorter of the two data. */ + if (d1_len <= d2_len) { + len = d1_len; + extra_len = d2_len; + marker = d2; + } else { /* d1_len > d2_len */ + len = d2_len; + extra_len = d1_len; + marker = d1; + } + + /* Have a match in the shortest length of data? */ + if (memcmp(d1, d2, len) != 0) + /* CONSTCOND */ + return (1); + + /* If the rest of longer data is nulls or blanks, call it a match. */ + while (len < extra_len) + if (!isspace(marker[len++])) + /* CONSTCOND */ + return (1); + return (0); +} + +static KMF_RETURN +kmf_get_token_slots(KMF_HANDLE *handle, CK_SLOT_ID_PTR *slot_list, + CK_ULONG *slot_count) +{ + + KMF_RETURN kmf_rv = KMF_OK; + CK_RV ck_rv = CKR_OK; + CK_ULONG tmp_count = 0; + CK_SLOT_ID_PTR tmp_list = NULL_PTR, tmp2_list = NULL_PTR; + + ck_rv = C_GetSlotList(1, NULL_PTR, &tmp_count); + if (ck_rv != CKR_OK) { + if (handle != NULL) { + handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + handle->lasterr.errcode = ck_rv; + } + return (KMF_ERR_INTERNAL); + } + + if (tmp_count == 0) { + *slot_list = NULL_PTR; + *slot_count = 0; + return (KMF_OK); + } + + /* Allocate initial space for the slot list. */ + if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count * + sizeof (CK_SLOT_ID))) == NULL) + return (KMF_ERR_MEMORY); + + /* Then get the slot list itself. */ + for (;;) { + ck_rv = C_GetSlotList(1, tmp_list, &tmp_count); + if (ck_rv == CKR_OK) { + *slot_list = tmp_list; + *slot_count = tmp_count; + kmf_rv = KMF_OK; + break; + } + + if (ck_rv != CKR_BUFFER_TOO_SMALL) { + free(tmp_list); + if (handle != NULL) { + handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + handle->lasterr.errcode = ck_rv; + } + kmf_rv = KMF_ERR_INTERNAL; + break; + } + + /* + * If the number of slots grew, try again. This + * is to be consistent with pktool in ONNV. + */ + if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list, + tmp_count * sizeof (CK_SLOT_ID))) == NULL) { + free(tmp_list); + kmf_rv = KMF_ERR_MEMORY; + break; + } + tmp_list = tmp2_list; + } + + return (kmf_rv); +} + +/* + * Returns pointer to either null-terminator or next unescaped colon. The + * string to be extracted starts at the beginning and goes until one character + * before this pointer. If NULL is returned, the string itself is NULL. + */ +static char * +find_unescaped_colon(char *str) +{ + char *end; + + if (str == NULL) + return (NULL); + + while ((end = strchr(str, ':')) != NULL) { + if (end != str && *(end-1) != '\\') + return (end); + str = end + 1; /* could point to null-terminator */ + } + if (end == NULL) + end = strchr(str, '\0'); + return (end); +} + +/* + * Compresses away any characters escaped with backslash from given string. + * The string is altered in-place. Example, "ab\:\\e" becomes "ab:\e". + */ +static void +unescape_str(char *str) +{ + boolean_t escaped = B_FALSE; + char *mark; + + if (str == NULL) + return; + + for (mark = str; *str != '\0'; str++) { + if (*str != '\\' || escaped == B_TRUE) { + *mark++ = *str; + escaped = B_FALSE; + } else { + escaped = B_TRUE; + } + } + *mark = '\0'; +} + + +/* + * Given a colon-separated token specifier, this functions splits it into + * its label, manufacturer ID (if any), and serial number (if any). Literal + * colons within the label/manuf/serial can be escaped with a backslash. + * Fields can left blank and trailing colons can be omitted, however leading + * colons are required as placeholders. For example, these are equivalent: + * (a) "lbl", "lbl:", "lbl::" (b) "lbl:man", "lbl:man:" + * but these are not: + * (c) "man", ":man" (d) "ser", "::ser" + * Furthermore, the token label is required always. + * + * The buffer containing the token specifier is altered by replacing the + * colons to null-terminators, and pointers returned are pointers into this + * string. No new memory is allocated. + */ +static int +parse_token_spec(char *token_spec, char **token_name, char **manuf_id, + char **serial_no) +{ + char *mark; + + if (token_spec == NULL || *token_spec == '\0') { + return (-1); + } + + *token_name = NULL; + *manuf_id = NULL; + *serial_no = NULL; + + /* Token label (required) */ + mark = find_unescaped_colon(token_spec); + *token_name = token_spec; + if (*mark != '\0') + *mark++ = '\0'; /* mark points to next field, if any */ + unescape_str(*token_name); + + if (*(*token_name) == '\0') { /* token label is required */ + return (-1); + } + + if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */ + return (0); + token_spec = mark; + + /* Manufacturer identifier (optional) */ + mark = find_unescaped_colon(token_spec); + *manuf_id = token_spec; + if (*mark != '\0') + *mark++ = '\0'; /* mark points to next field, if any */ + unescape_str(*manuf_id); + + if (*mark == '\0' || *(mark+1) == '\0') /* no more fields */ + return (0); + token_spec = mark; + + /* Serial number (optional) */ + mark = find_unescaped_colon(token_spec); + *serial_no = token_spec; + if (*mark != '\0') + *mark++ = '\0'; /* null-terminate, just in case */ + unescape_str(*serial_no); + + return (0); +} + +/* + * Find slots that match a token identifier. Token labels take the + * form of: + * token_name:manufacturer:serial_number + * manufacterer and serial number are optional. If used, the fields + * are delimited by the colon ':' character. + */ +KMF_RETURN +KMF_PK11TokenLookup(KMF_HANDLE_T handle, char *label, CK_SLOT_ID *slot_id) +{ + KMF_RETURN kmf_rv = KMF_OK; + CK_RV rv; + CK_SLOT_ID_PTR slot_list = NULL; + CK_TOKEN_INFO token_info; + CK_ULONG slot_count = 0; + int i; + uint_t len, max_sz; + boolean_t metaslot_status_enabled; + boolean_t metaslot_migrate_enabled; + char *metaslot_slot_info; + char *metaslot_token_info; + char *tmplabel = NULL; + char *token_name = NULL; + char *manuf_id = NULL; + char *serial_no = NULL; + boolean_t tok_match = B_FALSE, + man_match = B_FALSE, + ser_match = B_FALSE; + + if (slot_id == NULL || label == NULL || !strlen(label)) + return (KMF_ERR_BAD_PARAMETER); + + if (handle == NULL) { + rv = C_Initialize(NULL); + if ((rv != CKR_OK) && + (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { + return (KMF_ERR_UNINITIALIZED); + } + } + + /* + * Parse token specifier into token_name, manuf_id, serial_no. + * Token_name is required; manuf_id and serial_no are optional. + */ + tmplabel = strdup(label); + if (tmplabel == NULL) + return (KMF_ERR_MEMORY); + + if (parse_token_spec(tmplabel, &token_name, &manuf_id, + &serial_no) < 0) { + free(tmplabel); + return (KMF_ERR_BAD_PARAMETER); + } + + /* Get a list of all slots with tokens present. */ + kmf_rv = kmf_get_token_slots(handle, &slot_list, &slot_count); + if (kmf_rv != KMF_OK) { + free(tmplabel); + return (kmf_rv); + } + + /* If there are no such slots, the desired token won't be found. */ + if (slot_count == 0) { + free(tmplabel); + return (KMF_ERR_TOKEN_NOT_PRESENT); + } + + /* Search the slot list for the token. */ + for (i = 0; i < slot_count; i++) { + if (C_GetTokenInfo(slot_list[i], &token_info) != CKR_OK) { + continue; + } + + /* See if the token label matches. */ + len = strlen(token_name); + max_sz = sizeof (token_info.label); + if (memcmp_pad_max(&(token_info.label), max_sz, token_name, + len, max_sz) == 0) + tok_match = B_TRUE; + /* + * If manufacturer id was given, see if it actually matches. + * If no manufacturer id was given, assume match is true. + */ + if (manuf_id) { + len = strlen(manuf_id); + max_sz = sizeof ((char *)(token_info.manufacturerID)); + if (memcmp_pad_max(&(token_info.manufacturerID), max_sz, + manuf_id, len, max_sz) == 0) + man_match = B_TRUE; + } else { + man_match = B_TRUE; + } + + /* + * If serial number was given, see if it actually matches. + * If no serial number was given, assume match is true. + */ + if (serial_no) { + len = strlen(serial_no); + max_sz = sizeof ((char *)(token_info.serialNumber)); + if (memcmp_pad_max(&(token_info.serialNumber), max_sz, + serial_no, len, max_sz) == 0) + ser_match = B_TRUE; + } else { + ser_match = B_TRUE; + } + + if (tok_match && man_match && ser_match) + break; /* found it! */ + } + + if (i < slot_count) { + /* found the desired token from the slotlist */ + *slot_id = slot_list[i]; + free(slot_list); + free(tmplabel); + return (KMF_OK); + } + + /* + * If we didn't find the token from the slotlist, check if this token + * is the one currently hidden by the metaslot. If that's case, + * we can just use the metaslot, the slot 0. + */ + kmf_rv = get_metaslot_info(&metaslot_status_enabled, + &metaslot_migrate_enabled, &metaslot_slot_info, + &metaslot_token_info); + if (kmf_rv) { + /* + * Failed to get the metaslot info. This usually means that + * metaslot is disabled from the system. + */ + kmf_rv = KMF_ERR_TOKEN_NOT_PRESENT; + } else { + max_sz = strlen(metaslot_token_info); + if (memcmp_pad_max(metaslot_token_info, max_sz, token_name, len, + max_sz) == 0) { + *slot_id = slot_list[0]; + } else { + kmf_rv = KMF_ERR_TOKEN_NOT_PRESENT; + } + free(metaslot_slot_info); + free(metaslot_token_info); + } + + free(slot_list); + free(tmplabel); + return (kmf_rv); +} + +KMF_RETURN +KMF_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params, + KMF_CREDENTIAL *newpin) +{ + KMF_RETURN rv = KMF_OK; + KMF_PLUGIN *plugin; + + CLEAR_ERROR(handle, rv); + if (rv != KMF_OK) + return (rv); + + if (params == NULL || newpin == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * If setting PKCS#11 token look for the slot. + */ + if (params->kstype == KMF_KEYSTORE_PK11TOKEN) { + rv = KMF_PK11TokenLookup(NULL, params->tokenname, + ¶ms->pkcs11parms.slot); + if (rv != KMF_OK) + return (rv); + } + + plugin = FindPlugin(handle, params->kstype); + if (plugin == NULL) + return (KMF_ERR_PLUGIN_NOTFOUND); + if (plugin->funclist->SetTokenPin == NULL) + return (KMF_ERR_FUNCTION_NOT_FOUND); + + rv = plugin->funclist->SetTokenPin(handle, params, newpin); + + return (rv); +} + +/* + * + * Name: KMF_SelectToken + * + * Description: + * This function enables the user of PKCS#11 plugin to select a + * particular PKCS#11 token. Valid token label are required in order to + * successfully complete this function. + * All subsequent KMF APIs, which specify PKCS#11 keystore as + * the backend, will be performed at the selected token. + * + * Parameters: + * label(input) - pointer to the token label + * + * Returns: + * A KMF_RETURN value indicating success or specifying a particular + * error condition. + * The value KMF_OK indicates success. All other values represent + * an error condition. + * + */ +KMF_RETURN +KMF_SelectToken(KMF_HANDLE_T handle, char *label, + int readonly) +{ + KMF_RETURN kmf_rv = KMF_OK; + CK_RV ck_rv = CKR_OK; + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE hSession; + CK_FLAGS openflags; + + CLEAR_ERROR(handle, kmf_rv); + if (kmf_rv != KMF_OK) + return (kmf_rv); + + if (label == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (!is_pk11_ready()) { + return (KMF_ERR_UNINITIALIZED); + } + + /* Only one token can be active per thread */ + if (handle->pk11handle != NULL) { + return (KMF_ERR_TOKEN_SELECTED); + } + + /* Find the token with matching label */ + kmf_rv = KMF_PK11TokenLookup(handle, label, &slot_id); + if (kmf_rv != KMF_OK) { + return (kmf_rv); + } + + openflags = CKF_SERIAL_SESSION; + if (!readonly) + openflags |= CKF_RW_SESSION; + + /* Open a session then log the user into the token */ + ck_rv = C_OpenSession(slot_id, openflags, NULL, NULL, &hSession); + if (ck_rv != CKR_OK) { + handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + handle->lasterr.errcode = ck_rv; + return (KMF_ERR_INTERNAL); + } + + handle->pk11handle = hSession; + + return (kmf_rv); +} diff --git a/usr/src/lib/libkmf/libkmf/common/policy.c b/usr/src/lib/libkmf/libkmf/common/policy.c new file mode 100644 index 0000000000..5e41f9f42a --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/policy.c @@ -0,0 +1,1460 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <ctype.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <kmfapiP.h> +#include <libxml/tree.h> +#include <libxml/parser.h> + +typedef struct { + char *ekuname; + KMF_OID *oid; +} EKUName2OID; + +static EKUName2OID EKUList[] = { + {"serverAuth", (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth}, + {"clientAuth", (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth}, + {"codeSigning", (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning}, + {"emailProtection", (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection}, + {"ipsecEndSystem", (KMF_OID *)&KMFOID_PKIX_KP_IPSecEndSystem}, + {"ipsecTunnel", (KMF_OID *)&KMFOID_PKIX_KP_IPSecTunnel}, + {"ipsecUser", (KMF_OID *)&KMFOID_PKIX_KP_IPSecUser}, + {"timeStamping", (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping}, + {"OCSPSigning", (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning} +}; + +static int num_ekus = sizeof (EKUList) / sizeof (EKUName2OID); + +static void +addFormatting(xmlNodePtr parent, char *text) +{ + xmlNodePtr snode; + + if (parent == NULL || text == NULL) + return; + + snode = xmlNewText((const xmlChar *)text); + if (snode != NULL) { + xmlAddChild(parent, snode); + } +} + +static void +parseOCSPValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo) +{ + xmlNodePtr n; + char *c; + n = node->children; + while (n != NULL) { + if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_OCSP_BASIC_ELEMENT)) { + + vinfo->ocsp_info.basic.responderURI = + (char *)xmlGetProp(n, + (const xmlChar *)KMF_OCSP_RESPONDER_ATTR); + + vinfo->ocsp_info.basic.proxy = (char *)xmlGetProp(n, + (const xmlChar *)KMF_OCSP_PROXY_ATTR); + + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_OCSP_URI_ATTR); + if (c != NULL && !strcasecmp(c, "true")) { + vinfo->ocsp_info.basic.uri_from_cert = 1; + xmlFree(c); + } + + vinfo->ocsp_info.basic.response_lifetime = + (char *)xmlGetProp(n, + (const xmlChar *)KMF_OCSP_RESPONSE_LIFETIME_ATTR); + + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_OCSP_IGNORE_SIGN_ATTR); + if (c != NULL && !strcasecmp(c, "true")) { + vinfo->ocsp_info.basic.ignore_response_sign = 1; + xmlFree(c); + } + + } else if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT)) { + + vinfo->ocsp_info.resp_cert.name = + (char *)xmlGetProp(n, + (const xmlChar *)KMF_CERT_NAME_ATTR); + vinfo->ocsp_info.resp_cert.serial = + (char *)xmlGetProp(n, + (const xmlChar *)KMF_CERT_SERIAL_ATTR); + vinfo->ocsp_info.has_resp_cert = 1; + } + + n = n->next; + } + +} + +/* + * Parse the "validation-methods" section of the policy. + */ +static void +parseValidation(xmlNodePtr node, KMF_VALIDATION_POLICY *vinfo, + KMF_POLICY_RECORD *policy) +{ + xmlNodePtr n; + char *c; + n = node->children; + while (n != NULL) { + if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_OCSP_ELEMENT)) { + + parseOCSPValidation(n, &policy->validation_info); + policy->revocation |= KMF_REVOCATION_METHOD_OCSP; + + + } else if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_CRL_ELEMENT)) { + + vinfo->crl_info.basefilename = (char *)xmlGetProp(n, + (const xmlChar *)KMF_CRL_BASENAME_ATTR); + + vinfo->crl_info.directory = (char *)xmlGetProp(n, + (const xmlChar *)KMF_CRL_DIRECTORY_ATTR); + + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_CRL_GET_URI_ATTR); + if (c != NULL && !strcasecmp(c, "true")) { + vinfo->crl_info.get_crl_uri = 1; + } else { + vinfo->crl_info.get_crl_uri = 0; + } + xmlFree(c); + + vinfo->crl_info.proxy = (char *)xmlGetProp(n, + (const xmlChar *)KMF_CRL_PROXY_ATTR); + + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_CRL_IGNORE_SIGN_ATTR); + if (c != NULL && !strcasecmp(c, "true")) { + vinfo->crl_info.ignore_crl_sign = 1; + } else { + vinfo->crl_info.ignore_crl_sign = 0; + } + xmlFree(c); + + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_CRL_IGNORE_DATE_ATTR); + if (c != NULL && !strcasecmp(c, "true")) { + vinfo->crl_info.ignore_crl_date = 1; + } else { + vinfo->crl_info.ignore_crl_date = 0; + } + xmlFree(c); + + policy->revocation |= KMF_REVOCATION_METHOD_CRL; + } + + n = n->next; + } +} + +char * +ku2str(uint32_t bitfield) +{ + if (bitfield & KMF_digitalSignature) + return ("digitalSignature"); + + if (bitfield & KMF_nonRepudiation) + return ("nonRepudiation"); + + if (bitfield & KMF_keyEncipherment) + return ("keyEncipherment"); + + if (bitfield & KMF_dataEncipherment) + return ("dataEncipherment"); + + if (bitfield & KMF_keyAgreement) + return ("keyAgreement"); + + if (bitfield & KMF_keyCertSign) + return ("keyCertSign"); + + if (bitfield & KMF_cRLSign) + return ("cRLSign"); + + if (bitfield & KMF_encipherOnly) + return ("encipherOnly"); + + if (bitfield & KMF_decipherOnly) + return ("decipherOnly"); + + return (NULL); +} + +uint16_t +KMF_StringToKeyUsage(char *kustring) +{ + if (kustring == NULL || !strlen(kustring)) + return (0); + if (strcasecmp(kustring, "digitalSignature") == 0) + return (KMF_digitalSignature); + if (strcasecmp(kustring, "nonRepudiation") == 0) + return (KMF_nonRepudiation); + if (strcasecmp(kustring, "keyEncipherment") == 0) + return (KMF_keyEncipherment); + if (strcasecmp(kustring, "dataEncipherment") == 0) + return (KMF_dataEncipherment); + if (strcasecmp(kustring, "keyAgreement") == 0) + return (KMF_keyAgreement); + if (strcasecmp(kustring, "keyCertSign") == 0) + return (KMF_keyCertSign); + if (strcasecmp(kustring, "cRLSign") == 0) + return (KMF_cRLSign); + if (strcasecmp(kustring, "encipherOnly") == 0) + return (KMF_encipherOnly); + if (strcasecmp(kustring, "decipherOnly") == 0) + return (KMF_decipherOnly); + + return (0); +} + +static void +parseKeyUsageSet(xmlNodePtr node, uint32_t *kubits) +{ + xmlNodePtr n; + char *c; + + n = node->children; + while (n != NULL) { + if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_KEY_USAGE_ELEMENT)) { + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_KEY_USAGE_USE_ATTR); + if (c) { + *kubits |= KMF_StringToKeyUsage(c); + xmlFree(c); + } + } + + n = n->next; + } +} + +static KMF_OID * +dup_oid(KMF_OID *oldoid) +{ + KMF_OID *oid; + + oid = malloc(sizeof (KMF_OID)); + if (oid == NULL) + return (NULL); + + oid->Length = oldoid->Length; + oid->Data = malloc(oid->Length); + if (oid->Data == NULL) { + free(oid); + return (NULL); + } + (void) memcpy(oid->Data, oldoid->Data, oid->Length); + + return (oid); +} + +KMF_OID * +kmf_ekuname2oid(char *ekuname) +{ + KMF_OID *oid; + int i; + + if (ekuname == NULL) + return (NULL); + + for (i = 0; i < num_ekus; i++) { + if (strcasecmp(EKUList[i].ekuname, ekuname) == 0) { + oid = dup_oid(EKUList[i].oid); + return (oid); + } + } + + return (NULL); +} + +char * +KMF_OID2EKUString(KMF_OID *oid) +{ + int i; + for (i = 0; i < num_ekus; i++) { + if (oid->Length == EKUList[i].oid->Length && + !memcmp(oid->Data, EKUList[i].oid->Data, oid->Length)) { + return (EKUList[i].ekuname); + } + } + return (NULL); +} + +/* + * Convert a human-readable OID string of the form "1.2.3.4" or + * "1 2 3 4" into a KMF_OID value. + */ +KMF_OID * +kmf_string2oid(char *oidstring) +{ + KMF_OID *oid = NULL; + char *cp, *bp, *startp; + int numbuf; + int onumbuf; + int nbytes, index; + int len; + unsigned char *op; + + if (oidstring == NULL) + return (NULL); + + len = strlen(oidstring); + + bp = oidstring; + cp = bp; + /* Skip over leading space */ + while ((bp < &cp[len]) && isspace(*bp)) + bp++; + + startp = bp; + nbytes = 0; + + /* + * The first two numbers are chewed up by the first octet. + */ + if (sscanf(bp, "%d", &numbuf) != 1) + return (NULL); + while ((bp < &cp[len]) && isdigit(*bp)) + bp++; + while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.')) + bp++; + if (sscanf(bp, "%d", &numbuf) != 1) + return (NULL); + while ((bp < &cp[len]) && isdigit(*bp)) + bp++; + while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.')) + bp++; + nbytes++; + + while (isdigit(*bp)) { + if (sscanf(bp, "%d", &numbuf) != 1) + return (NULL); + while (numbuf) { + nbytes++; + numbuf >>= 7; + } + while ((bp < &cp[len]) && isdigit(*bp)) + bp++; + while ((bp < &cp[len]) && (isspace(*bp) || *bp == '.')) + bp++; + } + + oid = malloc(sizeof (KMF_OID)); + if (oid == NULL) + return (NULL); + + oid->Length = nbytes; + oid->Data = malloc(oid->Length); + if (oid->Data == NULL) { + free(oid); + return (NULL); + } + (void) memset(oid->Data, 0, oid->Length); + + op = oid->Data; + + bp = startp; + (void) sscanf(bp, "%d", &numbuf); + + while (isdigit(*bp)) bp++; + while (isspace(*bp) || *bp == '.') bp++; + + onumbuf = 40 * numbuf; + (void) sscanf(bp, "%d", &numbuf); + onumbuf += numbuf; + *op = (unsigned char) onumbuf; + op++; + + while (isdigit(*bp)) bp++; + while (isspace(*bp) || *bp == '.') bp++; + while (isdigit(*bp)) { + (void) sscanf(bp, "%d", &numbuf); + nbytes = 0; + /* Have to fill in the bytes msb-first */ + onumbuf = numbuf; + while (numbuf) { + nbytes++; + numbuf >>= 7; + } + numbuf = onumbuf; + op += nbytes; + index = -1; + while (numbuf) { + op[index] = (unsigned char)numbuf & 0x7f; + if (index != -1) + op[index] |= 0x80; + index--; + numbuf >>= 7; + } + while (isdigit(*bp)) bp++; + while (isspace(*bp) || *bp == '.') bp++; + } + + return (oid); +} + +static KMF_RETURN +parseExtKeyUsage(xmlNodePtr node, KMF_EKU_POLICY *ekus) +{ + xmlNodePtr n; + char *c; + KMF_RETURN ret = KMF_OK; + boolean_t found = FALSE; + + n = node->children; + while (n != NULL && ret == KMF_OK) { + KMF_OID *newoid = NULL; + + if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_EKU_NAME_ELEMENT)) { + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_EKU_NAME_ATTR); + if (c != NULL) { + newoid = kmf_ekuname2oid(c); + xmlFree(c); + found = TRUE; + } + } else if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_EKU_OID_ELEMENT)) { + c = (char *)xmlGetProp(n, + (const xmlChar *)KMF_EKU_OID_ATTR); + if (c != NULL) { + newoid = kmf_string2oid(c); + xmlFree(c); + found = TRUE; + } + } else { + n = n->next; + if ((n == NULL) && (!found)) + ret = KMF_ERR_POLICY_DB_FORMAT; + continue; + } + + if (newoid != NULL) { + ekus->eku_count++; + ekus->ekulist = realloc(ekus->ekulist, + ekus->eku_count * sizeof (KMF_OID)); + if (ekus->ekulist != NULL) { + ekus->ekulist[ekus->eku_count-1].Length = + newoid->Length; + ekus->ekulist[ekus->eku_count-1].Data = + malloc(newoid->Length); + if (ekus->ekulist[ekus->eku_count-1].Data == + NULL) { + ret = KMF_ERR_MEMORY; + } else { + (void) memcpy( + ekus->ekulist[ekus->eku_count-1]. + Data, + newoid->Data, newoid->Length); + } + } else { + ret = KMF_ERR_MEMORY; + } + KMF_FreeData(newoid); + free(newoid); + } else { + ret = KMF_ERR_POLICY_DB_FORMAT; + } + + n = n->next; + } + + return (ret); +} + +int +parsePolicyElement(xmlNodePtr node, KMF_POLICY_RECORD *policy) +{ + int ret = 0; + xmlNodePtr n = node->xmlChildrenNode; + char *c; + + if (node->type == XML_ELEMENT_NODE) { + if (node->properties != NULL) { + policy->name = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_NAME_ATTR); + + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_OPTIONS_IGNORE_DATE_ATTR); + if (c && !strcasecmp(c, "true")) { + policy->ignore_date = 1; + xmlFree((xmlChar *)c); + } + + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_OPTIONS_IGNORE_UNKNOWN_EKUS); + if (c && !strcasecmp(c, "true")) { + policy->ignore_unknown_ekus = 1; + xmlFree(c); + } + + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_OPTIONS_IGNORE_TRUST_ANCHOR); + if (c && !strcasecmp(c, "true")) { + policy->ignore_trust_anchor = 1; + xmlFree(c); + } + + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_OPTIONS_VALIDITY_ADJUSTTIME); + if (c) { + policy->validity_adjusttime = c; + } else { + policy->validity_adjusttime = NULL; + } + + policy->ta_name = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_TA_NAME_ATTR); + + policy->ta_serial = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_TA_SERIAL_ATTR); + } + + n = node->children; + while (n != NULL) { + if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT)) + parseValidation(n, &policy->validation_info, + policy); + else if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT)) + parseKeyUsageSet(n, &policy->ku_bits); + else if (!xmlStrcmp((const xmlChar *)n->name, + (const xmlChar *)KMF_EKU_ELEMENT)) { + ret = parseExtKeyUsage(n, &policy->eku_set); + if (ret != KMF_OK) + return (ret); + } + + n = n->next; + } + } + + return (ret); +} + +static int +newprop(xmlNodePtr node, char *attrname, char *src) +{ + xmlAttrPtr newattr; + + if (src != NULL && strlen(src)) { + newattr = xmlNewProp(node, (const xmlChar *)attrname, + (xmlChar *)src); + if (newattr == NULL) { + xmlUnlinkNode(node); + xmlFreeNode(node); + return (-1); + } + } + return (0); +} + +/* + * Add CRL policy information to the XML tree. + * Return non-zero on any failure, else 0 for success. + * + * This function is called only when the KMF_REVOCATION_METHOD_CRL flag is on. + */ +static int +AddCRLNodes(xmlNodePtr node, KMF_CRL_POLICY *crlinfo) +{ + xmlNodePtr n; + + addFormatting(node, "\t\t"); + n = xmlNewChild(node, NULL, (const xmlChar *)"crl", NULL); + if (n == NULL) + return (-1); + + if (crlinfo->basefilename && + newprop(n, KMF_CRL_BASENAME_ATTR, crlinfo->basefilename)) + return (-1); + + if (crlinfo->directory && + newprop(n, KMF_CRL_DIRECTORY_ATTR, crlinfo->directory)) + return (-1); + + if (crlinfo->get_crl_uri && + newprop(n, KMF_CRL_GET_URI_ATTR, "TRUE")) { + return (-1); + } + + if (crlinfo->proxy && + newprop(n, KMF_CRL_PROXY_ATTR, crlinfo->proxy)) + return (-1); + + if (crlinfo->ignore_crl_sign && + newprop(n, KMF_CRL_IGNORE_SIGN_ATTR, "TRUE")) { + return (-1); + } + + if (crlinfo->ignore_crl_date && + newprop(n, KMF_CRL_IGNORE_DATE_ATTR, "TRUE")) { + return (-1); + } + + addFormatting(node, "\n"); + return (0); +} + +/* + * Add OCSP information to the policy tree. + * Return non-zero on any failure, else 0 for success. + * + * This function is called only when the KMF_REVOCATION_METHOD_OCSP flag is on. + */ +static int +AddOCSPNodes(xmlNodePtr parent, KMF_OCSP_POLICY *ocsp) +{ + int ret = 0; + xmlNodePtr n_ocsp, n_basic, n_resp; + KMF_OCSP_BASIC_POLICY *basic; + KMF_RESP_CERT_POLICY *resp_cert; + + basic = &(ocsp->basic); + resp_cert = &(ocsp->resp_cert); + + if (basic->responderURI != NULL || basic->uri_from_cert == B_TRUE) { + + addFormatting(parent, "\t\t"); + + /* basic node */ + n_ocsp = xmlNewChild(parent, NULL, + (const xmlChar *)KMF_OCSP_ELEMENT, NULL); + if (n_ocsp == NULL) + return (-1); + addFormatting(n_ocsp, "\n\t\t\t"); + + n_basic = xmlNewChild(n_ocsp, NULL, + (const xmlChar *)KMF_OCSP_BASIC_ELEMENT, NULL); + if (n_basic == NULL) + return (-1); + if (basic->responderURI && newprop(n_basic, + KMF_OCSP_RESPONDER_ATTR, basic->responderURI)) + return (-1); + if (basic->proxy && + newprop(n_basic, KMF_OCSP_PROXY_ATTR, basic->proxy)) + return (-1); + if (basic->uri_from_cert && + newprop(n_basic, KMF_OCSP_URI_ATTR, "TRUE")) + return (-1); + if (basic->response_lifetime && + newprop(n_basic, KMF_OCSP_RESPONSE_LIFETIME_ATTR, + basic->response_lifetime)) + return (-1); + if (basic->ignore_response_sign && + newprop(n_basic, KMF_OCSP_IGNORE_SIGN_ATTR, "TRUE")) + return (-1); + + addFormatting(n_ocsp, "\n\t\t\t"); + + /* responder cert node */ + if (ocsp->has_resp_cert) { + n_resp = xmlNewChild(n_ocsp, NULL, + (const xmlChar *)KMF_OCSP_RESPONDER_CERT_ELEMENT, + NULL); + if (n_resp == NULL) + return (-1); + if (newprop(n_resp, KMF_CERT_NAME_ATTR, + resp_cert->name)) + return (-1); + if (newprop(n_resp, KMF_CERT_SERIAL_ATTR, + resp_cert->serial)) + return (-1); + } + addFormatting(n_ocsp, "\n\t\t"); + } + + addFormatting(parent, "\n"); + return (ret); +} + +/* + * Add validation method information to the policy tree. + * Return non-zero on any failure, else 0 for success. + */ +static int +AddValidationNodes(xmlNodePtr parent, KMF_POLICY_RECORD *policy) +{ + xmlNodePtr mnode; + int ret = 0; + + addFormatting(parent, "\t"); + mnode = xmlNewChild(parent, NULL, + (const xmlChar *)KMF_VALIDATION_METHODS_ELEMENT, NULL); + if (mnode == NULL) + return (-1); + + addFormatting(mnode, "\n"); + + if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) { + ret = AddOCSPNodes(mnode, &(policy->validation_info.ocsp_info)); + if (ret != KMF_OK) + goto end; + } + + if (policy->revocation & KMF_REVOCATION_METHOD_CRL) { + ret = AddCRLNodes(mnode, &(policy->validation_info.crl_info)); + if (ret != KMF_OK) + goto end; + } + + addFormatting(mnode, "\t"); + addFormatting(parent, "\n"); + +end: + if (ret != 0) { + xmlUnlinkNode(mnode); + xmlFreeNode(mnode); + } + return (ret); + +} + +/* + * Add Key Usage information to the policy tree. + * Return non-zero on any failure, else 0 for success. + */ +static KMF_RETURN +AddKeyUsageNodes(xmlNodePtr parent, uint32_t kubits) +{ + int ret = KMF_OK; + int i; + + xmlNodePtr kuset, kunode; + + if (kubits == 0) + return (0); + + addFormatting(parent, "\n\t"); + kuset = xmlNewChild(parent, NULL, + (const xmlChar *)KMF_KEY_USAGE_SET_ELEMENT, NULL); + if (kuset == NULL) + return (KMF_ERR_POLICY_ENGINE); + + for (i = KULOWBIT; i <= KUHIGHBIT && ret == KMF_OK; i++) { + char *s = ku2str((kubits & (1<<i))); + if (s != NULL) { + addFormatting(kuset, "\n\t\t"); + + kunode = xmlNewChild(kuset, NULL, + (const xmlChar *)KMF_KEY_USAGE_ELEMENT, NULL); + if (kunode == NULL) + ret = KMF_ERR_POLICY_ENGINE; + + else if (newprop(kunode, KMF_KEY_USAGE_USE_ATTR, s)) + ret = KMF_ERR_POLICY_ENGINE; + } + } + addFormatting(kuset, "\n\t"); + addFormatting(parent, "\n"); + + if (ret != KMF_OK) { + xmlUnlinkNode(kuset); + xmlFreeNode(kuset); + } + + return (ret); +} + +/* + * Add Extended-Key-Usage information to the policy tree. + * Return non-zero on any failure, else 0 for success. + */ +static KMF_RETURN +AddExtKeyUsageNodes(xmlNodePtr parent, KMF_EKU_POLICY *ekus) +{ + KMF_RETURN ret = KMF_OK; + xmlNodePtr n, kunode; + int i; + + if (ekus != NULL && ekus->eku_count > 0) { + addFormatting(parent, "\n\t"); + n = xmlNewChild(parent, NULL, + (const xmlChar *)KMF_EKU_ELEMENT, NULL); + if (n == NULL) + return (KMF_ERR_POLICY_ENGINE); + + for (i = 0; i < ekus->eku_count; i++) { + char *s = KMF_OID2String(&ekus->ekulist[i]); + if (s != NULL) { + addFormatting(n, "\n\t\t"); + kunode = xmlNewChild(n, NULL, + (const xmlChar *)KMF_EKU_OID_ELEMENT, + NULL); + if (kunode == NULL) + ret = KMF_ERR_POLICY_ENGINE; + + else if (newprop(kunode, KMF_EKU_OID_ATTR, s)) + ret = KMF_ERR_POLICY_ENGINE; + free(s); + } else { + ret = KMF_ERR_POLICY_ENGINE; + } + } + addFormatting(n, "\n\t"); + addFormatting(parent, "\n"); + } + + if (ret != KMF_OK) { + xmlUnlinkNode(n); + xmlFreeNode(n); + } + return (ret); +} + +void +KMF_FreeEKUPolicy(KMF_EKU_POLICY *ekus) +{ + if (ekus->eku_count > 0) { + int i; + for (i = 0; i < ekus->eku_count; i++) { + KMF_FreeData(&ekus->ekulist[i]); + } + free(ekus->ekulist); + } +} + +#define FREE_POLICY_STR(s) if (s != NULL) free(s); + +void +KMF_FreePolicyRecord(KMF_POLICY_RECORD *policy) +{ + if (policy == NULL) + return; + + FREE_POLICY_STR(policy->name) + FREE_POLICY_STR(policy->VAL_OCSP_BASIC.responderURI) + FREE_POLICY_STR(policy->VAL_OCSP_BASIC.proxy) + FREE_POLICY_STR(policy->VAL_OCSP_BASIC.response_lifetime) + FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.name) + FREE_POLICY_STR(policy->VAL_OCSP_RESP_CERT.serial) + FREE_POLICY_STR(policy->validation_info.crl_info.basefilename) + FREE_POLICY_STR(policy->validation_info.crl_info.directory) + FREE_POLICY_STR(policy->validation_info.crl_info.proxy) + FREE_POLICY_STR(policy->validity_adjusttime) + FREE_POLICY_STR(policy->ta_name) + FREE_POLICY_STR(policy->ta_serial) + + KMF_FreeEKUPolicy(&policy->eku_set); + + (void) memset(policy, 0, sizeof (KMF_POLICY_RECORD)); +} + +/* + * KMF_GetPolicy + * + * Find a policy record in the database. + */ +KMF_RETURN +KMF_GetPolicy(char *filename, char *policy_name, KMF_POLICY_RECORD *plc) +{ + KMF_RETURN ret = KMF_OK; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc = NULL; + xmlNodePtr cur, node; + int found = 0; + + if (filename == NULL || policy_name == NULL || plc == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(plc, 0, sizeof (KMF_POLICY_RECORD)); + + /* Create a parser context */ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return (KMF_ERR_POLICY_DB_FORMAT); + + /* Read the policy DB and verify it against the schema. */ + doc = xmlCtxtReadFile(ctxt, filename, NULL, + XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (doc == NULL || ctxt->valid == 0) { + ret = KMF_ERR_POLICY_DB_FORMAT; + goto out; + } + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + ret = KMF_ERR_POLICY_DB_FORMAT; + goto out; + } + + node = cur->xmlChildrenNode; + while (node != NULL && !found) { + char *c; + /* + * Search for the policy that matches the given name. + */ + if (!xmlStrcmp((const xmlChar *)node->name, + (const xmlChar *)KMF_POLICY_ELEMENT)) { + /* Check the name attribute */ + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_NAME_ATTR); + + /* If a match, parse the rest of the data */ + if (c != NULL) { + if (strcmp(c, policy_name) == 0) { + ret = parsePolicyElement(node, plc); + found = (ret == KMF_OK); + } + xmlFree(c); + } + } + node = node->next; + } + + if (!found) { + ret = KMF_ERR_POLICY_NOT_FOUND; + goto out; + } + +out: + if (ctxt != NULL) + xmlFreeParserCtxt(ctxt); + + if (doc != NULL) + xmlFreeDoc(doc); + + return (ret); +} + +/* + * KMF_SetPolicy + * + * Set the policy record in the handle. This searches + * the policy DB for the named policy. If it is not found + * or an error occurred in processing, the existing policy + * is kept and an error code is returned. + */ +KMF_RETURN +KMF_SetPolicy(KMF_HANDLE_T handle, char *policyfile, char *policyname) +{ + KMF_RETURN ret = KMF_OK; + KMF_POLICY_RECORD *newpolicy = NULL; + + CLEAR_ERROR(handle, ret); + if (ret != KMF_OK) + return (ret); + + newpolicy = malloc(sizeof (KMF_POLICY_RECORD)); + if (newpolicy == NULL) + return (KMF_ERR_MEMORY); + (void) memset(newpolicy, 0, sizeof (KMF_POLICY_RECORD)); + + ret = KMF_GetPolicy( + policyfile == NULL ? KMF_DEFAULT_POLICY_FILE : policyfile, + policyname == NULL ? KMF_DEFAULT_POLICY_NAME : policyname, + newpolicy); + if (ret != KMF_OK) + goto out; + + ret = KMF_VerifyPolicy(newpolicy); + if (ret != KMF_OK) + goto out; + + /* release the existing policy data (if any). */ + if (handle->policy != NULL) { + KMF_FreePolicyRecord(handle->policy); + free(handle->policy); + } + + handle->policy = newpolicy; + +out: + /* Cleanup any data allocated before the error occurred */ + if (ret != KMF_OK) { + KMF_FreePolicyRecord(newpolicy); + free(newpolicy); + } + + return (ret); +} + + +static KMF_RETURN +deletePolicyNode(xmlNodePtr node, char *policy_name) +{ + KMF_RETURN ret = KMF_OK; + int found = 0; + xmlNodePtr dnode = NULL; + + while (node != NULL && !found) { + char *c; + /* + * Search for the policy that matches the given name. + */ + if (!xmlStrcmp((const xmlChar *)node->name, + (const xmlChar *)KMF_POLICY_ELEMENT)) { + /* Check the name attribute */ + c = (char *)xmlGetProp(node, + (const xmlChar *)KMF_POLICY_NAME_ATTR); + + /* If a match, parse the rest of the data */ + if (c != NULL) { + if (strcmp(c, policy_name) == 0) { + found = 1; + dnode = node; + } + xmlFree(c); + } + } + if (!found) + node = node->next; + } + + if (found && dnode != NULL) { + /* Unlink the node */ + xmlUnlinkNode(dnode); + + /* Delete it from the document tree */ + xmlFreeNode(dnode); + } else { + ret = KMF_ERR_POLICY_NOT_FOUND; + } + + return (ret); +} + +/* + * update_policyfile + * + * Attempt to do a "safe" file update as follows: + * 1. Lock the original file. + * 2. Create and write to a temporary file + * 3. Replace the original file with the temporary file. + */ +static KMF_RETURN +update_policyfile(xmlDocPtr doc, char *filename) +{ + KMF_RETURN ret = KMF_OK; + FILE *pfile, *tmpfile; + char tmpfilename[MAXPATHLEN]; + char *p; + int prefix_len, tmpfd; + mode_t old_mode; + + /* + * Open and lock the DB file. First try to open an existing file, + * if that fails, open it as if it were new. + */ + if ((pfile = fopen(filename, "r+")) == NULL && errno == ENOENT) + pfile = fopen(filename, "w+"); + + if (pfile == NULL) + return (KMF_ERR_POLICY_DB_FILE); + + if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { + (void) fclose(pfile); + return (KMF_ERR_POLICY_DB_FILE); + } + + /* + * Create a temporary file to hold the new data. + */ + (void) memset(tmpfilename, 0, sizeof (tmpfilename)); + p = (char *)strrchr(filename, '/'); + if (p == NULL) { + /* + * filename contains basename only so we + * create a temp file in current directory. + */ + if (strlcpy(tmpfilename, TMPFILE_TEMPLATE, + sizeof (tmpfilename)) >= sizeof (tmpfilename)) + return (KMF_ERR_INTERNAL); + } else { + /* + * create a temp file in the same directory + * as the policy file. + */ + prefix_len = p - filename; + (void) strncpy(tmpfilename, filename, prefix_len); + (void) strncat(tmpfilename, "/", 1); + (void) strncat(tmpfilename, TMPFILE_TEMPLATE, + sizeof (TMPFILE_TEMPLATE)); + } + + old_mode = umask(077); + tmpfd = mkstemp(tmpfilename); + (void) umask(old_mode); + if (tmpfd == -1) { + return (KMF_ERR_POLICY_DB_FILE); + } + + if ((tmpfile = fdopen(tmpfd, "w")) == NULL) { + (void) close(tmpfd); + (void) unlink(tmpfilename); + (void) fclose(pfile); + return (KMF_ERR_POLICY_DB_FILE); + } + + /* + * Write the new info to the temporary file. + */ + if (xmlDocFormatDump(tmpfile, doc, 1) == -1) { + (void) fclose(pfile); + (void) fclose(tmpfile); + (void) unlink(tmpfilename); + return (KMF_ERR_POLICY_ENGINE); + } + + (void) fclose(pfile); + + if (fchmod(tmpfd, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { + (void) close(tmpfd); + (void) unlink(tmpfilename); + return (KMF_ERR_POLICY_DB_FILE); + } + if (fclose(tmpfile) != 0) + return (KMF_ERR_POLICY_DB_FILE); + + /* + * Replace the original file with the updated tempfile. + */ + if (rename(tmpfilename, filename) == -1) { + ret = KMF_ERR_POLICY_DB_FILE; + } + + if (ret != KMF_OK) { + /* try to remove the tmp file */ + (void) unlink(tmpfilename); + } + + return (ret); +} + +/* + * DeletePolicyFromDB + * + * Find a policy by name and remove it from the policy DB file. + * If the policy is not found, return an error. + */ +KMF_RETURN +KMF_DeletePolicyFromDB(char *policy_name, char *dbfilename) +{ + KMF_RETURN ret; + xmlParserCtxtPtr ctxt = NULL; + xmlDocPtr doc = NULL; + xmlNodePtr cur, node; + + if (policy_name == NULL || dbfilename == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Cannot delete the default policy record from the system + * default policy database (/etc/security/kmfpolicy.xml). + */ + if (strcmp(dbfilename, KMF_DEFAULT_POLICY_FILE) == 0 && + strcmp(policy_name, KMF_DEFAULT_POLICY_NAME) == 0) + return (KMF_ERR_BAD_PARAMETER); + + /* Make sure the policy file exists */ + if (access(dbfilename, R_OK | W_OK)) + return (KMF_ERR_BAD_PARAMETER); + + /* Read the policy DB and verify it against the schema. */ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return (KMF_ERR_POLICY_DB_FORMAT); + + doc = xmlCtxtReadFile(ctxt, dbfilename, NULL, + XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (doc == NULL || ctxt->valid == 0) { + ret = KMF_ERR_POLICY_DB_FORMAT; + goto end; + } + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + xmlFreeDoc(doc); + return (KMF_ERR_POLICY_DB_FORMAT); + } + node = cur->xmlChildrenNode; + + ret = deletePolicyNode(node, policy_name); + + if (ret == KMF_OK) + ret = update_policyfile(doc, dbfilename); + +end: + if (ctxt != NULL) + xmlFreeParserCtxt(ctxt); + + if (doc != NULL) + xmlFreeDoc(doc); + + return (ret); +} + +/* + * Add a new policy node to the Policy DB XML tree. + */ +static KMF_RETURN +addPolicyNode(xmlNodePtr pnode, KMF_POLICY_RECORD *policy) +{ + KMF_RETURN ret = KMF_OK; + + if (pnode != NULL && policy != NULL) { + if (newprop(pnode, KMF_POLICY_NAME_ATTR, policy->name) != 0) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + if (policy->ignore_date) { + if (newprop(pnode, KMF_OPTIONS_IGNORE_DATE_ATTR, + "TRUE")) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + } + + if (policy->ignore_unknown_ekus) { + if (newprop(pnode, KMF_OPTIONS_IGNORE_UNKNOWN_EKUS, + "TRUE")) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + } + + if (policy->ignore_trust_anchor) { + if (newprop(pnode, KMF_OPTIONS_IGNORE_TRUST_ANCHOR, + "TRUE")) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + } + + if (policy->validity_adjusttime) { + if (newprop(pnode, KMF_OPTIONS_VALIDITY_ADJUSTTIME, + policy->validity_adjusttime)) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + } + + if (newprop(pnode, KMF_POLICY_TA_NAME_ATTR, + policy->ta_name) != 0) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + + if (newprop(pnode, KMF_POLICY_TA_SERIAL_ATTR, + policy->ta_serial) != 0) { + ret = KMF_ERR_POLICY_ENGINE; + goto out; + } + + /* Add a text node for readability */ + addFormatting(pnode, "\n"); + + if (ret = AddValidationNodes(pnode, policy)) { + goto out; + } + + if ((ret = AddKeyUsageNodes(pnode, policy->ku_bits))) { + goto out; + } + + if ((ret = AddExtKeyUsageNodes(pnode, &policy->eku_set))) { + goto out; + } + } else { + ret = KMF_ERR_BAD_PARAMETER; + } +out: + if (ret != KMF_OK && pnode != NULL) { + xmlUnlinkNode(pnode); + xmlFreeNode(pnode); + } + + return (ret); +} + + +KMF_RETURN +KMF_VerifyPolicy(KMF_POLICY_RECORD *policy) +{ + KMF_RETURN ret = KMF_OK; + boolean_t has_ta; + + if (policy->name == NULL || !strlen(policy->name)) + return (KMF_ERR_POLICY_NAME); + + /* Check the TA related policy */ + if (policy->ta_name != NULL && policy->ta_serial != NULL) { + has_ta = B_TRUE; + } else if (policy->ta_name == NULL && policy->ta_serial == NULL) { + has_ta = B_FALSE; + } else { + /* + * If the TA cert is set, then both name and serial number + * need to be specified. + */ + return (KMF_ERR_TA_POLICY); + } + + if (has_ta == B_FALSE && policy->ignore_trust_anchor == B_FALSE) + return (KMF_ERR_TA_POLICY); + + if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) { + /* + * For OCSP, either use a fixed responder or use the + * value from the cert, but not both. + */ + if ((policy->VAL_OCSP_BASIC.responderURI == NULL && + policy->VAL_OCSP_BASIC.uri_from_cert == B_FALSE) || + (policy->VAL_OCSP_BASIC.responderURI != NULL && + policy->VAL_OCSP_BASIC.uri_from_cert == B_TRUE)) + return (KMF_ERR_OCSP_POLICY); + + /* + * If the OCSP responder cert is set, then both name and serial + * number need to be specified. + */ + if ((policy->VAL_OCSP_RESP_CERT.name != NULL && + policy->VAL_OCSP_RESP_CERT.serial == NULL) || + (policy->VAL_OCSP_RESP_CERT.name == NULL && + policy->VAL_OCSP_RESP_CERT.serial != NULL)) + return (KMF_ERR_OCSP_POLICY); + } + + return (ret); +} + +/* + * Update the KMF policy file by creating a new XML Policy doc tree + * from the data in the KMF_POLICY_RECORD structure. If "check_policy" + * is true, then we check the policy sanity also. + */ +KMF_RETURN +KMF_AddPolicyToDB(KMF_POLICY_RECORD *policy, char *dbfilename, + boolean_t check_policy) +{ + KMF_RETURN ret = KMF_OK; + xmlDocPtr doc = NULL; + xmlNodePtr root, node; + xmlParserCtxtPtr ctxt = NULL; + + if (policy == NULL || dbfilename == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (check_policy == B_TRUE) { + if (ret = KMF_VerifyPolicy(policy)) + return (ret); + } + + /* If the policyDB exists, load it into memory */ + if (!access(dbfilename, R_OK)) { + + /* Create a parser context */ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return (KMF_ERR_POLICY_DB_FORMAT); + + doc = xmlCtxtReadFile(ctxt, dbfilename, NULL, + XML_PARSE_DTDVALID | XML_PARSE_NOERROR | + XML_PARSE_NOWARNING); + if (doc == NULL || ctxt->valid == 0) { + ret = KMF_ERR_POLICY_DB_FORMAT; + goto out; + } + + root = xmlDocGetRootElement(doc); + if (root == NULL) { + ret = KMF_ERR_POLICY_DB_FORMAT; + goto out; + } + + node = root->xmlChildrenNode; + /* + * If the DB has an existing policy of the + * same name, delete it from the tree. + */ + ret = deletePolicyNode(node, policy->name); + if (ret == KMF_ERR_POLICY_NOT_FOUND) + ret = KMF_OK; + } else { + /* Initialize a new DB tree */ + doc = xmlNewDoc((const xmlChar *)"1.0"); + if (doc == NULL) + return (KMF_ERR_POLICY_ENGINE); + + /* + * Add the DOCTYPE header to the tree so the + * DTD link is embedded + */ + doc->intSubset = xmlCreateIntSubset(doc, + (const xmlChar *)KMF_POLICY_ROOT, + NULL, (const xmlChar *)KMF_POLICY_DTD); + + root = xmlNewDocNode(doc, NULL, + (const xmlChar *)KMF_POLICY_ROOT, NULL); + if (root != NULL) { + xmlDocSetRootElement(doc, root); + } + } + + /* Append the new policy info to the root node. */ + if (root != NULL) { + xmlNodePtr pnode; + + pnode = xmlNewChild(root, NULL, + (const xmlChar *)KMF_POLICY_ELEMENT, NULL); + + ret = addPolicyNode(pnode, policy); + /* If that worked, update the DB file. */ + if (ret == KMF_OK) + ret = update_policyfile(doc, dbfilename); + } else { + ret = KMF_ERR_POLICY_ENGINE; + } + + +out: + if (ctxt != NULL) + xmlFreeParserCtxt(ctxt); + + if (doc != NULL) + xmlFreeDoc(doc); + + return (ret); +} diff --git a/usr/src/lib/libkmf/libkmf/common/rdn_parser.c b/usr/src/lib/libkmf/libkmf/common/rdn_parser.c new file mode 100644 index 0000000000..ae944a7d7a --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/common/rdn_parser.c @@ -0,0 +1,546 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * File: rdn_parser.c + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#include <strings.h> +#include <stdlib.h> +#include <kmfapi.h> +#include <kmfapiP.h> +#include <ber_der.h> +#include <rdn_parser.h> +#include <stdio.h> +#include <values.h> + +/* + * The order here is important. The OIDs are arranged in order of + * significance. The CN is the most specific value, the C (country) + * is less specific, etc. Add to this list with care. + */ +static const struct NameToKind name2kinds[] = { +{ "CN", OID_AVA_COMMON_NAME, (KMF_OID *)&KMFOID_CommonName}, +{ "SN", OID_AVA_SURNAME, (KMF_OID *)&KMFOID_Surname}, +{ "GN", OID_AVA_GIVEN_NAME, (KMF_OID *)&KMFOID_GivenName}, +{ "emailAddress", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress}, +{ "E", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress}, +{ "MAIL", OID_RFC1274_MAIL, (KMF_OID *)&KMFOID_RFC822mailbox}, +{ "STREET", OID_AVA_STREET_ADDRESS, (KMF_OID *)&KMFOID_StreetAddress}, +{ "UID", OID_RFC1274_UID, (KMF_OID *)&KMFOID_userid}, +{ "OU", OID_AVA_ORGANIZATIONAL_UNIT_NAME, + (KMF_OID *)&KMFOID_OrganizationalUnitName}, +{ "O", OID_AVA_ORGANIZATION_NAME, (KMF_OID *)&KMFOID_OrganizationName}, +{ "L", OID_AVA_LOCALITY, (KMF_OID *)&KMFOID_LocalityName}, +{ "ST", OID_AVA_STATE_OR_PROVINCE, + (KMF_OID *)&KMFOID_StateProvinceName}, +{ "C", OID_AVA_COUNTRY_NAME, (KMF_OID *)&KMFOID_CountryName}, +{ "DC", OID_AVA_DC, (KMF_OID *)&KMFOID_domainComponent}, +{ 0, OID_UNKNOWN, NULL} +}; + +static KMF_BOOL +IsPrintable(unsigned char *data, unsigned len) +{ + unsigned char ch, *end; + + end = data + len; + while (data < end) { + ch = *data++; + if (!IS_PRINTABLE(ch)) { + return (B_FALSE); + } + } + return (B_TRUE); +} + +static KMF_BOOL +Is7Bit(unsigned char *data, unsigned len) +{ + unsigned char ch, *end; + + end = data + len; + while (data < end) { + ch = *data++; + if ((ch & 0x80)) { + return (B_FALSE); + } + } + return (B_TRUE); +} + +static void +skipSpace(char **pbp, char *endptr) +{ + char *bp = *pbp; + while (bp < endptr && OPTIONAL_SPACE(*bp)) { + bp++; + } + *pbp = bp; +} + +static KMF_RETURN +scanTag(char **pbp, char *endptr, char *tagBuf, int tagBufSize) +{ + char *bp, *tagBufp; + int taglen; + + if (tagBufSize <= 0) + return (KMF_ERR_INTERNAL); + + /* skip optional leading space */ + skipSpace(pbp, endptr); + if (*pbp == endptr) { + /* nothing left */ + return (KMF_ERR_RDN_PARSER); + } + + /* fill tagBuf */ + taglen = 0; + bp = *pbp; + tagBufp = tagBuf; + while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) { + if (++taglen >= tagBufSize) { + *pbp = bp; + return (KMF_ERR_RDN_PARSER); + } + *tagBufp++ = *bp++; + } + /* null-terminate tagBuf -- guaranteed at least one space left */ + *tagBufp++ = 0; + *pbp = bp; + + /* + * skip trailing spaces till we hit something - should be + * an equal sign + */ + skipSpace(pbp, endptr); + if (*pbp == endptr) { + /* nothing left */ + return (KMF_ERR_RDN_PARSER); + } + if (**pbp != C_EQUAL) { + /* should be an equal sign */ + return (KMF_ERR_RDN_PARSER); + } + /* skip over the equal sign */ + (*pbp)++; + + return (KMF_OK); +} + +static KMF_RETURN +scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize) +{ + char *bp, *valBufp; + int vallen; + boolean_t isQuoted; + + if (valBufSize <= 0) + return (KMF_ERR_INTERNAL); + + /* skip optional leading space */ + skipSpace(pbp, endptr); + if (*pbp == endptr) { + /* nothing left */ + return (KMF_ERR_RDN_PARSER); + } + + bp = *pbp; + + /* quoted? */ + if (*bp == C_DOUBLE_QUOTE) { + isQuoted = B_TRUE; + /* skip over it */ + bp++; + } else { + isQuoted = B_FALSE; + } + + valBufp = valBuf; + vallen = 0; + while (bp < endptr) { + char c = *bp; + if (c == C_BACKSLASH) { + /* escape character */ + bp++; + if (bp >= endptr) { + /* + * escape charater must appear with paired char + */ + *pbp = bp; + return (KMF_ERR_RDN_PARSER); + } + } else if (!isQuoted && SPECIAL_CHAR(c)) { + /* unescaped special and not within quoted value */ + break; + } else if (c == C_DOUBLE_QUOTE) { + /* reached unescaped double quote */ + break; + } + /* append character */ + vallen++; + if (vallen >= valBufSize) { + *pbp = bp; + return (KMF_ERR_RDN_PARSER); + } + *valBufp++ = *bp++; + } + + /* stip trailing spaces from unquoted values */ + if (!isQuoted) { + if (valBufp > valBuf) { + valBufp--; + while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) { + valBufp--; + } + valBufp++; + } + } + + if (isQuoted) { + /* insist that we stopped on a double quote */ + if (*bp != C_DOUBLE_QUOTE) { + *pbp = bp; + return (KMF_ERR_RDN_PARSER); + } + /* skip over the quote and skip optional space */ + bp++; + skipSpace(&bp, endptr); + } + + *pbp = bp; + + if (valBufp == valBuf) { + /* empty value -- not allowed */ + return (KMF_ERR_RDN_PARSER); + } + + /* null-terminate valBuf -- guaranteed at least one space left */ + *valBufp++ = 0; + + return (KMF_OK); +} + +static KMF_RETURN +CreateRDN(KMF_X509_TYPE_VALUE_PAIR *ava, KMF_X509_RDN *newrdn) +{ + /* Each RDN has 1 AttrTypeAndValue */ + (void) memset(newrdn, 0, sizeof (KMF_X509_RDN)); + newrdn->numberOfPairs = 1; + newrdn->AttributeTypeAndValue = ava; + + return (KMF_OK); +} + +static KMF_RETURN +copy_oid(KMF_OID *dst, KMF_OID *src) +{ + KMF_RETURN ret = KMF_OK; + + if (dst == NULL || src == NULL) + return (KMF_ERR_BAD_PARAMETER); + + dst->Data = malloc(src->Length); + if (dst->Data == NULL) + return (KMF_ERR_MEMORY); + + dst->Length = src->Length; + (void) memcpy(dst->Data, src->Data, src->Length); + + return (ret); +} + +static KMF_RETURN +CreateAVA(KMF_OID *oid, int valueType, char *value, + KMF_X509_TYPE_VALUE_PAIR **newava) +{ + int rv = KMF_OK; + KMF_X509_TYPE_VALUE_PAIR *ava = NULL; + + *newava = NULL; + ava = (KMF_X509_TYPE_VALUE_PAIR*) malloc( + sizeof (KMF_X509_TYPE_VALUE_PAIR)); + if (ava == NULL) { + return (KMF_ERR_MEMORY); + } else { + (void) memset(ava, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR)); + ava->valueType = valueType; + ava->value.Data = malloc(strlen(value)); + if (ava->value.Data == NULL) { + free(ava); + return (KMF_ERR_MEMORY); + } + (void) memcpy(ava->value.Data, value, strlen(value)); + ava->value.Length = strlen(value); + + rv = copy_oid(&ava->type, oid); + if (rv != KMF_OK) { + /* Illegal AVA type */ + free(ava->value.Data); + free(ava); + return (rv); + } + } + *newava = ava; + + return (rv); +} + +static KMF_RETURN +ParseRdnAttribute(char **pbp, char *endptr, boolean_t singleAVA, + KMF_X509_TYPE_VALUE_PAIR **a) +{ + KMF_RETURN rv; + const struct NameToKind *n2k; + int vt; + int valLen; + char *bp; + + char tagBuf[32]; + char valBuf[384]; + + rv = scanTag(pbp, endptr, tagBuf, sizeof (tagBuf)); + if (rv != KMF_OK) + return (rv); + rv = scanVal(pbp, endptr, valBuf, sizeof (valBuf)); + if (rv != KMF_OK) + return (rv); + + /* insist that if we haven't finished we've stopped on a separator */ + bp = *pbp; + if (bp < endptr) { + if (singleAVA || (*bp != ',' && *bp != ';')) { + *pbp = bp; + return (KMF_ERR_RDN_ATTR); + } + /* ok, skip over separator */ + bp++; + } + *pbp = bp; + + for (n2k = name2kinds; n2k->name; n2k++) { + if (strcasecmp(n2k->name, tagBuf) == 0) { + valLen = strlen(valBuf); + if (n2k->kind == OID_AVA_COUNTRY_NAME) { + vt = BER_PRINTABLE_STRING; + if (valLen != 2) { + return (KMF_ERR_RDN_ATTR); + } + if (!IsPrintable((unsigned char *) valBuf, 2)) { + return (KMF_ERR_RDN_ATTR); + } + } else if ((n2k->kind == OID_PKCS9_EMAIL_ADDRESS) || + (n2k->kind == OID_RFC1274_MAIL)) { + vt = BER_IA5STRING; + } else { + /* + * Hack -- for rationale see X.520 + * DirectoryString defn + */ + if (IsPrintable((unsigned char *)valBuf, + valLen)) { + vt = BER_PRINTABLE_STRING; + } else if (Is7Bit((unsigned char *)valBuf, + valLen)) { + vt = BER_T61STRING; + } + } + rv = CreateAVA(n2k->OID, + vt, (char *)valBuf, a); + return (rv); + } + } + /* matched no kind -- invalid tag */ + return (KMF_ERR_RDN_ATTR); +} + +static int +rdnavcompare(const void *a, const void *b) +{ + KMF_X509_RDN *r1, *r2; + KMF_X509_TYPE_VALUE_PAIR *av1, *av2; + int i, p1, p2; + const struct NameToKind *n2k; + KMF_OID *oidrec; + + r1 = (KMF_X509_RDN *)a; + r2 = (KMF_X509_RDN *)b; + + av1 = r1->AttributeTypeAndValue; + av2 = r2->AttributeTypeAndValue; + + p1 = p2 = MAXINT; + /* + * The "Name2Kinds" list is ordered by significance. + * Compare the "ranking" of each of the OIDs to determine + * the result. + */ + for (n2k = name2kinds, i = 0; + n2k->name && (p1 == MAXINT || p2 == MAXINT); + n2k++, i++) { + oidrec = n2k->OID; + if (oidrec != NULL) { + if (IsEqualOid(&av1->type, oidrec)) + p1 = i; + if (IsEqualOid(&av2->type, oidrec)) + p2 = i; + } + } + + if (p1 > p2) + return (-1); + else if (p1 < p2) + return (1); + else /* If equal, treat as if it is less than */ + return (1); +} + +KMF_RETURN +ParseDistinguishedName(char *buf, int len, KMF_X509_NAME *name) +{ + KMF_RETURN rv = KMF_OK; + char *bp, *e; + KMF_X509_TYPE_VALUE_PAIR *ava = NULL; + KMF_X509_RDN rdn; + + (void) memset(name, 0, sizeof (KMF_X509_NAME)); + e = buf + len; + bp = buf; + while (bp < e) { + rv = ParseRdnAttribute(&bp, e, B_FALSE, &ava); + if (rv != KMF_OK) goto loser; + rv = CreateRDN(ava, &rdn); + if (rv != KMF_OK) goto loser; + if (AddRDN(name, &rdn) != KMF_OK) goto loser; + skipSpace(&bp, e); + } + + /* + * Canonicalize the DN by sorting the elements + * in little-endian order, as per RFC 1485: + * "The name is presented/input in a little-endian + * order (most significant component last)." + */ + qsort((void *)name->RelativeDistinguishedName, + name->numberOfRDNs, + sizeof (KMF_X509_RDN), + rdnavcompare); + + /* return result */ + return (rv); + +loser: + KMF_FreeDN(name); + return (rv); +} + +static KMF_BOOL +IsEqualData(KMF_DATA *d1, KMF_DATA *d2) +{ + return ((d1->Length == d2->Length) && + !memcmp(d1->Data, d2->Data, d1->Length)); +} + +/* + * Generic routine to compare 2 RDN structures. + * + * Because the ordering of the AV pairs may not be + * the same, we must compare each AV pair individually + * + * Return 0 if equal, 1 if not. + */ +int +KMF_CompareRDNs(KMF_X509_NAME *name1, KMF_X509_NAME *name2) +{ + int i, j; + boolean_t avfound; + KMF_X509_RDN *r1, *r2; + KMF_X509_TYPE_VALUE_PAIR *av1, *av2; + + if (name1 == NULL || name2 == NULL) + return (1); + + if (name1->numberOfRDNs != name2->numberOfRDNs) + return (1); + + for (i = 0; i < name1->numberOfRDNs; i++) { + r1 = (KMF_X509_RDN *)&name1->RelativeDistinguishedName[i]; + av1 = (KMF_X509_TYPE_VALUE_PAIR *)r1->AttributeTypeAndValue; + + avfound = FALSE; + for (j = 0; j < name2->numberOfRDNs && !avfound; j++) { + r2 = (KMF_X509_RDN *) + &name2->RelativeDistinguishedName[j]; + av2 = (KMF_X509_TYPE_VALUE_PAIR *) + r2->AttributeTypeAndValue; + + avfound = (IsEqualOid(&av1->type, &av2->type) && + IsEqualData(&av1->value, &av2->value)); + } + /* + * If the current AV from name1 was not found in name2, + * we are done. + */ + if (!avfound) + return (1); + } + + /* If we got this far, it must be a match */ + return (0); +} diff --git a/usr/src/lib/libkmf/libkmf/i386/Makefile b/usr/src/lib/libkmf/libkmf/i386/Makefile new file mode 100644 index 0000000000..6dd6b42169 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/libkmf/libkmf/sparc/Makefile b/usr/src/lib/libkmf/libkmf/sparc/Makefile new file mode 100644 index 0000000000..6dd6b42169 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/libkmf/libkmf/sparcv9/Makefile b/usr/src/lib/libkmf/libkmf/sparcv9/Makefile new file mode 100644 index 0000000000..dbd1e9ec93 --- /dev/null +++ b/usr/src/lib/libkmf/libkmf/sparcv9/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libkmf/plugins/Makefile b/usr/src/lib/libkmf/plugins/Makefile new file mode 100644 index 0000000000..5b27f7e6da --- /dev/null +++ b/usr/src/lib/libkmf/plugins/Makefile @@ -0,0 +1,48 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# KMF Prototype Makefile +# +include ../../Makefile.lib + +SUBDIRS = kmf_nss kmf_openssl kmf_pkcs11 + +HDRS= +HDRDIR= include + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile new file mode 100644 index 0000000000..5c60729ece --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com new file mode 100644 index 0000000000..30209c69f9 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/Makefile.com @@ -0,0 +1,74 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for KMF Plugins +# + +LIBRARY= kmf_nss.a +VERS= .1 + +OBJECTS= nss_spi.o + +include $(SRC)/lib/Makefile.lib + +MPSDIR= /usr/lib/mps +KMFINC= -I../../../include -I../../../ber_der/inc +NSSINC= -I/usr/include/mps +BERLIB= -lkmf -lkmfberder +BERLIB64= $(BERLIB) + +NSSLIBS= $(BERLIB) -L$(MPSDIR) -R$(MPSDIR) -lnss3 -lnspr4 -lsmime3 -lc +NSSLIBS64= $(BERLIB64) -L$(MPSDIR)/$(MACH64) -R$(MPSDIR)/$(MACH64) -lnss3 -lnspr4 -lsmime3 -lc + +SRCDIR= ../common +INCDIR= ../../include + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT $(KMFINC) $(NSSINC) \ + -I$(SFWDIR)/include -I$(INCDIR) -I/usr/include/libxml2 + +PICS= $(OBJECTS:%=pics/%) + +lint:= NSSLIBS = $(BERLIB) +lint:= NSSLIBS64 = $(BERLIB64) + +LDLIBS32 += $(NSSLIBS) + +LIBS = $(DYNLIB) + +ROOTLIBDIR= $(ROOT)/usr/lib/security +ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64) + + +.KEEP_STATE: + +all: $(LIBS) $(LINTLIB) + +lint: lintcheck + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile new file mode 100644 index 0000000000..aa52c4aefb --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +LDLIBS64 += $(NSSLIBS64) + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers new file mode 100644 index 0000000000..ed84774842 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/mapfile-vers @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + KMF_Plugin_Initialize; + NSS_FindCert; + NSS_FreeKMFCert; + NSS_StoreCert; + NSS_ImportCert; + NSS_ImportCRL; + NSS_DeleteCert; + NSS_DeleteCRL; + NSS_CreateKeypair; + NSS_FindKey; + NSS_EncodePubKeyData; + NSS_SignData; + NSS_DeleteKey; + NSS_FindCRL; + NSS_FindCertInCRL; + NSS_GetErrorString; + NSS_GetPrikeyByCert; + NSS_DecryptData; + NSS_ExportP12; + NSS_StorePrivateKey; + NSS_CreateSymKey; + NSS_GetSymKeyValue; + NSS_SetTokenPin; + + local: + *; +}; diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c new file mode 100644 index 0000000000..b23886aaae --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c @@ -0,0 +1,2508 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * NSS keystore wrapper + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <synch.h> + +#include <kmfapiP.h> +#include <ber_der.h> +#include <oidsalg.h> +/* NSS related headers */ + +#include <mps/nss.h> +#include <mps/cert.h> +#include <mps/certdb.h> +#include <mps/secoid.h> +#include <mps/secder.h> +#include <mps/secerr.h> +#include <mps/cryptohi.h> +#include <mps/keyhi.h> +#include <mps/keythi.h> +#include <mps/pk11func.h> +#include <mps/pk11pqg.h> +#include <mps/pkcs12.h> +#include <mps/p12plcy.h> +#include <mps/prerror.h> + +#define NSS_OK 0 + +mutex_t init_lock = DEFAULTMUTEX; +static int nss_initialized = 0; + +KMF_RETURN +NSS_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *); + +KMF_RETURN +NSS_FindCert(KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs); + +void +NSS_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *); + +KMF_RETURN +NSS_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *params, + KMF_DATA * pcert); + +KMF_RETURN +NSS_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *params); + +KMF_RETURN +NSS_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *params); + +KMF_RETURN +NSS_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +KMF_RETURN +NSS_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +NSS_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +NSS_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *params); + +KMF_RETURN +NSS_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *params); + +KMF_RETURN +NSS_FindCRL(KMF_HANDLE_T, KMF_FINDCRL_PARAMS *params, + char **CRLNameList, int *CRLCount); + +KMF_RETURN +NSS_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +KMF_RETURN +NSS_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *params); + +KMF_RETURN +NSS_GetErrorString(KMF_HANDLE_T, char **); + +KMF_RETURN +NSS_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, boolean_t); + +KMF_RETURN +NSS_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, + KMF_KEY_HANDLE *, KMF_KEY_ALG); + +KMF_RETURN +NSS_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +NSS_ExportP12(KMF_HANDLE_T, + KMF_EXPORTP12_PARAMS *, + int, KMF_X509_DER_CERT *, + int, KMF_KEY_HANDLE *, + char *); + +KMF_RETURN +NSS_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, KMF_RAW_KEY_DATA *); + +KMF_RETURN +NSS_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, KMF_KEY_HANDLE *); + +KMF_RETURN +NSS_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); + +KMF_RETURN +NSS_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *); + +static +KMF_PLUGIN_FUNCLIST nss_plugin_table = +{ + 1, /* Version */ + NSS_ConfigureKeystore, + NSS_FindCert, + NSS_FreeKMFCert, + NSS_StoreCert, + NSS_ImportCert, + NSS_ImportCRL, + NSS_DeleteCert, + NSS_DeleteCRL, + NSS_CreateKeypair, + NSS_FindKey, + NSS_EncodePubKeyData, + NSS_SignData, + NSS_DeleteKey, + NULL /* ListCRL */, + NSS_FindCRL, + NSS_FindCertInCRL, + NSS_GetErrorString, + NSS_GetPrikeyByCert, + NSS_DecryptData, + NSS_ExportP12, + NSS_StorePrivateKey, + NSS_CreateSymKey, + NSS_GetSymKeyValue, + NSS_SetTokenPin, + NULL /* Finalize */ +}; + +/* additions for importing and exporting PKCS 12 files */ +typedef struct p12uContextStr { + char *filename; /* name of file */ + PRFileDesc *file; /* pointer to file */ + PRBool error; /* error occurred? */ + int errorValue; /* which error occurred? */ +} p12uContext; + +#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_NSS; \ + h->lasterr.errcode = c; + +KMF_PLUGIN_FUNCLIST * +KMF_Plugin_Initialize() +{ + SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); + SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); + + return (&nss_plugin_table); +} + +static char * +/*ARGSUSED*/ +nss_getpassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + if (retry) + return (NULL); + if (arg != NULL) + return ((char *)strdup(arg)); + else + return (NULL); +} + +static KMF_RETURN +nss_authenticate(KMF_HANDLE_T handle, + PK11SlotInfo *nss_slot, KMF_CREDENTIAL *cred) +{ + + SECStatus nssrv = SECSuccess; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + /* If a password was given, try to login to the slot */ + if (cred == NULL || cred->cred == NULL || cred->credlen == 0 || + nss_slot == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (PK11_IsLoggedIn(nss_slot, NULL)) { + return (KMF_OK); + } + + PK11_SetPasswordFunc(nss_getpassword); + nssrv = PK11_Authenticate(nss_slot, PR_TRUE, + (void *)cred->cred); + + if (nssrv != SECSuccess) { + SET_ERROR(kmfh, nssrv); + PK11_FreeSlot(nss_slot); + return (KMF_ERR_AUTH_FAILED); + } + + return (KMF_OK); +} + +static SECStatus +Init_NSS_DBs(const char *configdir, + const char *certPrefix, + const char *keyPrefix, + const char *secmodName) +{ + SECStatus rv = NSS_OK; + + (void) mutex_lock(&init_lock); + + /* If another thread already did it, return OK. */ + if (nss_initialized) { + (void) mutex_unlock(&init_lock); + return (SECSuccess); + } + + rv = NSS_Initialize((configdir && strlen(configdir)) ? + configdir : "./", certPrefix, + keyPrefix, secmodName ? secmodName : "secmod.db", + NSS_INIT_COOPERATE); + if (rv != SECSuccess) { + goto end; + } + + nss_initialized++; +end: + (void) mutex_unlock(&init_lock); + return (rv); +} + +/* + * When it is called the first time, it will intialize NSS. Once the NSS + * is initialized, this function returns KMF_KEYSTORE_ALREADY_INITIALIZED + * if it is called again. + */ +KMF_RETURN +NSS_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) mutex_lock(&init_lock); + if (nss_initialized == 0) { + SECStatus err; + + (void) mutex_unlock(&init_lock); + err = Init_NSS_DBs(params->nssconfig.configdir, + params->nssconfig.certPrefix, + params->nssconfig.keyPrefix, + params->nssconfig.secModName); + if (err != SECSuccess) { + SET_ERROR(kmfh, err); + return (KMF_ERR_INTERNAL); + } + } else { + rv = KMF_KEYSTORE_ALREADY_INITIALIZED; + (void) mutex_unlock(&init_lock); + } + + return (rv); +} + + +/* + * This function sets up the slot to be used for other operations. + * This function is basically called by every NSS SPI function. + * For those functions that can only be performed in the internal slot, the + * boolean "internal_slot_only" argument needs to be TRUE. + * A slot pointer will be returned when this function is executed successfully. + */ +static KMF_RETURN +Do_NSS_Init( + void *handle, + KMF_NSS_PARAMS nss_opts, + boolean_t internal_slot_only, + PK11SlotInfo **nss_slot) +{ + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (!nss_initialized) + return (KMF_ERR_PLUGIN_INIT); + + /* + * NSS Is already initialized, but we need to find + * the right slot. + */ + if (nss_opts.slotlabel == NULL || + strcmp(nss_opts.slotlabel, "internal") == 0) { + *nss_slot = PK11_GetInternalKeySlot(); + } else if (internal_slot_only == TRUE) { + return (KMF_ERR_SLOTNAME); + } else { + *nss_slot = PK11_FindSlotByName(nss_opts.slotlabel); + } + + if (*nss_slot == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_SLOTNAME); + } + + /* + * If the token was not yet initialized, return an error. + */ + if (PK11_NeedUserInit(*nss_slot)) { + return (KMF_ERR_UNINITIALIZED_TOKEN); + } + + return (KMF_OK); +} + +static KMF_RETURN +nss2kmf_cert(CERTCertificate *nss_cert, KMF_X509_DER_CERT *kmf_cert) +{ + kmf_cert->kmf_private.keystore_type = KMF_KEYSTORE_NSS; + kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID; + + kmf_cert->certificate.Length = nss_cert->derCert.len; + + if ((kmf_cert->certificate.Data = malloc(nss_cert->derCert.len)) == + NULL) { + kmf_cert->certificate.Length = 0; + return (KMF_ERR_MEMORY); + } + (void) memcpy(kmf_cert->certificate.Data, nss_cert->derCert.data, + nss_cert->derCert.len); + if (nss_cert->nickname != NULL) + kmf_cert->kmf_private.label = + (char *)strdup(nss_cert->nickname); + return (KMF_OK); +} + +static KMF_RETURN +nss_getcert_by_label(KMF_HANDLE *kmfh, + char *name, KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs, KMF_CERT_VALIDITY find_criteria) +{ + KMF_RETURN rv = KMF_OK; + CERTCertificate *nss_cert; + SECCertTimeValidity validity; + + nss_cert = PK11_FindCertFromNickname(name, NULL); + if (nss_cert == NULL) { + *num_certs = 0; + SET_ERROR(kmfh, PORT_GetError()); + *num_certs = 0; + return (KMF_ERR_CERT_NOT_FOUND); + } else { + *num_certs = 1; + } + + switch (find_criteria) { + case KMF_ALL_CERTS: + break; + case KMF_NONEXPIRED_CERTS: + validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(), + PR_FALSE); + if (validity != secCertTimeValid) { + /* this is an invalid cert, reject it */ + *num_certs = 0; + CERT_DestroyCertificate(nss_cert); + return (KMF_OK); + } + break; + case KMF_EXPIRED_CERTS: + validity = CERT_CheckCertValidTimes(nss_cert, PR_Now(), + PR_FALSE); + if (validity == secCertTimeValid) { + /* this is a valid cert, reject it in this case. */ + *num_certs = 0; + CERT_DestroyCertificate(nss_cert); + return (KMF_OK); + } + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + if (kmf_cert != NULL) + rv = nss2kmf_cert(nss_cert, kmf_cert); + + /* We copied the data we need, so cleanup the internal record */ + CERT_DestroyCertificate(nss_cert); + + if (rv != KMF_OK) + *num_certs = 0; + + return (rv); +} + +static KMF_RETURN +nss_find_matching_certs(PK11SlotInfo *slot, + char *issuer, char *subject, KMF_BIGINT *serial, + CERTCertList **certlist, KMF_CERT_VALIDITY find_criteria) +{ + KMF_RETURN rv = KMF_OK; + SECStatus ret; + CERTCertList *list; + CERTCertListNode *node; + KMF_X509_NAME issuerDN, subjectDN; + boolean_t findIssuer = FALSE; + boolean_t findSubject = FALSE; + boolean_t findSerial = FALSE; + + if (issuer != NULL && strlen(issuer)) { + rv = KMF_DNParser(issuer, &issuerDN); + if (rv != KMF_OK) + return (rv); + findIssuer = TRUE; + } + if (subject != NULL && strlen(subject)) { + rv = KMF_DNParser(subject, &subjectDN); + if (rv != KMF_OK) + return (rv); + findSubject = TRUE; + } + if (serial != 0 && serial->val != NULL && serial->len > 0) + findSerial = TRUE; + + list = PK11_ListCertsInSlot(slot); + if (list) { + node = CERT_LIST_HEAD(list); + while (!CERT_LIST_END(node, list)) { + KMF_X509_NAME cmpDN; + KMF_DATA der; + boolean_t match; + CERTCertListNode *freenode; + + if (findIssuer) { + der.Data = node->cert->derIssuer.data; + der.Length = node->cert->derIssuer.len; + rv = DerDecodeName(&der, &cmpDN); + if (rv == KMF_OK) { + match = !KMF_CompareRDNs(&issuerDN, + &cmpDN); + KMF_FreeDN(&cmpDN); + if (!match) + goto delete_and_cont; + } else { + goto delete_and_cont; + } + } + if (findSubject) { + der.Data = node->cert->derSubject.data; + der.Length = node->cert->derSubject.len; + rv = DerDecodeName(&der, &cmpDN); + if (rv == KMF_OK) { + match = !KMF_CompareRDNs(&subjectDN, + &cmpDN); + KMF_FreeDN(&cmpDN); + if (!match) + goto delete_and_cont; + } else { + goto delete_and_cont; + } + } + if (findSerial) { + SECItem *sernum; + + sernum = &node->cert->serialNumber; + + if (serial->len != sernum->len) + goto delete_and_cont; + + if (memcmp(sernum->data, serial->val, + serial->len)) + goto delete_and_cont; + } + + /* select the certs using find criteria */ + switch (find_criteria) { + case KMF_ALL_CERTS: + break; + case KMF_NONEXPIRED_CERTS: + ret = CERT_CertTimesValid(node->cert); + if (ret == SECFailure) { + /* this is an invalid cert */ + goto skip; + } + break; + + case KMF_EXPIRED_CERTS: + ret = CERT_CertTimesValid(node->cert); + if (ret != SECFailure) { + /* this is a valid cert */ + goto skip; + } + break; + } +skip: + node = CERT_LIST_NEXT(node); + continue; +delete_and_cont: + freenode = node; + node = CERT_LIST_NEXT(node); + CERT_RemoveCertListNode(freenode); + } + } + + if (rv == KMF_OK && certlist != NULL) { + *certlist = list; + } else { + CERT_DestroyCertList(list); + } + return (rv); +} + +static KMF_RETURN +convertCertList(void *kmfhandle, + CERTCertList *nsscerts, KMF_X509_DER_CERT *kmfcerts, + uint32_t *numcerts) +{ + KMF_RETURN rv = KMF_OK; + CERTCertListNode *node; + + *numcerts = 0; + + for (node = CERT_LIST_HEAD(nsscerts); + !CERT_LIST_END(node, nsscerts) && rv == KMF_OK; + node = CERT_LIST_NEXT(node), (*numcerts)++) { + if (kmfcerts != NULL) + rv = nss2kmf_cert(node->cert, &kmfcerts[*numcerts]); + } + + /* + * If we failed, delete any certs allocated so far. + */ + if (rv != KMF_OK) { + int i; + for (i = 0; i < *numcerts; i++) + KMF_FreeKMFCert(kmfhandle, &kmfcerts[i]); + } + return (rv); +} + +KMF_RETURN +NSS_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmfcerts, + uint32_t *num_certs) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTCertList *certlist = NULL; + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + *num_certs = 0; + if (params->certLabel) { + rv = nss_getcert_by_label(kmfh, + params->certLabel, + kmfcerts, num_certs, params->find_cert_validity); + } else { + rv = nss_find_matching_certs(nss_slot, + params->issuer, params->subject, params->serial, + &certlist, params->find_cert_validity); + + if (rv == KMF_OK && certlist != NULL) { + rv = convertCertList(handle, + certlist, kmfcerts, num_certs); + CERT_DestroyCertList(certlist); + } + } + + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (rv == KMF_OK && *num_certs == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + + return (rv); +} + +void +/*ARGSUSED*/ +NSS_FreeKMFCert(KMF_HANDLE_T handle, + KMF_X509_DER_CERT *kmf_cert) +{ + if (kmf_cert != NULL) { + if (kmf_cert->certificate.Data != NULL) { + free(kmf_cert->certificate.Data); + kmf_cert->certificate.Data = NULL; + kmf_cert->certificate.Length = 0; + } + if (kmf_cert->kmf_private.label != NULL) { + free(kmf_cert->kmf_private.label); + kmf_cert->kmf_private.label = NULL; + } + } +} + +KMF_RETURN +NSS_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params, + KMF_DATA *pcert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECStatus nss_rv; + CERTCertificate *nss_cert = NULL; + CERTCertTrust *nss_trust = NULL; + PK11SlotInfo *nss_slot = NULL; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + if (pcert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* NSS only support DER format */ + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (ret != KMF_OK) { + return (ret); + } + + nss_cert = CERT_DecodeCertFromPackage((char *)pcert->Data, + pcert->Length); + if (nss_cert == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + nss_rv = PK11_ImportCert(nss_slot, nss_cert, CK_INVALID_HANDLE, + params->certLabel, 0); + if (nss_rv) { + SET_ERROR(kmfh, nss_rv); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto out; + } + + if (params->ks_opt_u.nss_opts.trustflag != NULL && + strlen(params->ks_opt_u.nss_opts.trustflag)) { + nss_trust = (CERTCertTrust *) malloc(sizeof (CERTCertTrust)); + if (nss_trust == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + nss_rv = CERT_DecodeTrustString(nss_trust, + params->ks_opt_u.nss_opts.trustflag); + if (nss_rv) { + SET_ERROR(kmfh, nss_rv); + ret = KMF_ERR_BAD_PARAMETER; + goto out; + } + + nss_rv = CERT_ChangeCertTrust(certHandle, nss_cert, nss_trust); + if (nss_rv) { + SET_ERROR(kmfh, nss_rv); + ret = KMF_ERR_BAD_PARAMETER; + } + } + +out: + if (nss_trust != NULL) { + free(nss_trust); + } + + if (nss_cert != NULL) { + CERT_DestroyCertificate(nss_cert); + } + + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + return (ret); +} + + +KMF_RETURN +NSS_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_STORECERT_PARAMS scparams; + KMF_DATA cert = {NULL, 0}; + KMF_DATA cert_der = {NULL, 0}; + KMF_DATA *cptr = NULL; + KMF_ENCODE_FORMAT format; + + if (params == NULL || params->certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * Check if the input cert file is a valid certificate and + * auto-detect the file format of it. + */ + ret = KMF_IsCertFile(handle, params->certfile, &format); + if (ret != KMF_OK) + return (ret); + + ret = KMF_ReadInputFile(handle, params->certfile, &cert); + if (ret != KMF_OK) { + return (ret); + } + + /* + * If the imported cert is in PEM format, convert it to + * DER format in order to store it in NSS token. + */ + if (format == KMF_FORMAT_PEM) { + int derlen; + ret = KMF_Pem2Der(cert.Data, cert.Length, + &cert_der.Data, &derlen); + if (ret != KMF_OK) { + goto cleanup; + } + cert_der.Length = (size_t)derlen; + cptr = &cert_der; + } else { + cptr = &cert; + } + + (void) memset(&scparams, 0, sizeof (scparams)); + scparams.kstype = params->kstype; + scparams.certLabel = params->certLabel; + scparams.nssparms = params->nssparms; + + ret = NSS_StoreCert(handle, &scparams, cptr); + + if (format == KMF_FORMAT_PEM) { + KMF_FreeData(&cert_der); + } + +cleanup: + KMF_FreeData(&cert); + + return (ret); +} + +KMF_RETURN +NSS_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + int nssrv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CERTCertificate *cert = NULL; + PK11SlotInfo *nss_slot = NULL; + + /* check params */ + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, + FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + if (params->certLabel) { + cert = PK11_FindCertFromNickname(params->certLabel, NULL); + if (cert == NULL) { + return (KMF_ERR_CERT_NOT_FOUND); + } + + switch (params->find_cert_validity) { + case KMF_ALL_CERTS: + break; + case KMF_NONEXPIRED_CERTS: + nssrv = CERT_CertTimesValid(cert); + if (nssrv == SECFailure) { + /* this is an invalid cert - skip it */ + goto out; + } + break; + case KMF_EXPIRED_CERTS: + nssrv = CERT_CertTimesValid(cert); + if (nssrv != SECFailure) { + /* this is a valid cert - skip it */ + goto out; + } + break; + } + /* delete it from database */ + nssrv = SEC_DeletePermCertificate(cert); + if (nssrv) { + SET_ERROR(kmfh, nssrv); + rv = KMF_ERR_INTERNAL; + } + } else { + CERTCertListNode *node; + CERTCertList *certlist = NULL; + + rv = nss_find_matching_certs(nss_slot, + params->issuer, params->subject, params->serial, + &certlist, params->find_cert_validity); + + for (node = CERT_LIST_HEAD(certlist); + !CERT_LIST_END(node, certlist) && rv == KMF_OK; + node = CERT_LIST_NEXT(node)) { + + nssrv = SEC_DeletePermCertificate(node->cert); + if (nssrv) { + SET_ERROR(kmfh, nssrv); + rv = KMF_ERR_INTERNAL; + } + } + + if (rv == KMF_OK && certlist != NULL) { + CERT_DestroyCertList(certlist); + } else if (rv == KMF_OK && certlist == NULL) { + rv = KMF_ERR_CERT_NOT_FOUND; + } + } +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + + return (rv); +} + +static void +InitRandom(char *filename) +{ + char buf[2048]; + int fd; + PRInt32 count; + + fd = open(filename, O_RDONLY); + if (!fd) + return; + + count = read(fd, buf, sizeof (buf)); + if (count > 0) { + PK11_RandomUpdate(buf, count); + } + + (void) close(fd); +} + +KMF_RETURN +NSS_CreateKeypair(KMF_HANDLE_T handle, + KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privkey, + KMF_KEY_HANDLE *pubkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11RSAGenParams rsaparams; + void *nssparams; + CK_MECHANISM_TYPE mechanism; + ulong_t publicExponent = 0x010001; + PK11SlotInfo *nss_slot = NULL; + SECKEYPrivateKey *NSSprivkey = NULL; + SECKEYPublicKey *NSSpubkey = NULL; + PQGParams *pqgParams = NULL; + + + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + /* Get some random bits */ + InitRandom("/dev/urandom"); + if (params->keytype == KMF_RSA) { + rsaparams.keySizeInBits = params->keylength; + /* + * NSS only allows for a 4 byte exponent. + * Ignore the exponent parameter if it is too big. + */ + if (params->rsa_exponent.len > 0 && + params->rsa_exponent.len <= sizeof (publicExponent) && + params->rsa_exponent.val != NULL) { + (void) memcpy(&publicExponent, + params->rsa_exponent.val, + params->rsa_exponent.len); + } + rsaparams.pe = publicExponent; + mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + nssparams = &rsaparams; + } else if (params->keytype == KMF_DSA) { + PQGVerify *pqgVerify = NULL; + int ks; + SECStatus nssrv, passed; + + mechanism = CKM_DSA_KEY_PAIR_GEN; + + ks = PQG_PBITS_TO_INDEX(params->keylength); + nssrv = PK11_PQG_ParamGen(ks, &pqgParams, &pqgVerify); + if (nssrv != SECSuccess) { + SET_ERROR(kmfh, rv); + PK11_PQG_DestroyVerify(pqgVerify); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + + nssrv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed); + if (nssrv != SECSuccess || passed != SECSuccess) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_KEYGEN_FAILED; + } + + PK11_PQG_DestroyVerify(pqgVerify); + + if (rv != KMF_OK) { + SET_ERROR(kmfh, PORT_GetError()); + goto cleanup; + } + + nssparams = pqgParams; + } else { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + NSSprivkey = PK11_GenerateKeyPair(nss_slot, + mechanism, nssparams, &NSSpubkey, + PR_TRUE, /* isPermanent */ + PR_TRUE, /* isSensitive */ + (void *)params->cred.cred); + + if (NSSprivkey == NULL || NSSpubkey == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_KEYGEN_FAILED; + } else { + if (params->keylabel != NULL && + strlen(params->keylabel)) { + (void) PK11_SetPrivateKeyNickname(NSSprivkey, + params->keylabel); + (void) PK11_SetPublicKeyNickname(NSSpubkey, + params->keylabel); + } + /* Now, convert it to a KMF_KEY object for the framework */ + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_NSS; + privkey->keyalg = params->keytype; + privkey->keyclass = KMF_ASYM_PRI; + privkey->keylabel = + PK11_GetPrivateKeyNickname(NSSprivkey); + privkey->keyp = (void *)NSSprivkey; + } + if (pubkey != NULL) { + pubkey->kstype = KMF_KEYSTORE_NSS; + pubkey->keyalg = params->keytype; + pubkey->keyp = (void *)NSSpubkey; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keylabel = + PK11_GetPublicKeyNickname(NSSpubkey); + } + rv = KMF_OK; + } +cleanup: + if (rv != KMF_OK) { + if (NSSpubkey) + PK11_DeleteTokenPublicKey(NSSpubkey); + if (NSSprivkey) + PK11_DeleteTokenPrivateKey(NSSprivkey, PR_TRUE); + + privkey->keyp = NULL; + pubkey->keyp = NULL; + } + + if (pqgParams != NULL) + PK11_PQG_DestroyParams(pqgParams); + + + if (nss_slot != NULL) + PK11_FreeSlot(nss_slot); + + return (rv); +} + +KMF_RETURN +NSS_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *tobesigned, + KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + KMF_ALGORITHM_INDEX AlgId; + SECOidTag signAlgTag; + SECKEYPrivateKey *NSSprivkey = NULL; + SECStatus rv; + SECItem signed_data; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + signed_data.data = 0; + if (key == NULL || AlgOID == NULL || + tobesigned == NULL || output == NULL || + tobesigned->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the OID to a NSS algorithm */ + AlgId = X509_AlgorithmOidToAlgId(AlgOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + NSSprivkey = (SECKEYPrivateKey *)key->keyp; + + if (AlgId == KMF_ALGID_MD5WithRSA) + signAlgTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + else if (AlgId == KMF_ALGID_MD2WithRSA) + signAlgTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; + else if (AlgId == KMF_ALGID_SHA1WithRSA) + signAlgTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + else if (AlgId == KMF_ALGID_SHA1WithDSA) + signAlgTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + else + return (KMF_ERR_BAD_PARAMETER); + + rv = SEC_SignData(&signed_data, tobesigned->Data, + tobesigned->Length, NSSprivkey, signAlgTag); + + if (rv != 0) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + if (signed_data.len <= output->Length) { + (void) memcpy(output->Data, signed_data.data, signed_data.len); + output->Length = signed_data.len; + } else { + output->Length = 0; + ret = KMF_ERR_BAD_PARAMETER; + } + free(signed_data.data); + + return (ret); +} + +KMF_RETURN +NSS_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp, + KMF_DATA *encoded) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECItem *rvitem; + CERTSubjectPublicKeyInfo *spki = NULL; + + if (keyp == NULL || encoded == NULL || keyp->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + spki = SECKEY_CreateSubjectPublicKeyInfo(keyp->keyp); + if (spki == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_MEMORY); + } + + rvitem = SEC_ASN1EncodeItem(NULL, NULL, spki, + CERT_SubjectPublicKeyInfoTemplate); + + if (rvitem != NULL) { + encoded->Data = malloc(rvitem->len); + if (encoded->Data == NULL) { + ret = KMF_ERR_MEMORY; + } else { + (void) memcpy(encoded->Data, rvitem->data, rvitem->len); + encoded->Length = rvitem->len; + } + SECITEM_FreeItem(rvitem, TRUE); + } else { + SET_ERROR(kmfh, PORT_GetError()); + encoded->Data = NULL; + encoded->Length = 0; + ret = KMF_ERR_ENCODING; + } + SECKEY_DestroySubjectPublicKeyInfo(spki); + + return (ret); +} + +KMF_RETURN +NSS_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key, boolean_t delete_token) +{ + KMF_RETURN rv = KMF_OK; + PK11SlotInfo *nss_slot = NULL; + + /* + * "delete_token" means to clear it from the token storage as well + * as from memory. + */ + if (key == NULL || key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (delete_token) { + SECStatus nssrv = SECSuccess; + if (key->keyclass != KMF_ASYM_PUB && + key->keyclass != KMF_ASYM_PRI && + key->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + if (key->keyclass == KMF_ASYM_PUB) { + nssrv = PK11_DeleteTokenPublicKey( + (SECKEYPublicKey *)key->keyp); + } else if (key->keyclass == KMF_ASYM_PRI) { + nssrv = PK11_DeleteTokenPrivateKey( + (SECKEYPrivateKey *)key->keyp, PR_TRUE); + } else if (key->keyclass == KMF_SYMMETRIC) { + nssrv = PK11_DeleteTokenSymKey( + (PK11SymKey *) key->keyp); + if (nssrv == SECSuccess) + PK11_FreeSymKey( + (PK11SymKey *) key->keyp); + } + if (nssrv != SECSuccess) { + SET_ERROR(handle, PORT_GetError()); + rv = KMF_ERR_INTERNAL; + } + } else { + if (key->keyclass == KMF_ASYM_PUB) { + SECKEY_DestroyPublicKey((SECKEYPublicKey *)key->keyp); + } else if (key->keyclass == KMF_ASYM_PRI) { + SECKEY_DestroyPrivateKey((SECKEYPrivateKey *)key->keyp); + } else if (key->keyclass == KMF_SYMMETRIC) { + PK11_FreeSymKey((PK11SymKey *) key->keyp); + } else { + return (KMF_ERR_BAD_KEY_CLASS); + } + } + key->keyp = NULL; + + return (rv); +} + +KMF_RETURN +NSS_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTSignedCrl *nss_crl = NULL; + KMF_ENCODE_FORMAT format; + int importOptions; + SECItem crlDER; + KMF_DATA crl1; + KMF_DATA crl2; + + if (params == NULL || params->ks_opt_u.nss_opts.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * Check if the input CRL file is a valid CRL file and auto-detect + * the encoded format of the file. + */ + ret = KMF_IsCRLFile(handle, params->ks_opt_u.nss_opts.crlfile, + &format); + if (ret != KMF_OK) + return (ret); + + ret = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, &nss_slot); + if (ret != KMF_OK) { + return (ret); + } + + /* set importOptions */ + if (params->ks_opt_u.nss_opts.crl_check == B_FALSE) { + importOptions = CRL_IMPORT_DEFAULT_OPTIONS | + CRL_IMPORT_BYPASS_CHECKS; + } else { + importOptions = CRL_IMPORT_DEFAULT_OPTIONS; + } + + + /* Read in the CRL file */ + crl1.Data = NULL; + crl2.Data = NULL; + ret = KMF_ReadInputFile(handle, params->ks_opt_u.nss_opts.crlfile, + &crl1); + if (ret != KMF_OK) { + return (ret); + } + + /* If the input CRL is in PEM format, convert it to DER first. */ + if (format == KMF_FORMAT_PEM) { + int len; + ret = KMF_Pem2Der(crl1.Data, crl1.Length, + &crl2.Data, &len); + if (ret != KMF_OK) { + goto out; + } + crl2.Length = (size_t)len; + } + + crlDER.data = format == KMF_FORMAT_ASN1 ? crl1.Data : crl2.Data; + crlDER.len = format == KMF_FORMAT_ASN1 ? crl1.Length : crl2.Length; + + nss_crl = PK11_ImportCRL(nss_slot, &crlDER, NULL, SEC_CRL_TYPE, + NULL, importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS); + + if (nss_crl == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_BAD_CRLFILE; + goto out; + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (crl1.Data != NULL) { + free(crl1.Data); + } + + if (crl2.Data != NULL) { + free(crl2.Data); + } + + if (nss_crl != NULL) { + SEC_DestroyCrl(nss_crl); + } + + return (ret); +} + +KMF_RETURN +NSS_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CERTSignedCrl *crl = NULL; + CERTCertificate *cert = NULL; + PK11SlotInfo *nss_slot = NULL; + CERTCrlHeadNode *crlList = NULL; + CERTCrlNode *crlNode = NULL; + PRArenaPool *arena = NULL; + CERTName *name = NULL; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + /* check params */ + if (params == NULL || + (params->ks_opt_u.nss_opts.crl_issuerName == NULL && + params->ks_opt_u.nss_opts.crl_subjName == NULL) || + (params->ks_opt_u.nss_opts.crl_issuerName != NULL && + params->ks_opt_u.nss_opts.crl_subjName != NULL)) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, + &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + /* Find the CRL based on the deletion criteria. */ + if (params->ks_opt_u.nss_opts.crl_issuerName != NULL) { + /* + * If the deletion is based on the issuer's certificate + * nickname, we will get the issuer's cert first, then + * get the CRL from the cert. + */ + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, + params->ks_opt_u.nss_opts.crl_issuerName); + if (!cert) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CERT_NOT_FOUND; + goto out; + } + + crl = SEC_FindCrlByName(certHandle, &cert->derSubject, + SEC_CRL_TYPE); + if (crl == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + } else { + /* + * If the deletion is based on the CRL's subject name, we will + * get all the CRLs from the internal database and search + * for the CRL with the same subject name. + */ + boolean_t found = B_FALSE; + int nssrv; + + nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE); + if (nssrv) { + SET_ERROR(kmfh, nssrv); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + + if (crlList == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + + /* Allocate space for name */ + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (arena == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + + name = PORT_ArenaZAlloc(arena, sizeof (*name)); + if (name == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + name->arena = arena; + + crlNode = crlList->first; + while (crlNode && !found) { + char *asciiname = NULL; + SECItem* issuer; + + name = &crlNode->crl->crl.name; + if (!name) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + + asciiname = CERT_NameToAscii(name); + if (asciiname == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + + if (strcmp(params->ks_opt_u.nss_opts.crl_subjName, + asciiname) == 0) { + found = B_TRUE; + issuer = &crlNode->crl->crl.derName; + crl = SEC_FindCrlByName(certHandle, issuer, + SEC_CRL_TYPE); + if (crl == NULL) { + /* We found a cert but no CRL */ + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + } + } + PORT_Free(asciiname); + crlNode = crlNode->next; + } + + if (rv) { + goto out; + } + } + + if (crl) { + (void) SEC_DeletePermCRL(crl); + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (crlList != NULL) { + PORT_FreeArena(crlList->arena, PR_FALSE); + } + + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + + if (crl != NULL) { + SEC_DestroyCrl(crl); + } + + return (rv); +} + + +KMF_RETURN +NSS_FindCRL(KMF_HANDLE_T handle, KMF_FINDCRL_PARAMS *params, + char **CRLNameList, int *CRLCount) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTCrlHeadNode *crlList = NULL; + CERTCrlNode *crlNode = NULL; + PRArenaPool *arena = NULL; + CERTName *name = NULL; + SECStatus nssrv; + char *asciiname = NULL; + int crl_num; + int i; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + if (CRLCount == NULL || params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + *CRLCount = 0; + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + /* Look up Crls */ + nssrv = SEC_LookupCrls(certHandle, &crlList, SEC_CRL_TYPE); + if (nssrv) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + } + + /* Allocate space for name first */ + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (arena == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + + name = PORT_ArenaZAlloc(arena, sizeof (*name)); + if (name == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + name->arena = arena; + + /* + * Loop thru the crlList and create a crl list with CRL's subject name. + */ + crlNode = crlList->first; + crl_num = 0; + while (crlNode) { + char *subj_name; + + /* Get the CRL subject name */ + name = &crlNode->crl->crl.name; + if (!name) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + + + if (CRLNameList != NULL) { + asciiname = CERT_NameToAscii(name); + if (asciiname == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + break; + } + subj_name = strdup(asciiname); + PORT_Free(asciiname); + if (subj_name == NULL) { + rv = KMF_ERR_MEMORY; + break; + } + CRLNameList[crl_num] = subj_name; + } + + crl_num++; + crlNode = crlNode->next; + } + + if (rv == KMF_OK) { + /* success */ + *CRLCount = crl_num; + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (crlList != NULL) { + PORT_FreeArena(crlList->arena, PR_FALSE); + } + + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + + /* If failed, free memory allocated for the returning rlist */ + if (rv && (CRLNameList != NULL)) { + for (i = 0; i < crl_num; i++) { + free(CRLNameList[i]); + } + } + + return (rv); +} + + +KMF_RETURN +NSS_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + CERTCertificate *cert = NULL; + CERTSignedCrl *crl = NULL; + CERTCrlEntry *entry; + boolean_t match = B_FALSE; + int i; + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + + /* check params */ + if (params == NULL || params->certLabel == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, TRUE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, + params->certLabel); + if (!cert) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CERT_NOT_FOUND; + goto out; + } + + /* Find the CRL with the same issuer as the given certificate. */ + crl = SEC_FindCrlByName(certHandle, &cert->derIssuer, SEC_CRL_TYPE); + if (crl == NULL) { + /* + * Could not find the CRL issued by the same issuer. This + * usually means that the CRL is not installed in the DB. + */ + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_CRL_NOT_FOUND; + goto out; + + } + + /* Check if the certificate's serialNumber is revoked in the CRL */ + i = 0; + while ((entry = (crl->crl).entries[i++]) != NULL) { + if (SECITEM_CompareItem(&(cert->serialNumber), + &(entry->serialNumber)) == SECEqual) { + match = B_TRUE; + break; + } + } + + if (!match) { + rv = KMF_ERR_NOT_REVOKED; + } + +out: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + + if (crl != NULL) { + SEC_DestroyCrl(crl); + } + + return (rv); +} + +KMF_RETURN +NSS_GetErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *str; + + /* Get the error string in the default language */ + str = (char *)PR_ErrorToName((PRErrorCode)kmfh->lasterr.errcode); + + if (str != NULL) { + *msgstr = (char *)strdup(str); + if ((*msgstr) == NULL) + ret = KMF_ERR_MEMORY; + } else { + *msgstr = NULL; + } + + return (ret); +} + +KMF_RETURN +NSS_GetPrikeyByCert(KMF_HANDLE_T handle, KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key, + KMF_KEY_ALG keytype) +{ + CERTCertificate *nss_cert = NULL; + SECKEYPrivateKey* privkey = NULL; + PK11SlotInfo *nss_slot = NULL; + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + rv = Do_NSS_Init(handle, + params->nssparms, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + nss_cert = CERT_DecodeCertFromPackage((char *)SignerCertData->Data, + SignerCertData->Length); + + if (nss_cert == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_BAD_CERT_FORMAT); + } + + privkey = PK11_FindPrivateKeyFromCert(nss_slot, nss_cert, NULL); + if (privkey == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + return (KMF_ERR_KEY_NOT_FOUND); + } + + key->kstype = KMF_KEYSTORE_NSS; + key->keyclass = KMF_ASYM_PRI; + key->keyalg = keytype; + key->keyp = (void *)privkey; + key->keylabel = PK11_GetPrivateKeyNickname(privkey); + + CERT_DestroyCertificate(nss_cert); + + return (KMF_OK); + +} + +KMF_RETURN +NSS_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *ciphertext, + KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + SECKEYPrivateKey *NSSprivkey = NULL; + SECStatus rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + unsigned int in_len = 0, out_len = 0; + unsigned int total_decrypted = 0, modulus_len = 0; + uint8_t *in_data, *out_data; + int i, blocks; + + + if (key == NULL || AlgOID == NULL || + ciphertext == NULL || output == NULL || + ciphertext->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + NSSprivkey = (SECKEYPrivateKey *)key->keyp; + modulus_len = PK11_GetPrivateModulusLen(NSSprivkey); + + blocks = ciphertext->Length/modulus_len; + out_data = output->Data; + in_data = ciphertext->Data; + out_len = modulus_len - 11; + in_len = modulus_len; + + for (i = 0; i < blocks; i++) { + rv = PK11_PrivDecryptPKCS1(NSSprivkey, out_data, + &out_len, ciphertext->Length, in_data, in_len); + + if (rv != 0) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + out_data += out_len; + total_decrypted += out_len; + in_data += in_len; + } + + output->Length = total_decrypted; + + return (ret); +} + +static KMF_KEY_ALG +pk11keytype2kmf(CK_KEY_TYPE type) +{ + switch (type) { + case CKK_RSA: + return (KMF_RSA); + case CKK_DSA: + return (KMF_RSA); + case CKK_AES: + return (KMF_AES); + case CKK_RC4: + return (KMF_RC4); + case CKK_DES: + return (KMF_DES); + case CKK_DES3: + return (KMF_DES3); + default: + /* not supported */ + return (KMF_KEYALG_NONE); + } +} + +KMF_RETURN +NSS_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms, + KMF_KEY_HANDLE *keys, uint32_t *numkeys) +{ + KMF_RETURN rv; + SECKEYPrivateKeyList *prilist; + SECKEYPrivateKeyListNode *prinode; + SECKEYPublicKeyList *publist; + SECKEYPublicKeyListNode *pubnode; + PK11SlotInfo *nss_slot = NULL; + PK11SymKey *symlist; + int count; + + if (handle == NULL || parms == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = Do_NSS_Init(handle, + parms->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, &parms->cred); + if (rv != KMF_OK) { + return (rv); + } + + *numkeys = 0; + if (parms->keyclass == KMF_ASYM_PUB) { + publist = PK11_ListPublicKeysInSlot(nss_slot, parms->findLabel); + if (publist == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto cleanup; + } + } else if (parms->keyclass == KMF_ASYM_PRI) { + prilist = PK11_ListPrivKeysInSlot(nss_slot, + parms->findLabel, NULL); + if (prilist == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto cleanup; + } + } else if (parms->keyclass == KMF_SYMMETRIC) { + symlist = PK11_ListFixedKeysInSlot(nss_slot, parms->findLabel, + NULL); + if (symlist == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto cleanup; + } + } else { + rv = KMF_ERR_BAD_KEY_CLASS; + goto cleanup; + } + + if (parms->keyclass == KMF_ASYM_PUB) { + for (count = 0, pubnode = PUBKEY_LIST_HEAD(publist); + !PUBKEY_LIST_END(pubnode, publist); + pubnode = PUBKEY_LIST_NEXT(pubnode), count++) { + if (keys != NULL) { + keys[count].kstype = KMF_KEYSTORE_NSS; + keys[count].keyclass = KMF_ASYM_PUB; + keys[count].keyp = (void *)pubnode->key; + keys[count].keylabel = + PK11_GetPublicKeyNickname( + pubnode->key); + + if (pubnode->key->keyType == rsaKey) + keys[count].keyalg = KMF_RSA; + else if (pubnode->key->keyType == dsaKey) + keys[count].keyalg = KMF_DSA; + } + } + *numkeys = count; + } else if (parms->keyclass == KMF_ASYM_PRI) { + for (count = 0, prinode = PRIVKEY_LIST_HEAD(prilist); + !PRIVKEY_LIST_END(prinode, prilist); + prinode = PRIVKEY_LIST_NEXT(prinode), count++) { + if (keys != NULL) { + keys[count].kstype = KMF_KEYSTORE_NSS; + keys[count].keyclass = KMF_ASYM_PRI; + keys[count].keyp = (void *)prinode->key; + keys[count].keylabel = + PK11_GetPrivateKeyNickname( + prinode->key); + + if (prinode->key->keyType == rsaKey) + keys[count].keyalg = KMF_RSA; + else if (prinode->key->keyType == dsaKey) + keys[count].keyalg = KMF_DSA; + } + } + *numkeys = count; + } else if (parms->keyclass == KMF_SYMMETRIC) { + count = 0; + while (symlist) { + PK11SymKey *symkey = symlist; + CK_KEY_TYPE type; + KMF_KEY_ALG keyalg; + + type = PK11_GetSymKeyType(symkey); + keyalg = pk11keytype2kmf(type); + + /* + * If keytype is specified in the searching parameter, + * check the keytype and skip the key if its keytype + * doesn't match. + */ + symlist = PK11_GetNextSymKey(symkey); + if (parms->keytype != KMF_KEYALG_NONE && + parms->keytype != keyalg) { + continue; + } + + if (keys != NULL) { + keys[count].kstype = KMF_KEYSTORE_NSS; + keys[count].keyclass = KMF_SYMMETRIC; + keys[count].keyp = (void *) symkey; + keys[count].keylabel = + PK11_GetSymKeyNickname(symkey); + keys[count].keyalg = keyalg; + } else { + PK11_FreeSymKey(symkey); + } + count++; + } + *numkeys = count; + } + +cleanup: + if (nss_slot != NULL) { + PK11_FreeSlot(nss_slot); + } + + return (rv); +} + +static SECStatus +p12u_SwapUnicodeBytes(SECItem *uniItem) +{ + unsigned int i; + unsigned char a; + if ((uniItem == NULL) || (uniItem->len % 2)) { + return (SECFailure); + } + for (i = 0; i < uniItem->len; i += 2) { + a = uniItem->data[i]; + uniItem->data[i] = uniItem->data[i+1]; + uniItem->data[i+1] = a; + } + return (SECSuccess); +} + +static PRBool +p12u_ucs2_ascii_conversion_function( + PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen, + PRBool swapBytes) +{ + SECItem it = { 0 }; + SECItem *dup = NULL; + PRBool ret; + + it.data = inBuf; + it.len = inBufLen; + dup = SECITEM_DupItem(&it); + /* + * If converting Unicode to ASCII, swap bytes before conversion + * as neccessary. + */ + if (!toUnicode && swapBytes) { + if (p12u_SwapUnicodeBytes(dup) != SECSuccess) { + SECITEM_ZfreeItem(dup, PR_TRUE); + return (PR_FALSE); + } + } + /* Perform the conversion. */ + ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len, + outBuf, maxOutBufLen, outBufLen); + if (dup) + SECITEM_ZfreeItem(dup, PR_TRUE); + + return (ret); +} + +static PRBool +p12u_OpenFile(p12uContext *p12ctx, PRBool fileRead) +{ + if (!p12ctx || !p12ctx->filename) { + return (PR_FALSE); + } + + if (fileRead) { + p12ctx->file = PR_Open(p12ctx->filename, + PR_RDONLY, 0400); + } else { + p12ctx->file = PR_Open(p12ctx->filename, + PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 0600); + } + + if (!p12ctx->file) { + p12ctx->error = PR_TRUE; + return (PR_FALSE); + } + + return (PR_TRUE); +} + +static void +p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile) +{ + if (!ppCtx || !(*ppCtx)) { + return; + } + + if ((*ppCtx)->file != NULL) { + PR_Close((*ppCtx)->file); + } + + if ((*ppCtx)->filename != NULL) { + if (removeFile) { + PR_Delete((*ppCtx)->filename); + } + free((*ppCtx)->filename); + } + + free(*ppCtx); + *ppCtx = NULL; +} + +static p12uContext * +p12u_InitContext(PRBool fileImport, char *filename) +{ + p12uContext *p12ctx; + + p12ctx = PORT_ZNew(p12uContext); + if (!p12ctx) { + return (NULL); + } + + p12ctx->error = PR_FALSE; + p12ctx->errorValue = 0; + p12ctx->filename = strdup(filename); + + if (!p12u_OpenFile(p12ctx, fileImport)) { + p12u_DestroyContext(&p12ctx, PR_FALSE); + return (NULL); + } + + return (p12ctx); +} + +static void +p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len) +{ + p12uContext *p12cxt = arg; + int writeLen; + + if (!p12cxt || (p12cxt->error == PR_TRUE)) { + return; + } + + if (p12cxt->file == NULL) { + p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; + p12cxt->error = PR_TRUE; + return; + } + + writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len); + + if (writeLen != (int)len) { + PR_Close(p12cxt->file); + free(p12cxt->filename); + p12cxt->filename = NULL; + p12cxt->file = NULL; + p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; + p12cxt->error = PR_TRUE; + } +} + +#define HANDLE_NSS_ERROR(r) {\ + SET_ERROR(kmfh, PORT_GetError()); \ + rv = r; \ + goto out; } + +static KMF_RETURN +add_cert_to_bag(SEC_PKCS12ExportContext *p12ecx, + CERTCertificate *cert, SECItem *pwitem) +{ + KMF_RETURN rv = KMF_OK; + SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL; + + keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); + if (PK11_IsFIPS()) { + certSafe = keySafe; + } else { + certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); + } + + if (!certSafe || !keySafe) { + rv = KMF_ERR_INTERNAL; + goto out; + } + + if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, + CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC) + != SECSuccess) { + rv = KMF_ERR_INTERNAL; + } +out: + return (rv); +} + +/*ARGSUSED*/ +KMF_RETURN +NSS_ExportP12(KMF_HANDLE_T handle, + KMF_EXPORTP12_PARAMS *params, + int numcerts, KMF_X509_DER_CERT *certs, + int numkeys, KMF_KEY_HANDLE *keylist, + char *filename) +{ + KMF_RETURN rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SEC_PKCS12ExportContext *p12ecx = NULL; + p12uContext *p12ctx = NULL; + CERTCertList *certlist = NULL; + CERTCertificate *nsscert = NULL; + CERTCertListNode* node = NULL; + PK11SlotInfo *slot = NULL; + SECItem pwitem = {NULL, 0}; + + rv = Do_NSS_Init(handle, + params->nssparms, FALSE, &slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + /* + * Find the certificate(s) first. + */ + if (params->certLabel) { + nsscert = PK11_FindCertFromNickname(params->certLabel, + NULL); + if (nsscert == NULL) { + HANDLE_NSS_ERROR(KMF_ERR_CERT_NOT_FOUND) + } + } else { + rv = nss_find_matching_certs(slot, + params->issuer, + params->subject, + params->serial, + &certlist, 0); + + if (rv == KMF_OK && certlist == NULL) { + return (KMF_ERR_CERT_NOT_FOUND); + } + if (rv != KMF_OK) + return (rv); + } + + /* + * The KMF_CREDENTIAL holds the password to use for + * encrypting the PKCS12 key information. + */ + pwitem.data = (uchar_t *)params->p12cred.cred; + pwitem.len = params->p12cred.credlen; + + p12ctx = p12u_InitContext(PR_FALSE, filename); + if (!p12ctx) { + HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE) + } + + PORT_SetUCS2_ASCIIConversionFunction( + p12u_ucs2_ascii_conversion_function); + + p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, + slot, NULL); + if (!p12ecx) { + HANDLE_NSS_ERROR(KMF_ERR_OPEN_FILE) + } + + if (SEC_PKCS12AddPasswordIntegrity(p12ecx, &pwitem, SEC_OID_SHA1) + != SECSuccess) { + HANDLE_NSS_ERROR(KMF_ERR_INTERNAL) + } + + /* + * NSS actually supports storing a list of keys and certs + * in the PKCS#12 PDU. Nice feature. + */ + if (certlist != NULL) { + for (node = CERT_LIST_HEAD(certlist); + !CERT_LIST_END(node, certlist) && rv == KMF_OK; + node = CERT_LIST_NEXT(node)) { + + rv = add_cert_to_bag(p12ecx, node->cert, &pwitem); + } + } else if (nsscert != NULL) { + rv = add_cert_to_bag(p12ecx, nsscert, &pwitem); + } + + if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12ctx) + != SECSuccess) { + HANDLE_NSS_ERROR(KMF_ERR_ENCODING) + } +out: + if (nsscert) + CERT_DestroyCertificate(nsscert); + + if (certlist) + CERT_DestroyCertList(certlist); + + if (p12ctx) + p12u_DestroyContext(&p12ctx, PR_FALSE); + + if (p12ecx) + SEC_PKCS12DestroyExportContext(p12ecx); + + return (rv); +} + +#define SETATTR(t, n, atype, value, size) \ + t[n].type = atype; \ + t[n].pValue = (CK_BYTE *)value; \ + t[n].ulValueLen = (CK_ULONG)size; + +KMF_RETURN +NSS_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *rawkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECStatus ckrv = SECSuccess; + PK11SlotInfo *slot = NULL; + CERTCertificate *nss_cert = NULL; + SECKEYPrivateKeyInfo rpk; + SECItem nickname; + KMF_DATA derkey = { NULL, 0 }; + uchar_t ver = 0; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (params == NULL || params->certificate == NULL || rawkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = Do_NSS_Init(handle, + params->nssparms, FALSE, &slot); + + if (rv != KMF_OK) + return (rv); + + rv = nss_authenticate(handle, slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + /* + * Decode the cert into an NSS CERT object so we can access the + * SPKI and KeyUsage data later. + */ + nss_cert = CERT_DecodeCertFromPackage((char *)params->certificate->Data, + params->certificate->Length); + + if (nss_cert == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + (void) memset(&rpk, 0, sizeof (rpk)); + + rpk.arena = NULL; + rpk.version.type = siUnsignedInteger; + rpk.version.data = &ver; + rpk.version.len = 1; + if (rawkey->keytype == KMF_RSA) { + + rv = DerEncodeRSAPrivateKey(&derkey, &rawkey->rawdata.rsa); + if (rv != KMF_OK) + goto cleanup; + + rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm; + rpk.privateKey.data = derkey.Data; + rpk.privateKey.len = derkey.Length; + rpk.attributes = NULL; + + + } else if (rawkey->keytype == KMF_DSA) { + rv = DerEncodeDSAPrivateKey(&derkey, &rawkey->rawdata.dsa); + if (rv != KMF_OK) + goto cleanup; + + rpk.algorithm = nss_cert->subjectPublicKeyInfo.algorithm; + rpk.privateKey.data = derkey.Data; + rpk.privateKey.len = derkey.Length; + rpk.attributes = NULL; + + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + nickname.data = (uchar_t *)params->label; + nickname.len = (params->label ? strlen(params->label) : 0); + + ckrv = PK11_ImportPrivateKeyInfo(slot, &rpk, + &nickname, &nss_cert->subjectPublicKeyInfo.subjectPublicKey, + TRUE, TRUE, nss_cert->keyUsage, NULL); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_INTERNAL; + } + +cleanup: + if (nss_cert != NULL) { + CERT_DestroyCertificate(nss_cert); + } + KMF_FreeData(&derkey); + return (rv); +} + +KMF_RETURN +NSS_CreateSymKey(KMF_HANDLE_T handle, + KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + PK11SlotInfo *nss_slot = NULL; + PK11SymKey *nsskey = NULL; + CK_MECHANISM_TYPE keyType; + SECStatus nssrv; + int keySize; + + if (params == NULL || symkey == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + switch (params->keytype) { + case KMF_AES: + keyType = CKM_AES_KEY_GEN; + keySize = params->keylength; + if (keySize == 0 || (keySize % 8) != 0) + return (KMF_ERR_BAD_KEY_SIZE); + break; + case KMF_RC4: + keyType = CKM_RC4_KEY_GEN; + keySize = params->keylength; + if (keySize == 0 || (keySize % 8) != 0) + return (KMF_ERR_BAD_KEY_SIZE); + break; + case KMF_DES: + keyType = CKM_DES_KEY_GEN; + keySize = 0; /* required by PK11_TokenKeyGen() */ + break; + case KMF_DES3: + keyType = CKM_DES3_KEY_GEN; + keySize = 0; /* required by PK11_TokenKeyGen() */ + break; + default: + rv = KMF_ERR_BAD_KEY_TYPE; + goto out; + } + + rv = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, FALSE, &nss_slot); + if (rv != KMF_OK) { + return (rv); + } + + rv = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + nsskey = PK11_TokenKeyGen(nss_slot, keyType, NULL, keySize, NULL, + PR_TRUE, (void *)params->cred.cred); + if (nsskey == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + nssrv = PK11_SetSymKeyNickname(nsskey, params->keylabel); + if (nssrv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + symkey->kstype = KMF_KEYSTORE_NSS; + symkey->keyalg = params->keytype; + symkey->keyclass = KMF_SYMMETRIC; + symkey->israw = FALSE; + symkey->keyp = (void *)nsskey; + +out: + if (nss_slot != NULL) + PK11_FreeSlot(nss_slot); + + if (rv != KMF_OK && nsskey != NULL) { + PK11_DeleteTokenSymKey(nsskey); + PK11_FreeSymKey(nsskey); + } + return (rv); +} + +KMF_RETURN +NSS_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SECItem *value = NULL; + PK11SymKey *nsskey; + SECStatus nss_rv; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + else if (symkey->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (symkey->israw) { + KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp; + + if (rawkey == NULL || + rawkey->rawdata.sym.keydata.val == NULL || + rawkey->rawdata.sym.keydata.len == 0) + return (KMF_ERR_BAD_KEYHANDLE); + + rkey->keydata.len = rawkey->rawdata.sym.keydata.len; + if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(rkey->keydata.val, + rawkey->rawdata.sym.keydata.val, rkey->keydata.len); + } else { + nsskey = (PK11SymKey *)(symkey->keyp); + if (nsskey == NULL) + return (KMF_ERR_BAD_KEYHANDLE); + + nss_rv = PK11_ExtractKeyValue(nsskey); + if (nss_rv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_GETKEYVALUE_FAILED; + goto out; + } + + value = PK11_GetKeyData(nsskey); + if (value == NULL) { + SET_ERROR(kmfh, PORT_GetError()); + rv = KMF_ERR_GETKEYVALUE_FAILED; + goto out; + } + + if (value->len == 0 || value->data == NULL) { + rv = KMF_ERR_GETKEYVALUE_FAILED; + goto out; + } + + rkey->keydata.val = malloc(value->len); + if (rkey->keydata.val == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + (void) memcpy(rkey->keydata.val, value->data, value->len); + rkey->keydata.len = value->len; + (void) memset(value->data, 0, value->len); + } +out: + if (value != NULL) + SECITEM_FreeItem(value, PR_TRUE); + return (rv); +} + +KMF_RETURN +NSS_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params, + KMF_CREDENTIAL *newpin) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int rv; + PK11SlotInfo *nss_slot = NULL; + + if (handle == NULL || params == NULL || newpin == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = Do_NSS_Init(handle, + params->ks_opt_u.nss_opts, + FALSE, &nss_slot); + /* If it was uninitialized, set it */ + if (ret == KMF_ERR_UNINITIALIZED_TOKEN) { + rv = PK11_InitPin(nss_slot, NULL, newpin->cred); + if (rv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_AUTH_FAILED; + } else { + ret = KMF_OK; + } + } else if (ret == KMF_OK) { + ret = nss_authenticate(handle, nss_slot, ¶ms->cred); + if (ret != KMF_OK) { + return (ret); + } + rv = PK11_ChangePW(nss_slot, + params->cred.cred, newpin->cred); + if (rv != SECSuccess) { + SET_ERROR(kmfh, PORT_GetError()); + ret = KMF_ERR_AUTH_FAILED; + } + } + + return (ret); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile new file mode 100644 index 0000000000..443f78537a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile new file mode 100644 index 0000000000..472ac90a9a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile new file mode 100644 index 0000000000..fe1e843387 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_nss/sparcv9/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../../Makefile.lib.64 + +LDLIBS += $(NSSLIBS64) + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile new file mode 100644 index 0000000000..ba73e41d2e --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com new file mode 100644 index 0000000000..3ae32a00da --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com @@ -0,0 +1,78 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for KMF Plugins +# + +LIBRARY= kmf_openssl.a +VERS= .1 + +OBJECTS= openssl_spi.o + +include $(SRC)/lib/Makefile.lib + +LIBLINKS= $(DYNLIB:.so.1=.so) +SFWDIR= /usr/sfw +KMFINC= -I../../../include -I../../../ber_der/inc +BERLIB= -lkmf -lkmfberder +BERLIB64= $(BERLIB) + +OPENSSLLIBS= $(BERLIB) -R$(SFWDIR)/lib -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc +OPENSSLLIBS64= $(BERLIB64) -R$(SFWDIR)/lib/$(MACH64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \ + -lcrypto -lcryptoutil -lc + +LINTSSLLIBS = $(BERLIB) -L$(ROOT)/$(SFWDIR)/lib -lcrypto -lcryptoutil -lc +LINTSSLLIBS64= $(BERLIB64) -L$(ROOT)/$(SFWDIR)/lib/$(MACH64) \ + -lcrypto -lcryptoutil -lc + +SRCDIR= ../common +INCDIR= ../../include + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(ROOT)/$(SFWDIR)/include \ + -I$(INCDIR) -I/usr/include/libxml2 + +PICS= $(OBJECTS:%=pics/%) +SONAME= $(DYNLIB) + +lint:= OPENSSLLIBS= $(LINTSSLLIBS) +lint:= OPENSSLLIBS64= $(LINTSSLLIBS64) + +LDLIBS32 += $(OPENSSLLIBS) + +ROOTLIBDIR= $(ROOT)/usr/lib/security +ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64) + +.KEEP_STATE: + +LIBS = $(DYNLIB) +all: $(DYNLIB) $(LINTLIB) + +lint: lintcheck + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile new file mode 100644 index 0000000000..d73321747a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +LDLIBS += $(OPENSSLLIBS64) + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers new file mode 100644 index 0000000000..cd910effa4 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers @@ -0,0 +1,61 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + KMF_Plugin_Initialize; + OpenSSL_CertGetPrintable; + OpenSSL_CheckCRLDate; + OpenSSL_CreateKeypair; + OpenSSL_CreateOCSPRequest; + OpenSSL_CreateSymKey; + OpenSSL_DecryptData; + OpenSSL_DeleteCRL; + OpenSSL_DeleteCert; + OpenSSL_DeleteKey; + OpenSSL_EncodePubKeyData; + OpenSSL_ExportP12; + OpenSSL_FindCert; + OpenSSL_FindCertInCRL; + OpenSSL_FindKey; + OpenSSL_FreeKMFCert; + OpenSSL_GetErrorString; + OpenSSL_GetOCSPStatusForCert; + OpenSSL_GetPrikeyByCert; + OpenSSL_GetSymKeyValue; + OpenSSL_ImportCRL; + OpenSSL_IsCRLFile; + OpenSSL_IsCertFile; + OpenSSL_ListCRL; + OpenSSL_SignData; + OpenSSL_StoreCert; + OpenSSL_StorePrivateKey; + OpenSSL_VerifyCRLFile; + openssl_read_pkcs12; + local: + *; +}; diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c new file mode 100644 index 0000000000..e088341f01 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c @@ -0,0 +1,4198 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * OpenSSL keystore wrapper + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <kmfapiP.h> +#include <ber_der.h> +#include <oidsalg.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <dirent.h> +#include <cryptoutil.h> +#include <synch.h> +#include <thread.h> + +/* OPENSSL related headers */ +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/bn.h> +#include <openssl/x509.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#include <openssl/x509v3.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/pkcs12.h> +#include <openssl/ocsp.h> +#include <openssl/des.h> +#include <openssl/rand.h> + +#define PRINT_ANY_EXTENSION (\ + KMF_X509_EXT_KEY_USAGE |\ + KMF_X509_EXT_CERT_POLICIES |\ + KMF_X509_EXT_SUBJALTNAME |\ + KMF_X509_EXT_BASIC_CONSTRAINTS |\ + KMF_X509_EXT_NAME_CONSTRAINTS |\ + KMF_X509_EXT_POLICY_CONSTRAINTS |\ + KMF_X509_EXT_EXT_KEY_USAGE |\ + KMF_X509_EXT_INHIBIT_ANY_POLICY |\ + KMF_X509_EXT_AUTH_KEY_ID |\ + KMF_X509_EXT_SUBJ_KEY_ID |\ + KMF_X509_EXT_POLICY_MAPPING) + +static BIO *bio_err = NULL; +static uchar_t P[] = { 0x00, 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, + 0xaa, 0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69, + 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c, + 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, + 0xe5, 0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, + 0xaf, 0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a, + 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24, + 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, + 0x91 }; + +static uchar_t Q[] = { 0x00, 0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8, + 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4, + 0x8e, 0xda, 0xce, 0x91, 0x5f }; + +static uchar_t G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, + 0x13, 0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5, + 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef, + 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, + 0x2e, 0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, + 0xbf, 0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c, + 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08, + 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, + 0x02 }; + +#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_OPENSSL; \ + h->lasterr.errcode = c; + +#define SET_SYS_ERROR(h, c) h->lasterr.kstype = -1; h->lasterr.errcode = c; + +mutex_t init_lock = DEFAULTMUTEX; +static int ssl_initialized = 0; + +KMF_RETURN +OpenSSL_FindCert(KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *, + KMF_X509_DER_CERT *, + uint32_t *); + +void +OpenSSL_FreeKMFCert(KMF_HANDLE_T, KMF_X509_DER_CERT *); + +KMF_RETURN +OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *, KMF_DATA *); + +KMF_RETURN +OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *); + +KMF_RETURN +OpenSSL_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +KMF_RETURN +OpenSSL_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +OpenSSL_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +OpenSSL_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, boolean_t); + +KMF_RETURN +OpenSSL_ImportCRL(KMF_HANDLE_T, KMF_IMPORTCRL_PARAMS *); + +KMF_RETURN +OpenSSL_DeleteCRL(KMF_HANDLE_T, KMF_DELETECRL_PARAMS *); + +KMF_RETURN +OpenSSL_ListCRL(KMF_HANDLE_T, KMF_LISTCRL_PARAMS *, char **); + +KMF_RETURN +OpenSSL_FindCertInCRL(KMF_HANDLE_T, KMF_FINDCERTINCRL_PARAMS *); + +KMF_RETURN +OpenSSL_CertGetPrintable(KMF_HANDLE_T, const KMF_DATA *, + KMF_PRINTABLE_ITEM, char *); + +KMF_RETURN +OpenSSL_GetErrorString(KMF_HANDLE_T, char **); + +KMF_RETURN +OpenSSL_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, + KMF_KEY_HANDLE *, KMF_KEY_ALG); + +KMF_RETURN +OpenSSL_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +OpenSSL_CreateOCSPRequest(KMF_HANDLE_T, KMF_OCSPREQUEST_PARAMS *, + char *reqfile); + +KMF_RETURN +OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T, KMF_OCSPRESPONSE_PARAMS_INPUT *, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *); + +KMF_RETURN +OpenSSL_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +KMF_RETURN +OpenSSL_ExportP12(KMF_HANDLE_T, + KMF_EXPORTP12_PARAMS *, + int, KMF_X509_DER_CERT *, + int, KMF_KEY_HANDLE *, + char *); + +KMF_RETURN +OpenSSL_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, + KMF_RAW_KEY_DATA *); + +KMF_RETURN +OpenSSL_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, + KMF_KEY_HANDLE *); + +KMF_RETURN +OpenSSL_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); + +KMF_RETURN +OpenSSL_VerifyCRLFile(KMF_HANDLE_T, KMF_VERIFYCRL_PARAMS *); + +KMF_RETURN +OpenSSL_CheckCRLDate(KMF_HANDLE_T, KMF_CHECKCRLDATE_PARAMS *); + +static +KMF_PLUGIN_FUNCLIST openssl_plugin_table = +{ + 1, /* Version */ + NULL, /* ConfigureKeystore */ + OpenSSL_FindCert, + OpenSSL_FreeKMFCert, + OpenSSL_StoreCert, + NULL, /* ImportCert */ + OpenSSL_ImportCRL, + OpenSSL_DeleteCert, + OpenSSL_DeleteCRL, + OpenSSL_CreateKeypair, + OpenSSL_FindKey, + OpenSSL_EncodePubKeyData, + OpenSSL_SignData, + OpenSSL_DeleteKey, + OpenSSL_ListCRL, + NULL, /* FindCRL */ + OpenSSL_FindCertInCRL, + OpenSSL_GetErrorString, + OpenSSL_GetPrikeyByCert, + OpenSSL_DecryptData, + OpenSSL_ExportP12, + OpenSSL_StorePrivateKey, + OpenSSL_CreateSymKey, + OpenSSL_GetSymKeyValue, + NULL, /* SetTokenPin */ + NULL /* Finalize */ +}; + +static mutex_t *lock_cs; +static long *lock_count; + +static void +/*ARGSUSED*/ +locking_cb(int mode, int type, char *file, int line) +{ + if (mode & CRYPTO_LOCK) { + (void) mutex_lock(&(lock_cs[type])); + lock_count[type]++; + } else { + (void) mutex_unlock(&(lock_cs[type])); + } +} + +static unsigned long +thread_id() +{ + return ((unsigned long)thr_self()); +} + +KMF_PLUGIN_FUNCLIST * +KMF_Plugin_Initialize() +{ + int i; + + (void) mutex_lock(&init_lock); + if (!ssl_initialized) { + OpenSSL_add_all_algorithms(); + + /* Enable error strings for reporting */ + ERR_load_crypto_strings(); + + /* + * Add support for extension OIDs that are not yet in the + * openssl default set. + */ + (void) OBJ_create("2.5.29.30", "nameConstraints", + "X509v3 Name Constraints"); + (void) OBJ_create("2.5.29.33", "policyMappings", + "X509v3 Policy Mappings"); + (void) OBJ_create("2.5.29.36", "policyConstraints", + "X509v3 Policy Constraints"); + (void) OBJ_create("2.5.29.46", "freshestCRL", + "X509v3 Freshest CRL"); + (void) OBJ_create("2.5.29.54", "inhibitAnyPolicy", + "X509v3 Inhibit Any-Policy"); + /* + * Set up for thread-safe operation. + */ + lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (mutex_t)); + if (lock_cs == NULL) { + (void) mutex_unlock(&init_lock); + return (NULL); + } + + lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof (long)); + if (lock_count == NULL) { + OPENSSL_free(lock_cs); + (void) mutex_unlock(&init_lock); + return (NULL); + } + + for (i = 0; i < CRYPTO_num_locks(); i++) { + lock_count[i] = 0; + (void) mutex_init(&lock_cs[i], USYNC_THREAD, NULL); + } + + CRYPTO_set_id_callback((unsigned long (*)())thread_id); + CRYPTO_set_locking_callback((void (*)())locking_cb); + ssl_initialized = 1; + } + (void) mutex_unlock(&init_lock); + + return (&openssl_plugin_table); +} +/* + * Convert an SSL DN to a KMF DN. + */ +static KMF_RETURN +get_x509_dn(X509_NAME *sslDN, KMF_X509_NAME *kmfDN) +{ + KMF_DATA derdata; + KMF_RETURN rv = KMF_OK; + uchar_t *tmp; + + /* Convert to raw DER format */ + derdata.Length = i2d_X509_NAME(sslDN, NULL); + if ((tmp = derdata.Data = (uchar_t *)OPENSSL_malloc(derdata.Length)) + == NULL) { + return (KMF_ERR_MEMORY); + } + (void) i2d_X509_NAME(sslDN, &tmp); + + /* Decode to KMF format */ + rv = DerDecodeName(&derdata, kmfDN); + if (rv != KMF_OK) { + rv = KMF_ERR_BAD_CERT_FORMAT; + } + OPENSSL_free(derdata.Data); + + return (rv); +} + +static int +isdir(char *path) +{ + struct stat s; + + if (stat(path, &s) == -1) + return (0); + + return (s.st_mode & S_IFDIR); +} + +static KMF_RETURN +ssl_cert2KMFDATA(KMF_HANDLE *kmfh, X509 *x509cert, KMF_DATA *cert) +{ + KMF_RETURN rv = KMF_OK; + unsigned char *buf = NULL, *p; + int len; + + /* + * Convert the X509 internal struct to DER encoded data + */ + if ((len = i2d_X509(x509cert, NULL)) < 0) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + if ((buf = malloc(len)) == NULL) { + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_MEMORY; + goto cleanup; + } + + /* + * i2d_X509 will increment the buf pointer so that we need to + * save it. + */ + p = buf; + if ((len = i2d_X509(x509cert, &p)) < 0) { + SET_ERROR(kmfh, ERR_get_error()); + free(buf); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* caller's responsibility to free it */ + cert->Data = buf; + cert->Length = len; + +cleanup: + if (rv != KMF_OK) { + if (buf) + free(buf); + cert->Data = NULL; + cert->Length = 0; + } + + return (rv); +} + +static KMF_RETURN +check_cert(X509 *xcert, KMF_FINDCERT_PARAMS *params, boolean_t *match) +{ + KMF_RETURN rv = KMF_OK; + boolean_t findIssuer = FALSE; + boolean_t findSubject = FALSE; + boolean_t findSerial = FALSE; + KMF_X509_NAME issuerDN, subjectDN; + KMF_X509_NAME certIssuerDN, certSubjectDN; + + *match = FALSE; + if (xcert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&certIssuerDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&certSubjectDN, 0, sizeof (KMF_X509_NAME)); + + if (params->issuer != NULL && strlen(params->issuer)) { + rv = KMF_DNParser(params->issuer, &issuerDN); + if (rv != KMF_OK) + return (KMF_ERR_BAD_PARAMETER); + + rv = get_x509_dn(xcert->cert_info->issuer, &certIssuerDN); + if (rv != KMF_OK) { + KMF_FreeDN(&issuerDN); + return (KMF_ERR_BAD_PARAMETER); + } + + findIssuer = TRUE; + } + if (params->subject != NULL && strlen(params->subject)) { + rv = KMF_DNParser(params->subject, &subjectDN); + if (rv != KMF_OK) { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + rv = get_x509_dn(xcert->cert_info->subject, &certSubjectDN); + if (rv != KMF_OK) { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + findSubject = TRUE; + } + if (params->serial != NULL && params->serial->val != NULL) + findSerial = TRUE; + + if (findSerial) { + BIGNUM *bn; + + /* Comparing BIGNUMs is a pain! */ + bn = ASN1_INTEGER_to_BN(xcert->cert_info->serialNumber, NULL); + if (bn != NULL) { + int bnlen = BN_num_bytes(bn); + + if (bnlen == params->serial->len) { + uchar_t *a = malloc(bnlen); + if (a == NULL) { + rv = KMF_ERR_MEMORY; + BN_free(bn); + goto cleanup; + } + bnlen = BN_bn2bin(bn, a); + *match = !memcmp(a, + params->serial->val, + params->serial->len); + rv = KMF_OK; + free(a); + } + BN_free(bn); + if (!(*match)) + goto cleanup; + } else { + rv = KMF_OK; + goto cleanup; + } + } + if (findIssuer) { + *match = !KMF_CompareRDNs(&issuerDN, &certIssuerDN); + if (!(*match)) { + rv = KMF_OK; + goto cleanup; + } + } + if (findSubject) { + *match = !KMF_CompareRDNs(&subjectDN, &certSubjectDN); + if (!(*match)) { + rv = KMF_OK; + goto cleanup; + } + } + + *match = TRUE; +cleanup: + if (findIssuer) { + KMF_FreeDN(&issuerDN); + KMF_FreeDN(&certIssuerDN); + } + if (findSubject) { + KMF_FreeDN(&subjectDN); + KMF_FreeDN(&certSubjectDN); + } + + return (rv); +} + +static KMF_RETURN +load_X509cert(KMF_HANDLE *kmfh, + KMF_FINDCERT_PARAMS *params, + char *pathname, + X509 **outcert) +{ + KMF_RETURN rv = KMF_OK; + X509 *xcert = NULL; + BIO *bcert = NULL; + boolean_t match = FALSE; + KMF_ENCODE_FORMAT format; + + /* + * auto-detect the file format, regardless of what + * the 'format' parameters in the params say. + */ + rv = KMF_GetFileFormat(pathname, &format); + if (rv != KMF_OK) { + if (rv == KMF_ERR_OPEN_FILE) + rv = KMF_ERR_CERT_NOT_FOUND; + return (rv); + } + + /* Not ASN1(DER) format */ + if ((bcert = BIO_new_file(pathname, "rb")) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (format == KMF_FORMAT_PEM) + xcert = PEM_read_bio_X509_AUX(bcert, NULL, NULL, NULL); + else if (format == KMF_FORMAT_ASN1) + xcert = d2i_X509_bio(bcert, NULL); + else if (format == KMF_FORMAT_PKCS12) { + PKCS12 *p12 = d2i_PKCS12_bio(bcert, NULL); + if (p12 != NULL) { + (void) PKCS12_parse(p12, NULL, NULL, &xcert, NULL); + PKCS12_free(p12); + p12 = NULL; + } else { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_BAD_CERT_FORMAT; + } + } else { + rv = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (check_cert(xcert, params, &match) != KMF_OK || match == FALSE) { + rv = KMF_ERR_CERT_NOT_FOUND; + goto cleanup; + } + + if (outcert != NULL) { + *outcert = xcert; + } + +cleanup: + if (bcert != NULL) (void) BIO_free(bcert); + if (rv != KMF_OK && xcert != NULL) + X509_free(xcert); + + return (rv); +} + +static KMF_RETURN +kmf_load_cert(KMF_HANDLE *kmfh, + KMF_FINDCERT_PARAMS *params, + char *pathname, + KMF_DATA *cert) +{ + KMF_RETURN rv = KMF_OK; + X509 *x509cert = NULL; + + rv = load_X509cert(kmfh, params, pathname, &x509cert); + if (rv == KMF_OK && x509cert != NULL && cert != NULL) { + rv = ssl_cert2KMFDATA(kmfh, x509cert, cert); + if (rv != KMF_OK) { + goto cleanup; + } + if (params->find_cert_validity == KMF_NONEXPIRED_CERTS) { + rv = KMF_CheckCertDate(kmfh, cert); + } else if (params->find_cert_validity == KMF_EXPIRED_CERTS) { + rv = KMF_CheckCertDate(kmfh, cert); + if (rv == KMF_OK) { + /* + * This is a valid cert so skip it. + */ + rv = KMF_ERR_CERT_NOT_FOUND; + } + if (rv == KMF_ERR_VALIDITY_PERIOD) { + /* + * We want to return success when we + * find an invalid cert. + */ + rv = KMF_OK; + goto cleanup; + } + } + } +cleanup: + if (x509cert != NULL) + X509_free(x509cert); + + return (rv); +} + +static EVP_PKEY * +openssl_load_key(KMF_HANDLE_T handle, const char *file) +{ + BIO *keyfile = NULL; + EVP_PKEY *pkey = NULL; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + + if (file == NULL) { + return (NULL); + } + + if (KMF_GetFileFormat((char *)file, &format) != KMF_OK) + return (NULL); + + keyfile = BIO_new_file(file, "rb"); + if (keyfile == NULL) { + goto end; + } + + if (format == KMF_FORMAT_ASN1) + pkey = d2i_PrivateKey_bio(keyfile, NULL); + else if (format == KMF_FORMAT_PEM) + pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL); + +end: + if (pkey == NULL) + SET_ERROR(kmfh, ERR_get_error()); + + if (keyfile != NULL) + (void) BIO_free(keyfile); + + return (pkey); +} + +KMF_RETURN +OpenSSL_FindCert(KMF_HANDLE_T handle, + KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_DATA certdata = {NULL, 0}; + char *fullpath; + + if (num_certs == NULL || params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *num_certs = 0; + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + DIR *dirp; + struct dirent *dp; + int n = 0; + + /* open all files in the directory and attempt to read them */ + if ((dirp = opendir(fullpath)) == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + while ((dp = readdir(dirp)) != NULL) { + char *fname; + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + fname = get_fullpath(fullpath, + (char *)&dp->d_name); + + rv = kmf_load_cert(kmfh, params, fname, + &certdata); + + if (rv != KMF_OK) { + free(fname); + KMF_FreeData(&certdata); + continue; + } + + /* If load succeeds, add certdata to the list */ + if (kmf_cert != NULL) { + kmf_cert[n].certificate.Data = certdata.Data; + kmf_cert[n].certificate.Length = + certdata.Length; + + kmf_cert[n].kmf_private.keystore_type = + KMF_KEYSTORE_OPENSSL; + kmf_cert[n].kmf_private.flags = + KMF_FLAG_CERT_VALID; + kmf_cert[n].kmf_private.label = fname; + } else { + free(fname); + KMF_FreeData(&certdata); + } + n++; + } + (*num_certs) = n; + if (*num_certs == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + if (*num_certs > 0) + rv = KMF_OK; +exit: + (void) closedir(dirp); + } else { + /* Just try to load a single certificate */ + rv = kmf_load_cert(kmfh, params, fullpath, &certdata); + if (rv != KMF_OK) { + free(fullpath); + KMF_FreeData(&certdata); + return (rv); + } + + if (kmf_cert != NULL) { + kmf_cert->certificate.Data = certdata.Data; + kmf_cert->certificate.Length = certdata.Length; + kmf_cert->kmf_private.keystore_type = + KMF_KEYSTORE_OPENSSL; + kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID; + kmf_cert->kmf_private.label = fullpath; + } else { + KMF_FreeData(&certdata); + } + + *num_certs = 1; + } + + if (kmf_cert == NULL || rv != KMF_OK) + free(fullpath); + + return (rv); + +} + +void +/*ARGSUSED*/ +OpenSSL_FreeKMFCert(KMF_HANDLE_T handle, + KMF_X509_DER_CERT *kmf_cert) +{ + if (kmf_cert != NULL) { + if (kmf_cert->certificate.Data != NULL) { + free(kmf_cert->certificate.Data); + kmf_cert->certificate.Data = NULL; + kmf_cert->certificate.Length = 0; + } + if (kmf_cert->kmf_private.label) + free(kmf_cert->kmf_private.label); + } +} + +KMF_RETURN +OpenSSL_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params, + KMF_DATA * pcert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *xcert = NULL; + FILE *fp; + unsigned char *outbuf; + unsigned char *outbuf_p; + char *fullpath; + int outbuflen; + int len; + KMF_ENCODE_FORMAT format; + + if (params == NULL || params->ks_opt_u.openssl_opts.certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * check if the cert output format is supported by OPENSSL. + * however, since the keystore for OPENSSL is just a file, we have + * no way to store the format along with the file. + */ + format = params->sslparms.format; + if (format != KMF_FORMAT_ASN1 && format != KMF_FORMAT_PEM) + return (KMF_ERR_BAD_CERT_FORMAT); + + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * When storing a certificate, you must specify a filename. + */ + if (isdir(fullpath)) { + free(fullpath); + return (KMF_ERR_BAD_PARAMETER); + } + + /* copy cert data to outbuf */ + outbuflen = pcert->Length; + outbuf = malloc(outbuflen); + if (outbuf == NULL) { + free(fullpath); + return (KMF_ERR_MEMORY); + } + (void) memcpy(outbuf, pcert->Data, pcert->Length); + + if ((fp = fopen(fullpath, "w")) == + NULL) { + SET_SYS_ERROR(kmfh, errno); + ret = KMF_ERR_INTERNAL; + goto out; + } + + if (format == KMF_FORMAT_ASN1) { + len = fwrite(outbuf, 1, outbuflen, fp); + if (len != outbuflen) { + SET_SYS_ERROR(kmfh, errno); + ret = KMF_ERR_WRITE_FILE; + } else { + ret = KMF_OK; + } + goto out; + } + + /* + * The output format is not KMF_FORMAT_ASN1, so we will + * Convert the cert data to OpenSSL internal X509 first. + */ + outbuf_p = outbuf; /* use a temp pointer; required by openssl */ + xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, outbuflen); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + + if (format == KMF_FORMAT_PEM) { + /* Convert to the PEM format and write it out */ + if (!PEM_write_X509(fp, xcert)) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + } else { + ret = KMF_OK; + } + goto out; + } + +out: + if (fullpath != NULL) + free(fullpath); + + if (outbuf != NULL) { + free(outbuf); + } + if (fp != NULL) { + (void) fclose(fp); + } + + if (xcert != NULL) { + X509_free(xcert); + } + + return (ret); +} + +KMF_RETURN +OpenSSL_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params) +{ + KMF_RETURN rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *fullpath = NULL; + KMF_DATA certdata = {NULL, 0}; + + if (params == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + DIR *dirp; + struct dirent *dp; + + /* open all files in the directory and attempt to read them */ + if ((dirp = opendir(fullpath)) == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") != 0 && + strcmp(dp->d_name, "..") != 0) { + char *fname; + + fname = get_fullpath(fullpath, + (char *)&dp->d_name); + + if (fname == NULL) { + rv = KMF_ERR_MEMORY; + break; + } + + rv = kmf_load_cert(kmfh, params, fname, + &certdata); + + if (rv == KMF_ERR_CERT_NOT_FOUND) { + free(fname); + if (certdata.Data) + free(certdata.Data); + rv = KMF_OK; + continue; + } else if (rv != KMF_OK) { + free(fname); + break; + } + + if (unlink(fname) != 0) { + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_INTERNAL; + free(fname); + break; + } + free(fname); + if (certdata.Data) + free(certdata.Data); + } + } + (void) closedir(dirp); + } else { + /* Just try to load a single certificate */ + rv = kmf_load_cert(kmfh, params, fullpath, &certdata); + if (rv == KMF_OK) { + if (unlink(fullpath) != 0) { + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_INTERNAL; + } + } + } + +out: + if (fullpath != NULL) + free(fullpath); + + if (certdata.Data) + free(certdata.Data); + + return (rv); +} + +KMF_RETURN +OpenSSL_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_DATA *keydata) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int n; + + if (key == NULL || keydata == NULL || + key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyalg == KMF_RSA) { + RSA *pubkey = EVP_PKEY_get1_RSA(key->keyp); + + if (!(n = i2d_RSA_PUBKEY(pubkey, &keydata->Data))) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_ENCODING); + } + RSA_free(pubkey); + } else if (key->keyalg == KMF_DSA) { + DSA *pubkey = EVP_PKEY_get1_DSA(key->keyp); + + if (!(n = i2d_DSA_PUBKEY(pubkey, &keydata->Data))) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_ENCODING); + } + DSA_free(pubkey); + } else { + return (KMF_ERR_BAD_PARAMETER); + } + keydata->Length = n; + +cleanup: + if (rv != KMF_OK) { + if (keydata->Data) + free(keydata->Data); + keydata->Data = NULL; + keydata->Length = 0; + } + + return (rv); +} + +static KMF_RETURN +ssl_write_private_key(KMF_HANDLE *kmfh, KMF_ENCODE_FORMAT format, BIO *out, + KMF_CREDENTIAL *cred, EVP_PKEY *pkey) +{ + int rv = 0; + RSA *rsa; + DSA *dsa; + + switch (format) { + case KMF_FORMAT_ASN1: + if (pkey->type == EVP_PKEY_RSA) { + rsa = EVP_PKEY_get1_RSA(pkey); + rv = i2d_RSAPrivateKey_bio(out, rsa); + RSA_free(rsa); + } else if (pkey->type == EVP_PKEY_DSA) { + dsa = EVP_PKEY_get1_DSA(pkey); + rv = i2d_DSAPrivateKey_bio(out, dsa); + DSA_free(dsa); + } + if (rv == 1) { + rv = KMF_OK; + } else { + SET_ERROR(kmfh, rv); + } + break; + case KMF_FORMAT_PEM: + if (pkey->type == EVP_PKEY_RSA) { + rsa = EVP_PKEY_get1_RSA(pkey); + rv = PEM_write_bio_RSAPrivateKey(out, + rsa, + NULL /* encryption type */, + NULL, 0, NULL, + cred->cred); + RSA_free(rsa); + } else if (pkey->type == EVP_PKEY_DSA) { + dsa = EVP_PKEY_get1_DSA(pkey); + rv = PEM_write_bio_DSAPrivateKey(out, + dsa, + NULL /* encryption type */, + NULL, 0, NULL, + cred->cred); + DSA_free(dsa); + } + + if (rv == 1) { + rv = KMF_OK; + } else { + SET_ERROR(kmfh, rv); + } + break; + + default: + rv = KMF_ERR_BAD_PARAMETER; + } + + return (rv); +} + +KMF_RETURN +OpenSSL_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int format; + uint32_t eValue = 0x010001; + RSA *sslPrivKey = NULL; + DSA *sslDSAKey = NULL; + EVP_PKEY *eprikey = NULL; + EVP_PKEY *epubkey = NULL; + BIO *out = NULL; + char *fullpath = NULL; + + if (params == NULL || params->sslparms.keyfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the requested file exists, return an error */ + if (access(fullpath, F_OK) == 0) { + free(fullpath); + return (KMF_ERR_DUPLICATE_KEYFILE); + } + + eprikey = EVP_PKEY_new(); + if (eprikey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + epubkey = EVP_PKEY_new(); + if (epubkey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + if (params->keytype == KMF_RSA) { + if (params->rsa_exponent.len > 0 && + params->rsa_exponent.len <= sizeof (eValue) && + params->rsa_exponent.val != NULL) + /*LINTED*/ + eValue = *(uint32_t *)params->rsa_exponent.val; + + sslPrivKey = RSA_generate_key(params->keylength, eValue, + NULL, NULL); + if (sslPrivKey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + } else { + if (privkey != NULL && + EVP_PKEY_set1_RSA(eprikey, sslPrivKey)) { + privkey->kstype = KMF_KEYSTORE_OPENSSL; + privkey->keyalg = KMF_RSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->israw = FALSE; + privkey->keylabel = (char *)strdup(fullpath); + privkey->keyp = (void *)eprikey; + } + /* OpenSSL derives the public key from the private */ + if (pubkey != NULL && + EVP_PKEY_set1_RSA(epubkey, sslPrivKey)) { + pubkey->kstype = KMF_KEYSTORE_OPENSSL; + pubkey->keyalg = KMF_RSA; + pubkey->israw = FALSE; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keylabel = (char *)strdup(fullpath); + pubkey->keyp = (void *)epubkey; + } + } + } else if (params->keytype == KMF_DSA) { + sslDSAKey = DSA_new(); + if (sslDSAKey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_MEMORY); + } + + if ((sslDSAKey->p = BN_bin2bn(P, sizeof (P), sslDSAKey->p)) == + NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + if ((sslDSAKey->q = BN_bin2bn(Q, sizeof (Q), sslDSAKey->q)) == + NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + if ((sslDSAKey->g = BN_bin2bn(G, sizeof (G), sslDSAKey->g)) == + NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + + if (!DSA_generate_key(sslDSAKey)) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_OPENSSL; + privkey->keyalg = KMF_DSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->israw = FALSE; + privkey->keylabel = (char *)strdup(fullpath); + if (EVP_PKEY_set1_DSA(eprikey, sslDSAKey)) { + privkey->keyp = (void *)eprikey; + } else { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + } + if (pubkey != NULL) { + DSA *dp = DSA_new(); + /* Make a copy for the public key */ + if (dp != NULL) { + if ((dp->p = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + DSA_free(dp); + goto cleanup; + } + if ((dp->q = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + BN_free(dp->p); + DSA_free(dp); + goto cleanup; + } + if ((dp->g = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + BN_free(dp->q); + BN_free(dp->p); + DSA_free(dp); + goto cleanup; + } + if ((dp->pub_key = BN_new()) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_MEMORY; + BN_free(dp->q); + BN_free(dp->p); + BN_free(dp->g); + DSA_free(dp); + goto cleanup; + } + (void) BN_copy(dp->p, sslDSAKey->p); + (void) BN_copy(dp->q, sslDSAKey->q); + (void) BN_copy(dp->g, sslDSAKey->g); + (void) BN_copy(dp->pub_key, sslDSAKey->pub_key); + + pubkey->kstype = KMF_KEYSTORE_OPENSSL; + pubkey->keyalg = KMF_DSA; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->israw = FALSE; + pubkey->keylabel = (char *)strdup(fullpath); + + if (EVP_PKEY_set1_DSA(epubkey, sslDSAKey)) { + pubkey->keyp = (void *)epubkey; + } else { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_KEYGEN_FAILED; + goto cleanup; + } + } + } + } + + if (rv != KMF_OK) { + goto cleanup; + } + + /* Store the private key to the keyfile */ + format = params->sslparms.format; + out = BIO_new_file(fullpath, "wb"); + if (out == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + rv = ssl_write_private_key(kmfh, format, out, ¶ms->cred, eprikey); + +cleanup: + if (rv != KMF_OK) { + if (eprikey != NULL) + EVP_PKEY_free(eprikey); + + if (epubkey != NULL) + EVP_PKEY_free(epubkey); + + if (pubkey->keylabel) { + free(pubkey->keylabel); + pubkey->keylabel = NULL; + } + + if (privkey->keylabel) { + free(privkey->keylabel); + privkey->keylabel = NULL; + } + + pubkey->keyp = NULL; + privkey->keyp = NULL; + } + + if (sslPrivKey) + RSA_free(sslPrivKey); + + if (sslDSAKey) + DSA_free(sslDSAKey); + + + if (out != NULL) + (void) BIO_free(out); + + if (fullpath) + free(fullpath); + + /* Protect the file by making it read-only */ + if (rv == KMF_OK) { + (void) chmod(fullpath, 0400); + } + return (rv); +} + +KMF_RETURN +OpenSSL_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *tobesigned, KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ALGORITHM_INDEX AlgId; + EVP_MD_CTX ctx; + const EVP_MD *md; + if (key == NULL || AlgOID == NULL || + tobesigned == NULL || output == NULL || + tobesigned->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the OID to an OpenSSL algorithm */ + AlgId = X509_AlgorithmOidToAlgId(AlgOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyalg == KMF_RSA) { + EVP_PKEY *pkey = (EVP_PKEY *)key->keyp; + uchar_t *p; + uint32_t len; + if (AlgId == KMF_ALGID_MD5WithRSA) + md = EVP_md5(); + else if (AlgId == KMF_ALGID_MD2WithRSA) + md = EVP_md2(); + else if (AlgId == KMF_ALGID_SHA1WithRSA) + md = EVP_sha1(); + else + return (KMF_ERR_BAD_PARAMETER); + + if (md == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + return (KMF_ERR_MEMORY); + } + + (void) EVP_MD_CTX_init(&ctx); + (void) EVP_SignInit_ex(&ctx, md, NULL); + (void) EVP_SignUpdate(&ctx, tobesigned->Data, + (uint32_t)tobesigned->Length); + len = (uint32_t)output->Length; + p = output->Data; + if (!EVP_SignFinal(&ctx, p, &len, pkey)) { + SET_ERROR(kmfh, ERR_get_error()); + output->Length = 0; + } + output->Length = len; + (void) EVP_MD_CTX_cleanup(&ctx); + } else if (key->keyalg == KMF_DSA) { + DSA *dsa = EVP_PKEY_get1_DSA(key->keyp); + + uchar_t hash[EVP_MAX_MD_SIZE]; + uint32_t hashlen; + DSA_SIG *dsasig; + + /* + * OpenSSL EVP_Sign operation automatically converts to + * ASN.1 output so we do the operations separately so we + * are assured of NOT getting ASN.1 output returned. + * KMF does not want ASN.1 encoded results because + * not all mechanisms return ASN.1 encodings (PKCS#11 + * and NSS return raw signature data). + */ + md = EVP_sha1(); + EVP_MD_CTX_init(&ctx); + (void) EVP_DigestInit_ex(&ctx, md, NULL); + (void) EVP_DigestUpdate(&ctx, tobesigned->Data, + tobesigned->Length); + (void) EVP_DigestFinal_ex(&ctx, hash, &hashlen); + (void) EVP_MD_CTX_cleanup(&ctx); + + dsasig = DSA_do_sign(hash, hashlen, dsa); + if (dsasig != NULL) { + int i; + output->Length = i = BN_bn2bin(dsasig->r, output->Data); + output->Length += BN_bn2bin(dsasig->s, + &output->Data[i]); + DSA_SIG_free(dsasig); + } else { + SET_ERROR(kmfh, ERR_get_error()); + } + } else { + return (KMF_ERR_BAD_PARAMETER); + } +cleanup: + return (ret); +} + +KMF_RETURN +/*ARGSUSED*/ +OpenSSL_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key, boolean_t destroy) +{ + KMF_RETURN rv = KMF_OK; + if (key == NULL || key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyclass != KMF_ASYM_PUB && + key->keyclass != KMF_ASYM_PRI && + key->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (key->keyclass == KMF_SYMMETRIC) { + KMF_FreeRawSymKey((KMF_RAW_SYM_KEY *)key->keyp); + key->keyp = NULL; + } else { + if (key->keyp != NULL) { + EVP_PKEY_free(key->keyp); + key->keyp = NULL; + } + } + + if (key->keylabel != NULL) { + EVP_PKEY *pkey = NULL; + /* If the file exists, make sure it is a proper key. */ + pkey = openssl_load_key(handle, key->keylabel); + if (pkey == NULL) { + free(key->keylabel); + key->keylabel = NULL; + return (KMF_ERR_KEY_NOT_FOUND); + } + EVP_PKEY_free(pkey); + + if (destroy) { + if (unlink(key->keylabel) != 0) { + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + SET_SYS_ERROR(kmfh, errno); + rv = KMF_ERR_INTERNAL; + } + } + if (key->keylabel != NULL) { + free(key->keylabel); + key->keylabel = NULL; + } + } + return (rv); +} + +KMF_RETURN +OpenSSL_ImportCRL(KMF_HANDLE_T handle, KMF_IMPORTCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509_CRL *xcrl = NULL; + X509 *xcert = NULL; + EVP_PKEY *pkey; + KMF_ENCODE_FORMAT format; + BIO *in = NULL, *out = NULL; + int openssl_ret = 0; + char *outcrlfile = NULL; + KMF_ENCODE_FORMAT outformat; + + if (params == NULL || params->sslparms.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (params->sslparms.crl_check == B_TRUE && + params->sslparms.certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + outcrlfile = get_fullpath(params->sslparms.dirpath, + params->sslparms.outcrlfile); + + if (outcrlfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(outcrlfile)) { + free(outcrlfile); + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format); + if (ret != KMF_OK) { + free(outcrlfile); + return (ret); + } + + in = BIO_new_file(params->sslparms.crlfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto end; + } + + /* If bypasscheck is specified, no need to verify. */ + if (params->sslparms.crl_check == B_FALSE) { + goto output; + } + + ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format); + if (ret != KMF_OK) + goto end; + + /* Read in the CA cert file and convert to X509 */ + if (BIO_read_filename(in, params->sslparms.certfile) <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcert = d2i_X509_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcert = PEM_read_bio_X509(in, NULL, NULL, NULL); + } else { + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto end; + } + /* Now get the public key from the CA cert */ + pkey = X509_get_pubkey(xcert); + if (!pkey) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERTFILE; + goto end; + } + + /* Verify the CRL with the CA's public key */ + openssl_ret = X509_CRL_verify(xcrl, pkey); + EVP_PKEY_free(pkey); + if (openssl_ret > 0) { + ret = KMF_OK; /* verify succeed */ + } else { + SET_ERROR(kmfh, openssl_ret); + ret = KMF_ERR_BAD_CRLFILE; + } + +output: + outformat = params->sslparms.format; + + out = BIO_new_file(outcrlfile, "wb"); + if (out == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (outformat == KMF_FORMAT_ASN1) { + openssl_ret = (int)i2d_X509_CRL_bio(out, xcrl); + } else if (outformat == KMF_FORMAT_PEM) { + openssl_ret = PEM_write_bio_X509_CRL(out, xcrl); + } else { + ret = KMF_ERR_BAD_PARAMETER; + goto end; + } + + if (openssl_ret <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_WRITE_FILE; + } else { + ret = KMF_OK; + } + +end: + if (xcrl != NULL) + X509_CRL_free(xcrl); + + if (xcert != NULL) + X509_free(xcert); + + if (in != NULL) + (void) BIO_free(in); + + if (out != NULL) + (void) BIO_free(out); + + if (outcrlfile != NULL) + free(outcrlfile); + + return (ret); +} + +KMF_RETURN +OpenSSL_ListCRL(KMF_HANDLE_T handle, KMF_LISTCRL_PARAMS *params, + char **crldata) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509_CRL *x = NULL; + KMF_ENCODE_FORMAT format; + char *crlfile = NULL; + BIO *in = NULL; + BIO *mem = NULL; + long len; + char *memptr; + char *data = NULL; + + if (params == NULL || params->sslparms.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + crlfile = get_fullpath(params->sslparms.dirpath, + params->sslparms.crlfile); + + if (crlfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(crlfile)) { + free(crlfile); + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, crlfile, &format); + if (ret != KMF_OK) { + free(crlfile); + return (ret); + } + + if (bio_err == NULL) + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + + in = BIO_new_file(crlfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + x = d2i_X509_CRL_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + } + + if (x == NULL) { /* should not happen */ + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_MEMORY; + goto end; + } + + (void) X509_CRL_print(mem, x); + len = BIO_get_mem_data(mem, &memptr); + if (len <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_MEMORY; + goto end; + } + + data = malloc(len + 1); + if (data == NULL) { + ret = KMF_ERR_MEMORY; + goto end; + } + + (void) memcpy(data, memptr, len); + data[len] = '\0'; + *crldata = data; + +end: + if (x != NULL) + X509_CRL_free(x); + + if (crlfile != NULL) + free(crlfile); + + if (in != NULL) + (void) BIO_free(in); + + if (mem != NULL) + (void) BIO_free(mem); + + return (ret); +} + +KMF_RETURN +OpenSSL_DeleteCRL(KMF_HANDLE_T handle, KMF_DELETECRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + char *crlfile = NULL; + BIO *in = NULL; + + if (params == NULL || params->sslparms.crlfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + crlfile = get_fullpath(params->sslparms.dirpath, + params->sslparms.crlfile); + + if (crlfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(crlfile)) { + ret = KMF_ERR_BAD_PARAMETER; + goto end; + } + + ret = KMF_IsCRLFile(handle, crlfile, &format); + if (ret != KMF_OK) + goto end; + + if (unlink(crlfile) != 0) { + SET_SYS_ERROR(kmfh, errno); + ret = KMF_ERR_INTERNAL; + goto end; + } + +end: + if (in != NULL) + (void) BIO_free(in); + if (crlfile != NULL) + free(crlfile); + + return (ret); +} + + +KMF_RETURN +OpenSSL_FindCertInCRL(KMF_HANDLE_T handle, KMF_FINDCERTINCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + BIO *in = NULL; + X509 *xcert = NULL; + X509_CRL *xcrl = NULL; + STACK_OF(X509_REVOKED) *revoke_stack = NULL; + X509_REVOKED *revoke; + int i; + + if (params == NULL || params->sslparms.crlfile == NULL || + params->sslparms.certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, params->sslparms.crlfile, &format); + if (ret != KMF_OK) + return (ret); + + /* Read the CRL file and load it into a X509_CRL structure */ + in = BIO_new_file(params->sslparms.crlfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto end; + } + (void) BIO_free(in); + + /* Read the Certificate file and load it into a X509 structure */ + ret = KMF_IsCertFile(handle, params->sslparms.certfile, &format); + if (ret != KMF_OK) + goto end; + + in = BIO_new_file(params->sslparms.certfile, "rb"); + if (in == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + + if (format == KMF_FORMAT_ASN1) { + xcert = d2i_X509_bio(in, NULL); + } else if (format == KMF_FORMAT_PEM) { + xcert = PEM_read_bio_X509(in, NULL, NULL, NULL); + } + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERTFILE; + goto end; + } + + /* Check if the certificate and the CRL have same issuer */ + if (X509_NAME_cmp(xcert->cert_info->issuer, xcrl->crl->issuer) != 0) { + ret = KMF_ERR_ISSUER; + goto end; + } + + /* Check to see if the certificate serial number is revoked */ + revoke_stack = X509_CRL_get_REVOKED(xcrl); + if (sk_X509_REVOKED_num(revoke_stack) <= 0) { + /* No revoked certificates in the CRL file */ + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_EMPTY_CRL; + goto end; + } + + for (i = 0; i < sk_X509_REVOKED_num(revoke_stack); i++) { + /*LINTED*/ + revoke = sk_X509_REVOKED_value(revoke_stack, i); + if (ASN1_INTEGER_cmp(xcert->cert_info->serialNumber, + revoke->serialNumber) == 0) { + break; + } + } + + if (i < sk_X509_REVOKED_num(revoke_stack)) { + ret = KMF_OK; + } else { + ret = KMF_ERR_NOT_REVOKED; + } + +end: + if (in != NULL) + (void) BIO_free(in); + if (xcrl != NULL) + X509_CRL_free(xcrl); + if (xcert != NULL) + X509_free(xcert); + + return (ret); +} + +KMF_RETURN +OpenSSL_GetErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char str[256]; /* OpenSSL needs at least 120 byte buffer */ + + ERR_error_string_n(kmfh->lasterr.errcode, str, sizeof (str)); + if (strlen(str)) { + *msgstr = (char *)strdup(str); + if ((*msgstr) == NULL) + ret = KMF_ERR_MEMORY; + } else { + *msgstr = NULL; + } + + return (ret); +} + +static int +ext2NID(int kmfext) +{ + switch (kmfext) { + case KMF_X509_EXT_KEY_USAGE: + return (NID_key_usage); + case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD: + return (NID_private_key_usage_period); + case KMF_X509_EXT_CERT_POLICIES: + return (NID_certificate_policies); + case KMF_X509_EXT_SUBJ_ALTNAME: + return (NID_subject_alt_name); + case KMF_X509_EXT_ISSUER_ALTNAME: + return (NID_issuer_alt_name); + case KMF_X509_EXT_BASIC_CONSTRAINTS: + return (NID_basic_constraints); + case KMF_X509_EXT_EXT_KEY_USAGE: + return (NID_ext_key_usage); + case KMF_X509_EXT_AUTH_KEY_ID: + return (NID_authority_key_identifier); + case KMF_X509_EXT_CRL_DIST_POINTS: + return (NID_crl_distribution_points); + case KMF_X509_EXT_SUBJ_KEY_ID: + return (NID_subject_key_identifier); + case KMF_X509_EXT_POLICY_MAPPINGS: + return (OBJ_sn2nid("policyMappings")); + case KMF_X509_EXT_NAME_CONSTRAINTS: + return (OBJ_sn2nid("nameConstraints")); + case KMF_X509_EXT_POLICY_CONSTRAINTS: + return (OBJ_sn2nid("policyConstraints")); + case KMF_X509_EXT_INHIBIT_ANY_POLICY: + return (OBJ_sn2nid("inhibitAnyPolicy")); + case KMF_X509_EXT_FRESHEST_CRL: + return (OBJ_sn2nid("freshestCRL")); + default: + return (NID_undef); + } +} + +KMF_RETURN +OpenSSL_CertGetPrintable(KMF_HANDLE_T handle, const KMF_DATA *pcert, + KMF_PRINTABLE_ITEM flag, char *resultStr) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *xcert = NULL; + unsigned char *outbuf = NULL; + unsigned char *outbuf_p; + char *tmpstr = NULL; + int j; + int ext_index, nid, len; + BIO *mem = NULL; + STACK *emlst = NULL; + X509_EXTENSION *ex; + X509_CINF *ci; + + if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* copy cert data to outbuf */ + outbuf = malloc(pcert->Length); + if (outbuf == NULL) { + return (KMF_ERR_MEMORY); + } + (void) memcpy(outbuf, pcert->Data, pcert->Length); + + outbuf_p = outbuf; /* use a temp pointer; required by openssl */ + xcert = d2i_X509(NULL, (const uchar_t **)&outbuf_p, pcert->Length); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_MEMORY; + goto out; + } + + switch (flag) { + case KMF_CERT_ISSUER: + (void) X509_NAME_print_ex(mem, X509_get_issuer_name(xcert), 0, + XN_FLAG_SEP_CPLUS_SPC); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_SUBJECT: + (void) X509_NAME_print_ex(mem, X509_get_subject_name(xcert), 0, + XN_FLAG_SEP_CPLUS_SPC); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_VERSION: + tmpstr = i2s_ASN1_INTEGER(NULL, xcert->cert_info->version); + (void) strncpy(resultStr, tmpstr, KMF_CERT_PRINTABLE_LEN); + OPENSSL_free(tmpstr); + len = strlen(resultStr); + break; + + case KMF_CERT_SERIALNUM: + if (i2a_ASN1_INTEGER(mem, X509_get_serialNumber(xcert)) > 0) { + (void) strcpy(resultStr, "0x"); + len = BIO_gets(mem, &resultStr[2], + KMF_CERT_PRINTABLE_LEN - 2); + } + break; + + case KMF_CERT_NOTBEFORE: + (void) ASN1_TIME_print(mem, X509_get_notBefore(xcert)); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_NOTAFTER: + (void) ASN1_TIME_print(mem, X509_get_notAfter(xcert)); + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + + case KMF_CERT_PUBKEY_DATA: + { + EVP_PKEY *pkey = X509_get_pubkey(xcert); + if (pkey == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + + if (pkey->type == EVP_PKEY_RSA) { + (void) BIO_printf(mem, + "RSA Public Key: (%d bit)\n", + BN_num_bits(pkey->pkey.rsa->n)); + (void) RSA_print(mem, pkey->pkey.rsa, 0); + } else if (pkey->type == EVP_PKEY_DSA) { + (void) BIO_printf(mem, + "%12sDSA Public Key:\n", ""); + (void) DSA_print(mem, pkey->pkey.dsa, 0); + } else { + (void) BIO_printf(mem, + "%12sUnknown Public Key:\n", ""); + } + (void) BIO_printf(mem, "\n"); + EVP_PKEY_free(pkey); + } + len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + break; + case KMF_CERT_SIGNATURE_ALG: + case KMF_CERT_PUBKEY_ALG: + if (flag == KMF_CERT_SIGNATURE_ALG) { + len = i2a_ASN1_OBJECT(mem, + xcert->sig_alg->algorithm); + } else { + len = i2a_ASN1_OBJECT(mem, + xcert->cert_info->key->algor->algorithm); + } + + if (len > 0) { + len = BIO_read(mem, resultStr, + KMF_CERT_PRINTABLE_LEN); + } + break; + + case KMF_CERT_EMAIL: + emlst = X509_get1_email(xcert); + for (j = 0; j < sk_num(emlst); j++) + (void) BIO_printf(mem, "%s\n", sk_value(emlst, j)); + + len = BIO_gets(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + X509_email_free(emlst); + break; + case KMF_X509_EXT_ISSUER_ALTNAME: + case KMF_X509_EXT_SUBJ_ALTNAME: + case KMF_X509_EXT_KEY_USAGE: + case KMF_X509_EXT_PRIV_KEY_USAGE_PERIOD: + case KMF_X509_EXT_CERT_POLICIES: + case KMF_X509_EXT_BASIC_CONSTRAINTS: + case KMF_X509_EXT_NAME_CONSTRAINTS: + case KMF_X509_EXT_POLICY_CONSTRAINTS: + case KMF_X509_EXT_EXT_KEY_USAGE: + case KMF_X509_EXT_INHIBIT_ANY_POLICY: + case KMF_X509_EXT_AUTH_KEY_ID: + case KMF_X509_EXT_SUBJ_KEY_ID: + case KMF_X509_EXT_POLICY_MAPPINGS: + case KMF_X509_EXT_CRL_DIST_POINTS: + case KMF_X509_EXT_FRESHEST_CRL: + nid = ext2NID(flag); + if (nid == NID_undef) { + ret = KMF_ERR_EXTENSION_NOT_FOUND; + goto out; + } + ci = xcert->cert_info; + + ext_index = X509v3_get_ext_by_NID(ci->extensions, nid, -1); + if (ext_index == -1) { + SET_ERROR(kmfh, ERR_get_error()); + + ret = KMF_ERR_EXTENSION_NOT_FOUND; + goto out; + } + ex = X509v3_get_ext(ci->extensions, ext_index); + + (void) i2a_ASN1_OBJECT(mem, X509_EXTENSION_get_object(ex)); + + if (BIO_printf(mem, ": %s\n", + X509_EXTENSION_get_critical(ex) ? "critical" : "") <= + 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + if (!X509V3_EXT_print(mem, ex, X509V3_EXT_DUMP_UNKNOWN, 4)) { + (void) BIO_printf(mem, "%*s", 4, ""); + (void) M_ASN1_OCTET_STRING_print(mem, ex->value); + } + if (BIO_write(mem, "\n", 1) <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + goto out; + } + len = BIO_read(mem, resultStr, KMF_CERT_PRINTABLE_LEN); + } + if (len <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_ENCODING; + } + +out: + if (outbuf != NULL) { + free(outbuf); + } + + if (xcert != NULL) { + X509_free(xcert); + } + + if (mem != NULL) { + (void) BIO_free(mem); + } + + return (ret); +} +KMF_RETURN +/*ARGSUSED*/ +OpenSSL_GetPrikeyByCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key, + KMF_KEY_ALG keytype) +{ + KMF_RETURN rv = KMF_OK; + KMF_FINDKEY_PARAMS fkparms; + uint32_t numkeys = 0; + + if (params == NULL && params->sslparms.keyfile == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * This is really just a FindKey operation, reuse the + * FindKey function. + */ + (void *)memset(&fkparms, 0, sizeof (fkparms)); + fkparms.kstype = KMF_KEYSTORE_OPENSSL; + fkparms.keyclass = KMF_ASYM_PRI; + fkparms.keytype = keytype; + fkparms.format = params->format; + fkparms.sslparms = params->sslparms; + + rv = OpenSSL_FindKey(handle, &fkparms, key, &numkeys); + + return (rv); +} + +KMF_RETURN +/*ARGSUSED*/ +OpenSSL_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *AlgOID, KMF_DATA *ciphertext, + KMF_DATA *output) +{ + KMF_RETURN ret = KMF_OK; + RSA *rsa = NULL; + unsigned int in_len = 0, out_len = 0; + unsigned int total_decrypted = 0, modulus_len = 0; + uint8_t *in_data, *out_data; + int i, blocks; + + if (key == NULL || AlgOID == NULL || + ciphertext == NULL || output == NULL || + ciphertext->Data == NULL || + output->Data == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyalg == KMF_RSA) { + rsa = EVP_PKEY_get1_RSA((EVP_PKEY *)key->keyp); + modulus_len = RSA_size(rsa); + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + blocks = ciphertext->Length/modulus_len; + out_data = output->Data; + in_data = ciphertext->Data; + out_len = modulus_len - 11; + in_len = modulus_len; + + for (i = 0; i < blocks; i++) { + out_len = RSA_private_decrypt(in_len, + in_data, out_data, rsa, RSA_PKCS1_PADDING); + + if (out_len == 0) { + ret = KMF_ERR_INTERNAL; + goto cleanup; + } + + out_data += out_len; + total_decrypted += out_len; + in_data += in_len; + } + + output->Length = total_decrypted; + +cleanup: + RSA_free(rsa); + if (ret != KMF_OK) + output->Length = 0; + + return (ret); + +} + +/* + * This function will create a certid from issuer_cert and user_cert. + * The caller should use OCSP_CERTID_free(OCSP_CERTID *) to deallocate + * certid memory after use. + */ +static KMF_RETURN +create_certid(KMF_HANDLE_T handle, const KMF_DATA *issuer_cert, + const KMF_DATA *user_cert, OCSP_CERTID **certid) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *issuer = NULL; + X509 *cert = NULL; + unsigned char *ptmp; + + if (issuer_cert == NULL || user_cert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* convert the DER-encoded issuer cert to an internal X509 */ + ptmp = issuer_cert->Data; + issuer = d2i_X509(NULL, (const uchar_t **)&ptmp, + issuer_cert->Length); + if (issuer == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_BAD_ISSUER; + goto end; + } + + /* convert the DER-encoded user cert to an internal X509 */ + ptmp = user_cert->Data; + cert = d2i_X509(NULL, (const uchar_t **)&ptmp, + user_cert->Length); + if (cert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + + ret = KMF_ERR_OCSP_BAD_CERT; + goto end; + } + + /* create a CERTID */ + *certid = OCSP_cert_to_id(NULL, cert, issuer); + if (*certid == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_CERTID; + goto end; + } + +end: + if (issuer != NULL) { + X509_free(issuer); + } + + if (cert != NULL) { + X509_free(cert); + } + + return (ret); +} + +KMF_RETURN +OpenSSL_CreateOCSPRequest(KMF_HANDLE_T handle, KMF_OCSPREQUEST_PARAMS *params, + char *reqfile) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + OCSP_CERTID *id = NULL; + OCSP_REQUEST *req = NULL; + BIO *derbio = NULL; + + if (params->user_cert == NULL || params->issuer_cert == NULL || + reqfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = create_certid(handle, params->issuer_cert, params->user_cert, + &id); + if (ret != KMF_OK) { + return (ret); + } + + /* Create an OCSP request */ + req = OCSP_REQUEST_new(); + if (req == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_CREATE_REQUEST; + goto end; + } + + if (!OCSP_request_add0_id(req, id)) { + ret = KMF_ERR_OCSP_CREATE_REQUEST; + goto end; + } + + /* Write the request to the output file with DER encoding */ + derbio = BIO_new_file(reqfile, "wb"); + if (!derbio) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto end; + } + if (i2d_OCSP_REQUEST_bio(derbio, req) <= 0) { + ret = KMF_ERR_ENCODING; + } + +end: + /* + * We don't need to free "id" explicitely, because OCSP_REQUEST_free() + * will deallocate certid's space also. + */ + if (req != NULL) { + OCSP_REQUEST_free(req); + } + + if (derbio != NULL) { + (void) BIO_free(derbio); + } + + return (ret); +} + +/* ocsp_find_signer_sk() is copied from openssl source */ +static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id) +{ + int i; + unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash; + + /* Easy if lookup by name */ + if (id->type == V_OCSP_RESPID_NAME) + return (X509_find_by_subject(certs, id->value.byName)); + + /* Lookup by key hash */ + + /* If key hash isn't SHA1 length then forget it */ + if (id->value.byKey->length != SHA_DIGEST_LENGTH) + return (NULL); + + keyhash = id->value.byKey->data; + /* Calculate hash of each key and compare */ + for (i = 0; i < sk_X509_num(certs); i++) { + /*LINTED*/ + X509 *x = sk_X509_value(certs, i); + (void) X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL); + if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH)) + return (x); + } + return (NULL); +} + +/* ocsp_find_signer() is copied from openssl source */ +/*ARGSUSED*/ +static int +ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, + X509_STORE *st, unsigned long flags) +{ + X509 *signer; + OCSP_RESPID *rid = bs->tbsResponseData->responderId; + if ((signer = ocsp_find_signer_sk(certs, rid))) { + *psigner = signer; + return (2); + } + if (!(flags & OCSP_NOINTERN) && + (signer = ocsp_find_signer_sk(bs->certs, rid))) { + *psigner = signer; + return (1); + } + /* Maybe lookup from store if by subject name */ + + *psigner = NULL; + return (0); +} + +/* + * This function will verify the signature of a basic response, using + * the public key from the OCSP responder certificate. + */ +static KMF_RETURN +check_response_signature(KMF_HANDLE_T handle, OCSP_BASICRESP *bs, + KMF_DATA *signer_cert, KMF_DATA *issuer_cert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + STACK_OF(X509) *cert_stack = NULL; + X509 *signer = NULL; + X509 *issuer = NULL; + EVP_PKEY *skey = NULL; + unsigned char *ptmp; + + + if (bs == NULL || issuer_cert == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Find the certificate that signed the basic response. + * + * If signer_cert is not NULL, we will use that as the signer cert. + * Otherwise, we will check if the issuer cert is actually the signer. + * If we still do not find a signer, we will look for it from the + * certificate list came with the response file. + */ + if (signer_cert != NULL) { + ptmp = signer_cert->Data; + signer = d2i_X509(NULL, (const uchar_t **)&ptmp, + signer_cert->Length); + if (signer == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_BAD_SIGNER; + goto end; + } + } else { + /* + * Convert the issuer cert into X509 and push it into a + * stack to be used by ocsp_find_signer(). + */ + ptmp = issuer_cert->Data; + issuer = d2i_X509(NULL, (const uchar_t **)&ptmp, + issuer_cert->Length); + if (issuer == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OCSP_BAD_ISSUER; + goto end; + } + + if ((cert_stack = sk_X509_new_null()) == NULL) { + ret = KMF_ERR_INTERNAL; + goto end; + } + + if (sk_X509_push(cert_stack, issuer) == NULL) { + ret = KMF_ERR_INTERNAL; + goto end; + } + + ret = ocsp_find_signer(&signer, bs, cert_stack, NULL, 0); + if (!ret) { + /* can not find the signer */ + ret = KMF_ERR_OCSP_BAD_SIGNER; + goto end; + } + } + + /* Verify the signature of the response */ + skey = X509_get_pubkey(signer); + if (skey == NULL) { + ret = KMF_ERR_OCSP_BAD_SIGNER; + goto end; + } + + ret = OCSP_BASICRESP_verify(bs, skey, 0); + if (ret == 0) { + ret = KMF_ERR_OCSP_RESPONSE_SIGNATURE; + goto end; + } + +end: + if (issuer != NULL) { + X509_free(issuer); + } + + if (signer != NULL) { + X509_free(signer); + } + + if (skey != NULL) { + EVP_PKEY_free(skey); + } + + if (cert_stack != NULL) { + sk_X509_free(cert_stack); + } + + return (ret); +} + + + +KMF_RETURN +OpenSSL_GetOCSPStatusForCert(KMF_HANDLE_T handle, + KMF_OCSPRESPONSE_PARAMS_INPUT *params_in, + KMF_OCSPRESPONSE_PARAMS_OUTPUT *params_out) +{ + KMF_RETURN ret = KMF_OK; + BIO *derbio = NULL; + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; + OCSP_CERTID *id = NULL; + OCSP_SINGLERESP *single = NULL; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int index, status, reason; + + if (params_in == NULL || params_in->issuer_cert == NULL || + params_in->user_cert == NULL || params_in->response == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + if (params_out == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* Read in the response */ + derbio = BIO_new_mem_buf(params_in->response->Data, + params_in->response->Length); + if (!derbio) { + ret = KMF_ERR_MEMORY; + return (ret); + } + + resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); + if (resp == NULL) { + ret = KMF_ERR_OCSP_MALFORMED_RESPONSE; + goto end; + } + + /* Check the response status */ + status = OCSP_response_status(resp); + params_out->response_status = status; + if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + ret = KMF_ERR_OCSP_RESPONSE_STATUS; + goto end; + } + +#ifdef DEBUG + printf("Successfully checked the response file status.\n"); +#endif /* DEBUG */ + + /* Extract basic response */ + bs = OCSP_response_get1_basic(resp); + if (bs == NULL) { + ret = KMF_ERR_OCSP_NO_BASIC_RESPONSE; + goto end; + } + +#ifdef DEBUG + printf("Successfully retrieved the basic response.\n"); +#endif /* DEBUG */ + + /* Check the basic response signature if required */ + if (params_in->ignore_response_sign == B_FALSE) { + ret = check_response_signature(handle, bs, + params_in->signer_cert, params_in->issuer_cert); + if (ret != KMF_OK) + goto end; + } + +#ifdef DEBUG + printf("Successfully verified the response signature.\n"); +#endif /* DEBUG */ + + /* Create a certid for the certificate in question */ + ret = create_certid(handle, params_in->issuer_cert, + params_in->user_cert, &id); + if (ret != KMF_OK) { + ret = KMF_ERR_OCSP_CERTID; + goto end; + } + +#ifdef DEBUG + printf("successfully created a certid for the cert.\n"); +#endif /* DEBUG */ + + /* Find the index of the single response for the certid */ + index = OCSP_resp_find(bs, id, -1); + if (index < 0) { + /* cound not find this certificate in the response */ + ret = KMF_ERR_OCSP_UNKNOWN_CERT; + goto end; + } + +#ifdef DEBUG + printf("Successfully found the single response index for the cert.\n"); +#endif /* DEBUG */ + + /* Retrieve the single response and get the cert status */ + single = OCSP_resp_get0(bs, index); + status = OCSP_single_get0_status(single, &reason, &rev, &thisupd, + &nextupd); + if (status == V_OCSP_CERTSTATUS_GOOD) { + params_out->cert_status = OCSP_GOOD; + } else if (status == V_OCSP_CERTSTATUS_UNKNOWN) { + params_out->cert_status = OCSP_UNKNOWN; + } else { /* revoked */ + params_out->cert_status = OCSP_REVOKED; + params_out->reason = reason; + } + ret = KMF_OK; + + /* Verify the time */ + if (!OCSP_check_validity(thisupd, nextupd, 300, + params_in->response_lifetime)) { + ret = KMF_ERR_OCSP_STATUS_TIME_INVALID; + goto end; + } + +#ifdef DEBUG + printf("Successfully verify the time.\n"); +#endif /* DEBUG */ + +end: + if (derbio != NULL) + (void) BIO_free(derbio); + + if (resp != NULL) + OCSP_RESPONSE_free(resp); + + if (bs != NULL) + OCSP_BASICRESP_free(bs); + + if (id != NULL) + OCSP_CERTID_free(id); + + return (ret); +} + +static KMF_RETURN +fetch_key(KMF_HANDLE_T handle, char *path, + KMF_KEY_CLASS keyclass, KMF_KEY_HANDLE *key) +{ + KMF_RETURN rv = KMF_OK; + EVP_PKEY *pkey; + KMF_RAW_SYM_KEY *rkey = NULL; + + /* Make sure the requested file actually exists. */ + if (access(path, F_OK) != 0) { + return (KMF_ERR_KEY_NOT_FOUND); + } + + if (keyclass == KMF_ASYM_PRI || + keyclass == KMF_ASYM_PUB) { + pkey = openssl_load_key(handle, path); + if (pkey == NULL) { + return (KMF_ERR_KEY_NOT_FOUND); + } + if (key != NULL) { + if (pkey->type == EVP_PKEY_RSA) + key->keyalg = KMF_RSA; + else if (pkey->type == EVP_PKEY_DSA) + key->keyalg = KMF_DSA; + + key->kstype = KMF_KEYSTORE_OPENSSL; + key->keyclass = keyclass; + key->keyp = (void *)pkey; + key->israw = FALSE; + key->keylabel = path; + } else { + EVP_PKEY_free(pkey); + pkey = NULL; + } + } else if (keyclass == KMF_SYMMETRIC) { + KMF_ENCODE_FORMAT fmt; + /* + * If the file is a recognized format, + * then it is NOT a symmetric key. + */ + rv = KMF_GetFileFormat(path, &fmt); + if (rv == KMF_OK || fmt != 0) { + return (KMF_ERR_KEY_NOT_FOUND); + } else if (rv == KMF_ERR_ENCODING) { + /* + * If we don't know the encoding, + * it is probably a symmetric key. + */ + rv = KMF_OK; + } + + if (key != NULL) { + KMF_DATA keyvalue; + rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); + if (rkey == NULL) { + rv = KMF_ERR_MEMORY; + goto out; + } + + (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); + rv = KMF_ReadInputFile(handle, path, &keyvalue); + if (rv != KMF_OK) + goto out; + + rkey->keydata.len = keyvalue.Length; + rkey->keydata.val = keyvalue.Data; + + key->kstype = KMF_KEYSTORE_OPENSSL; + key->keyclass = keyclass; + key->israw = TRUE; + key->keylabel = path; + key->keyp = (void *)rkey; + } + } +out: + if (rv != KMF_OK) { + if (rkey != NULL) { + KMF_FreeRawSymKey(rkey); + } + if (pkey != NULL) + EVP_PKEY_free(pkey); + + if (key != NULL) { + key->keyalg = KMF_KEYALG_NONE; + key->keyclass = KMF_KEYCLASS_NONE; + key->keyp = NULL; + } + } + + return (rv); +} + +KMF_RETURN +OpenSSL_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *params, + KMF_KEY_HANDLE *key, uint32_t *numkeys) +{ + KMF_RETURN rv = KMF_OK; + char *fullpath = NULL; + + if (handle == NULL || params == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (params->keyclass != KMF_ASYM_PUB && + params->keyclass != KMF_ASYM_PRI && + params->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + *numkeys = 0; + + if (isdir(fullpath)) { + DIR *dirp; + struct dirent *dp; + int n = 0; + + /* open all files in the directory and attempt to read them */ + if ((dirp = opendir(fullpath)) == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + rewinddir(dirp); + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") && + strcmp(dp->d_name, "..")) { + char *fname; + + fname = get_fullpath(fullpath, + (char *)&dp->d_name); + + rv = fetch_key(handle, fname, + params->keyclass, + key ? &key[n] : NULL); + + if (rv == KMF_OK) + n++; + + if (rv != KMF_OK || key == NULL) + free(fname); + } + } + (void) closedir(dirp); + free(fullpath); + (*numkeys) = n; + } else { + rv = fetch_key(handle, fullpath, params->keyclass, key); + if (rv == KMF_OK) + (*numkeys) = 1; + + if (rv != KMF_OK || key == NULL) + free(fullpath); + } + + if ((*numkeys) == 0) + rv = KMF_ERR_KEY_NOT_FOUND; + + return (rv); +} + +#define HANDLE_PK12_ERROR { \ + SET_ERROR(kmfh, ERR_get_error()); \ + rv = KMF_ERR_ENCODING; \ + goto out; \ +} + +static KMF_RETURN +write_pkcs12(KMF_HANDLE *kmfh, + BIO *bio, + KMF_CREDENTIAL *cred, + EVP_PKEY *pkey, + X509 *sslcert) +{ + KMF_RETURN rv = KMF_OK; + STACK_OF(PKCS12_SAFEBAG) *bag_stack = NULL; + PKCS12_SAFEBAG *bag = NULL; + PKCS7 *cert_authsafe = NULL; + PKCS8_PRIV_KEY_INFO *p8 = NULL; + PKCS7 *key_authsafe = NULL; + STACK_OF(PKCS7) *authsafe_stack = NULL; + PKCS12 *p12_elem = NULL; + char *lab = NULL; + int lab_len = 0; + unsigned char keyid[EVP_MAX_MD_SIZE]; + unsigned int keyidlen = 0; + + /* Must have at least a cert OR a key */ + if (sslcert == NULL && pkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(keyid, 0, sizeof (keyid)); + /* + * Section 1: + * + * The first PKCS#12 container (safebag) will hold the certificates + * associated with this key. The result of this section is a + * PIN-encrypted PKCS#7 container (authsafe). If there are no + * certificates, there is no point in creating the "safebag" or the + * "authsafe" so we go to the next section. + */ + if (sslcert != NULL && pkey != NULL) { + if (X509_check_private_key(sslcert, pkey)) { + (void) X509_digest(sslcert, EVP_sha1(), keyid, + &keyidlen); + } else { + /* The key doesn't match the cert */ + HANDLE_PK12_ERROR + } + } + + bag_stack = sk_PKCS12_SAFEBAG_new_null(); + if (bag_stack == NULL) + return (KMF_ERR_MEMORY); + + if (sslcert != NULL) { + /* Convert cert from X509 struct to PKCS#12 bag */ + bag = PKCS12_x5092certbag(sslcert); + if (bag == NULL) { + HANDLE_PK12_ERROR + } + + /* Add the key id to the certificate bag. */ + if (keyidlen > 0 && + !PKCS12_add_localkeyid(bag, keyid, keyidlen)) { + HANDLE_PK12_ERROR + } + + /* Pile it on the bag_stack. */ + if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) { + HANDLE_PK12_ERROR + } +#if 0 + /* No support for CA certs yet */ + if (cacerts != NULL && ncacerts > 0) { + int i; + for (i = 0; i < ncacerts; i++) { + KMF_X509_DER_CERT *c = &cacerts[i]; + X509 *ca = NULL; + + uchar_t *p = (uchar_t *)c->certificate.Data; + ca = d2i_X509(NULL, &p, + c->certificate.Length); + if (ca == NULL) { + HANDLE_PK12_ERROR + } + /* Convert CA cert to PKCS#12 bag. */ + bag = PKCS12_x5092certbag(ca); + if (bag == NULL) { + sk_PKCS12_SAFEBAG_pop_free(bag_stack, + PKCS12_SAFEBAG_free); + HANDLE_PK12_ERROR + } + /* Pile it onto the bag_stack. */ + if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) { + HANDLE_PK12_ERROR + } + } + } +#endif + /* Turn bag_stack of certs into encrypted authsafe. */ + cert_authsafe = PKCS12_pack_p7encdata( + NID_pbe_WithSHA1And40BitRC2_CBC, + cred->cred, + cred->credlen, NULL, 0, + PKCS12_DEFAULT_ITER, + bag_stack); + + /* Clear away this bag_stack, we're done with it. */ + sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); + bag_stack = NULL; + + if (cert_authsafe == NULL) { + HANDLE_PK12_ERROR + } + } + /* + * Section 2: + * + * The second PKCS#12 container (safebag) will hold the private key + * that goes with the certificates above. The results of this section + * is an unencrypted PKCS#7 container (authsafe). If there is no + * private key, there is no point in creating the "safebag" or the + * "authsafe" so we go to the next section. + */ + if (pkey != NULL) { + p8 = EVP_PKEY2PKCS8(pkey); + if (p8 == NULL) { + HANDLE_PK12_ERROR + } + /* Put the shrouded key into a PKCS#12 bag. */ + bag = PKCS12_MAKE_SHKEYBAG( + NID_pbe_WithSHA1And3_Key_TripleDES_CBC, + cred->cred, cred->credlen, + NULL, 0, PKCS12_DEFAULT_ITER, p8); + + /* Clean up the PKCS#8 shrouded key, don't need it now. */ + PKCS8_PRIV_KEY_INFO_free(p8); + p8 = NULL; + + if (bag == NULL) { + HANDLE_PK12_ERROR + } + if (keyidlen && + !PKCS12_add_localkeyid(bag, keyid, keyidlen)) { + HANDLE_PK12_ERROR + } + if (lab != NULL) { + if (!PKCS12_add_friendlyname(bag, + (char *)lab, lab_len)) { + HANDLE_PK12_ERROR + } + } + /* Start a PKCS#12 safebag container for the private key. */ + bag_stack = sk_PKCS12_SAFEBAG_new_null(); + if (bag_stack == NULL) { + HANDLE_PK12_ERROR + } + + /* Pile on the private key on the bag_stack. */ + if (!sk_PKCS12_SAFEBAG_push(bag_stack, bag)) { + HANDLE_PK12_ERROR + } + key_authsafe = PKCS12_pack_p7data(bag_stack); + + /* Clear away this bag_stack, we're done with it. */ + sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); + bag_stack = NULL; + + if (key_authsafe == NULL) { + HANDLE_PK12_ERROR + } + } + /* + * Section 3: + * + * This is where the two PKCS#7 containers, one for the certificates + * and one for the private key, are put together into a PKCS#12 + * element. This final PKCS#12 element is written to the export file. + */ + + /* Start a PKCS#7 stack. */ + authsafe_stack = sk_PKCS7_new_null(); + if (authsafe_stack == NULL) { + HANDLE_PK12_ERROR + } + if (key_authsafe != NULL) { + if (!sk_PKCS7_push(authsafe_stack, key_authsafe)) { + HANDLE_PK12_ERROR + } + } + if (cert_authsafe != NULL) { + if (!sk_PKCS7_push(authsafe_stack, cert_authsafe)) { + HANDLE_PK12_ERROR + } + } + p12_elem = PKCS12_init(NID_pkcs7_data); + if (p12_elem == NULL) { + sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); + HANDLE_PK12_ERROR + } + + /* Put the PKCS#7 stack into the PKCS#12 element. */ + if (!PKCS12_pack_authsafes(p12_elem, authsafe_stack)) { + HANDLE_PK12_ERROR + } + /* Clear away the PKCS#7 stack, we're done with it. */ + sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); + authsafe_stack = NULL; + + /* Set the integrity MAC on the PKCS#12 element. */ + if (!PKCS12_set_mac(p12_elem, cred->cred, cred->credlen, + NULL, 0, PKCS12_DEFAULT_ITER, NULL)) { + HANDLE_PK12_ERROR + } + + /* Write the PKCS#12 element to the export file. */ + if (!i2d_PKCS12_bio(bio, p12_elem)) { + HANDLE_PK12_ERROR + } + + PKCS12_free(p12_elem); +out: + if (rv != KMF_OK) { + /* Clear away this bag_stack, we're done with it. */ + sk_PKCS12_SAFEBAG_pop_free(bag_stack, PKCS12_SAFEBAG_free); + sk_PKCS7_pop_free(authsafe_stack, PKCS7_free); + } + return (rv); +} + +static EVP_PKEY * +ImportRawRSAKey(KMF_RAW_RSA_KEY *key) +{ + RSA *rsa = NULL; + EVP_PKEY *newkey = NULL; + + if ((rsa = RSA_new()) == NULL) + return (NULL); + + if ((rsa->n = BN_bin2bn(key->mod.val, key->mod.len, rsa->n)) == NULL) + return (NULL); + + if ((rsa->e = BN_bin2bn(key->pubexp.val, key->pubexp.len, rsa->e)) == + NULL) + return (NULL); + + if (key->priexp.val != NULL) + if ((rsa->d = BN_bin2bn(key->priexp.val, key->priexp.len, + rsa->d)) == NULL) + return (NULL); + + if (key->prime1.val != NULL) + if ((rsa->p = BN_bin2bn(key->prime1.val, key->prime1.len, + rsa->p)) == NULL) + return (NULL); + + if (key->prime2.val != NULL) + if ((rsa->q = BN_bin2bn(key->prime2.val, key->prime2.len, + rsa->q)) == NULL) + return (NULL); + + if (key->exp1.val != NULL) + if ((rsa->dmp1 = BN_bin2bn(key->exp1.val, key->exp1.len, + rsa->dmp1)) == NULL) + return (NULL); + + if (key->exp2.val != NULL) + if ((rsa->dmq1 = BN_bin2bn(key->exp2.val, key->exp2.len, + rsa->dmq1)) == NULL) + return (NULL); + + if (key->coef.val != NULL) + if ((rsa->iqmp = BN_bin2bn(key->coef.val, key->coef.len, + rsa->iqmp)) == NULL) + return (NULL); + + if ((newkey = EVP_PKEY_new()) == NULL) + return (NULL); + + (void) EVP_PKEY_set1_RSA(newkey, rsa); + + /* The original key must be freed once here or it leaks memory */ + RSA_free(rsa); + + return (newkey); +} + +static EVP_PKEY * +ImportRawDSAKey(KMF_RAW_DSA_KEY *key) +{ + DSA *dsa = NULL; + EVP_PKEY *newkey = NULL; + + if ((dsa = DSA_new()) == NULL) + return (NULL); + + if ((dsa->p = BN_bin2bn(key->prime.val, key->prime.len, + dsa->p)) == NULL) + return (NULL); + + if ((dsa->q = BN_bin2bn(key->subprime.val, key->subprime.len, + dsa->q)) == NULL) + return (NULL); + + if ((dsa->g = BN_bin2bn(key->base.val, key->base.len, + dsa->g)) == NULL) + return (NULL); + + if ((dsa->priv_key = BN_bin2bn(key->value.val, key->value.len, + dsa->priv_key)) == NULL) + return (NULL); + + if ((newkey = EVP_PKEY_new()) == NULL) + return (NULL); + + (void) EVP_PKEY_set1_DSA(newkey, dsa); + + /* The original key must be freed once here or it leaks memory */ + DSA_free(dsa); + return (newkey); +} + +static KMF_RETURN +ExportPK12FromRawData(KMF_HANDLE_T handle, + KMF_CREDENTIAL *cred, + int numcerts, KMF_X509_DER_CERT *certlist, + int numkeys, KMF_KEY_HANDLE *keylist, + char *filename) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bio = NULL; + X509 *xcert = NULL; + EVP_PKEY *pkey = NULL; + int i; + + /* + * Open the output file. + */ + if ((bio = BIO_new_file(filename, "wb")) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (numcerts > 0 && numkeys > 0) { + for (i = 0; rv == KMF_OK && i < numcerts; i++) { + KMF_RAW_KEY_DATA *key = NULL; + const uchar_t *p = certlist[i].certificate.Data; + long len = certlist[i].certificate.Length; + + if (i < numkeys) { + key = (KMF_RAW_KEY_DATA *)keylist[i].keyp; + + if (key->keytype == KMF_RSA) { + pkey = ImportRawRSAKey( + &key->rawdata.rsa); + } else if (key->keytype == KMF_DSA) { + pkey = ImportRawDSAKey( + &key->rawdata.dsa); + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + } + + xcert = d2i_X509(NULL, &p, len); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_ENCODING; + } + /* Stick the key and the cert into a PKCS#12 file */ + rv = write_pkcs12(kmfh, bio, cred, pkey, xcert); + if (xcert) + X509_free(xcert); + if (pkey) + EVP_PKEY_free(pkey); + } + } + +cleanup: + + if (bio != NULL) + (void) BIO_free_all(bio); + + return (rv); +} + +KMF_RETURN +OpenSSL_ExportP12(KMF_HANDLE_T handle, + KMF_EXPORTP12_PARAMS *params, + int numcerts, KMF_X509_DER_CERT *certlist, + int numkeys, KMF_KEY_HANDLE *keylist, + char *filename) +{ + KMF_RETURN rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_FINDCERT_PARAMS fcargs; + BIO *bio = NULL; + X509 *xcert = NULL; + char *fullpath = NULL; + EVP_PKEY *pkey = NULL; + + /* + * First, find the certificate. + */ + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * If the caller already sent the raw keys and certs, + * shortcut the search and just export that + * data. + * + * One *may* export a key OR a cert by itself. + */ + if (certlist != NULL || keylist != NULL) { + rv = ExportPK12FromRawData(handle, + ¶ms->p12cred, + numcerts, certlist, + numkeys, keylist, + filename); + return (rv); + } + + if (params->sslparms.certfile != NULL) { + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.certfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + free(fullpath); + return (KMF_ERR_AMBIGUOUS_PATHNAME); + } + + (void *)memset(&fcargs, 0, sizeof (fcargs)); + fcargs.kstype = params->kstype; + fcargs.certLabel = params->certLabel; + fcargs.issuer = params->issuer; + fcargs.subject = params->subject; + fcargs.serial = params->serial; + fcargs.idstr = params->idstr; + fcargs.sslparms.dirpath = NULL; + fcargs.sslparms.certfile = fullpath; + fcargs.sslparms.format = params->sslparms.format; + + rv = load_X509cert(kmfh, &fcargs, fullpath, &xcert); + if (rv != KMF_OK) + goto end; + } + + /* + * Now find the private key. + */ + if (params->sslparms.keyfile != NULL) { + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (isdir(fullpath)) { + free(fullpath); + return (KMF_ERR_AMBIGUOUS_PATHNAME); + } + + pkey = openssl_load_key(handle, fullpath); + if (pkey == NULL) { + rv = KMF_ERR_KEY_NOT_FOUND; + goto end; + } + } + + /* + * Open the output file. + */ + if ((bio = BIO_new_file(filename, "wb")) == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto end; + } + + /* Stick the key and the cert into a PKCS#12 file */ + rv = write_pkcs12(kmfh, bio, ¶ms->p12cred, + pkey, xcert); + +end: + if (fullpath) + free(fullpath); + if (xcert) + X509_free(xcert); + if (pkey) + EVP_PKEY_free(pkey); + if (bio) + (void) BIO_free(bio); + + return (rv); +} + +/* + * Helper function to decrypt and parse PKCS#12 import file. + */ +static KMF_RETURN +extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen, + EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca) +/* ARGSUSED */ +{ + PKCS12 *pk12, *pk12_tmp; + EVP_PKEY *temp_pkey = NULL; + X509 *temp_cert = NULL; + STACK_OF(X509) *temp_ca = NULL; + + if ((pk12 = PKCS12_new()) == NULL) { + return (KMF_ERR_MEMORY); + } + + if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) { + /* This is ok; it seems to mean there is no more to read. */ + if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 && + ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG) + goto end_extract_pkcs12; + + PKCS12_free(pk12); + return (KMF_ERR_PKCS12_FORMAT); + } + pk12 = pk12_tmp; + + if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert, + &temp_ca) <= 0) { + PKCS12_free(pk12); + return (KMF_ERR_PKCS12_FORMAT); + } + +end_extract_pkcs12: + + *priv_key = temp_pkey; + *cert = temp_cert; + *ca = temp_ca; + + PKCS12_free(pk12); + return (KMF_OK); +} + +static KMF_RETURN +sslBN2KMFBN(BIGNUM *from, KMF_BIGINT *to) +{ + KMF_RETURN rv = KMF_OK; + uint32_t sz; + + sz = BN_num_bytes(from); + to->val = (uchar_t *)malloc(sz); + if (to->val == NULL) + return (KMF_ERR_MEMORY); + + if ((to->len = BN_bn2bin(from, to->val)) != sz) { + free(to->val); + to->val = NULL; + to->len = 0; + rv = KMF_ERR_MEMORY; + } + + return (rv); +} + +static KMF_RETURN +exportRawRSAKey(RSA *rsa, KMF_RAW_KEY_DATA *key) +{ + KMF_RETURN rv; + KMF_RAW_RSA_KEY *kmfkey = &key->rawdata.rsa; + + (void) memset(kmfkey, 0, sizeof (KMF_RAW_RSA_KEY)); + if ((rv = sslBN2KMFBN(rsa->n, &kmfkey->mod)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(rsa->e, &kmfkey->pubexp)) != KMF_OK) + goto cleanup; + + if (rsa->d != NULL) + if ((rv = sslBN2KMFBN(rsa->d, &kmfkey->priexp)) != KMF_OK) + goto cleanup; + + if (rsa->p != NULL) + if ((rv = sslBN2KMFBN(rsa->p, &kmfkey->prime1)) != KMF_OK) + goto cleanup; + + if (rsa->q != NULL) + if ((rv = sslBN2KMFBN(rsa->q, &kmfkey->prime2)) != KMF_OK) + goto cleanup; + + if (rsa->dmp1 != NULL) + if ((rv = sslBN2KMFBN(rsa->dmp1, &kmfkey->exp1)) != KMF_OK) + goto cleanup; + + if (rsa->dmq1 != NULL) + if ((rv = sslBN2KMFBN(rsa->dmq1, &kmfkey->exp2)) != KMF_OK) + goto cleanup; + + if (rsa->iqmp != NULL) + if ((rv = sslBN2KMFBN(rsa->iqmp, &kmfkey->coef)) != KMF_OK) + goto cleanup; +cleanup: + if (rv != KMF_OK) + KMF_FreeRawKey(key); + else + key->keytype = KMF_RSA; + + /* + * Free the reference to this key, SSL will not actually free + * the memory until the refcount == 0, so this is safe. + */ + RSA_free(rsa); + + return (rv); +} + +static KMF_RETURN +exportRawDSAKey(DSA *dsa, KMF_RAW_KEY_DATA *key) +{ + KMF_RETURN rv; + KMF_RAW_DSA_KEY *kmfkey = &key->rawdata.dsa; + + (void) memset(kmfkey, 0, sizeof (KMF_RAW_DSA_KEY)); + if ((rv = sslBN2KMFBN(dsa->p, &kmfkey->prime)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(dsa->q, &kmfkey->subprime)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(dsa->g, &kmfkey->base)) != KMF_OK) + goto cleanup; + + if ((rv = sslBN2KMFBN(dsa->priv_key, &kmfkey->value)) != KMF_OK) + goto cleanup; + +cleanup: + if (rv != KMF_OK) + KMF_FreeRawKey(key); + else + key->keytype = KMF_DSA; + + /* + * Free the reference to this key, SSL will not actually free + * the memory until the refcount == 0, so this is safe. + */ + DSA_free(dsa); + + return (rv); +} + +static KMF_RETURN +add_cert_to_list(KMF_HANDLE *kmfh, X509 *sslcert, + KMF_DATA **certlist, int *ncerts) +{ + KMF_RETURN rv = KMF_OK; + KMF_DATA *list = (*certlist); + KMF_DATA cert; + int n = (*ncerts); + + if (list == NULL) { + list = (KMF_DATA *)malloc(sizeof (KMF_DATA)); + } else { + list = (KMF_DATA *)realloc(list, sizeof (KMF_DATA) * (n + 1)); + } + + if (list == NULL) + return (KMF_ERR_MEMORY); + + rv = ssl_cert2KMFDATA(kmfh, sslcert, &cert); + if (rv == KMF_OK) { + list[n] = cert; + (*ncerts) = n + 1; + + *certlist = list; + } else { + free(list); + } + + return (rv); +} + +static KMF_RETURN +add_key_to_list(KMF_RAW_KEY_DATA **keylist, + KMF_RAW_KEY_DATA *newkey, int *nkeys) +{ + KMF_RAW_KEY_DATA *list = (*keylist); + int n = (*nkeys); + + if (list == NULL) { + list = (KMF_RAW_KEY_DATA *)malloc(sizeof (KMF_RAW_KEY_DATA)); + } else { + list = (KMF_RAW_KEY_DATA *)realloc(list, + sizeof (KMF_RAW_KEY_DATA) * (n + 1)); + } + + if (list == NULL) + return (KMF_ERR_MEMORY); + + list[n] = *newkey; + (*nkeys) = n + 1; + + *keylist = list; + + return (KMF_OK); +} + + +static KMF_RETURN +convertPK12Objects( + KMF_HANDLE *kmfh, + EVP_PKEY *sslkey, X509 *sslcert, STACK_OF(X509) *sslcacerts, + KMF_RAW_KEY_DATA **keylist, int *nkeys, + KMF_DATA **certlist, int *ncerts) +{ + KMF_RETURN rv = KMF_OK; + KMF_RAW_KEY_DATA key; + int i; + + if (sslkey != NULL) { + /* Convert SSL key to raw key */ + switch (sslkey->type) { + case EVP_PKEY_RSA: + rv = exportRawRSAKey(EVP_PKEY_get1_RSA(sslkey), + &key); + if (rv != KMF_OK) + return (rv); + + break; + case EVP_PKEY_DSA: + rv = exportRawDSAKey(EVP_PKEY_get1_DSA(sslkey), + &key); + if (rv != KMF_OK) + return (rv); + + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + rv = add_key_to_list(keylist, &key, nkeys); + if (rv != KMF_OK) + return (rv); + } + + /* Now add the certificate to the certlist */ + if (sslcert != NULL) { + rv = add_cert_to_list(kmfh, sslcert, certlist, ncerts); + if (rv != KMF_OK) + return (rv); + } + + /* Also add any included CA certs to the list */ + for (i = 0; i != sk_X509_num(sslcacerts); i++) { + X509 *c; + /* + * sk_X509_value() is macro that embeds a cast to (X509 *). + * Here it translates into ((X509 *)sk_value((ca), (i))). + * Lint is complaining about the embedded casting, and + * to fix it, you need to fix openssl header files. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + c = sk_X509_value(sslcacerts, i); + + /* Now add the ca cert to the certlist */ + rv = add_cert_to_list(kmfh, c, certlist, ncerts); + if (rv != KMF_OK) + return (rv); + } + return (rv); +} + +KMF_RETURN +openssl_read_pkcs12(KMF_HANDLE *kmfh, + char *filename, KMF_CREDENTIAL *cred, + KMF_DATA **certlist, int *ncerts, + KMF_RAW_KEY_DATA **keylist, int *nkeys) +{ + KMF_RETURN rv = KMF_OK; + BIO *bio = NULL; + EVP_PKEY *privkey = NULL; + X509 *cert = NULL; + STACK_OF(X509) *cacerts = NULL; + + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto end; + } + + *certlist = NULL; + *keylist = NULL; + *ncerts = 0; + *nkeys = 0; + while (rv == KMF_OK) { + rv = extract_pkcs12(bio, + (uchar_t *)cred->cred, + (uint32_t)cred->credlen, + &privkey, &cert, &cacerts); + + /* Reached end of import file? */ + if (rv == KMF_OK && privkey == NULL && + cert == NULL && cacerts == NULL) + break; + + if (rv == KMF_OK) + /* Convert keys and certs to exportable format */ + rv = convertPK12Objects(kmfh, privkey, cert, cacerts, + keylist, nkeys, certlist, ncerts); + + if (privkey) + EVP_PKEY_free(privkey); + + if (cert) + X509_free(cert); + + if (cacerts) + sk_X509_free(cacerts); + } +end: + if (bio != NULL) + (void) BIO_free(bio); + + if (privkey) + EVP_PKEY_free(privkey); + + if (cert) + X509_free(cert); + + if (cacerts) + sk_X509_free(cacerts); + + return (rv); +} + +KMF_RETURN +OpenSSL_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *key) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *fullpath; + EVP_PKEY *pkey = NULL; + BIO *bio = NULL; + + if (key != NULL) { + if (key->keytype == KMF_RSA) { + pkey = ImportRawRSAKey(&key->rawdata.rsa); + } else if (key->keytype == KMF_DSA) { + pkey = ImportRawDSAKey(&key->rawdata.dsa); + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + if (rv != KMF_OK || pkey == NULL) + return (rv); + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the requested file exists, return an error */ + if (access(fullpath, F_OK) == 0) { + free(fullpath); + return (KMF_ERR_DUPLICATE_KEYFILE); + } + + bio = BIO_new_file(fullpath, "wb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + rv = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + rv = ssl_write_private_key(kmfh, + params->sslparms.format, + bio, ¶ms->cred, pkey); + +cleanup: + if (fullpath) + free(fullpath); + + if (pkey) + EVP_PKEY_free(pkey); + + if (bio) + (void) BIO_free(bio); + + /* Protect the file by making it read-only */ + if (rv == KMF_OK) { + (void) chmod(fullpath, 0400); + } + return (rv); +} + +static KMF_RETURN +create_deskey(DES_cblock **deskey) +{ + DES_cblock *key; + + key = (DES_cblock *) malloc(sizeof (DES_cblock)); + if (key == NULL) { + return (KMF_ERR_MEMORY); + } + + if (DES_random_key(key) == 0) { + free(key); + return (KMF_ERR_KEYGEN_FAILED); + } + + *deskey = key; + return (KMF_OK); +} + +#define KEYGEN_RETRY 3 +#define DES3_KEY_SIZE 24 + +static KMF_RETURN +create_des3key(unsigned char **des3key) +{ + KMF_RETURN ret = KMF_OK; + DES_cblock *deskey1 = NULL; + DES_cblock *deskey2 = NULL; + DES_cblock *deskey3 = NULL; + unsigned char *newkey = NULL; + int retry; + + if ((newkey = malloc(DES3_KEY_SIZE)) == NULL) { + return (KMF_ERR_MEMORY); + } + + /* create the 1st DES key */ + if ((ret = create_deskey(&deskey1)) != KMF_OK) { + goto out; + } + + /* + * Create the 2nd DES key and make sure its value is different + * from the 1st DES key. + */ + retry = 0; + do { + if (deskey2 != NULL) { + free(deskey2); + deskey2 = NULL; + } + + if ((ret = create_deskey(&deskey2)) != KMF_OK) { + goto out; + } + + if (memcmp((const void *) deskey1, (const void *) deskey2, 8) + == 0) { + ret = KMF_ERR_KEYGEN_FAILED; + retry++; + } + } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY); + + if (ret != KMF_OK) { + goto out; + } + + /* + * Create the 3rd DES key and make sure its value is different + * from the 2nd DES key. + */ + retry = 0; + do { + if (deskey3 != NULL) { + free(deskey3); + deskey3 = NULL; + } + + if ((ret = create_deskey(&deskey3)) != KMF_OK) { + goto out; + } + + if (memcmp((const void *)deskey2, (const void *)deskey3, 8) + == 0) { + ret = KMF_ERR_KEYGEN_FAILED; + retry++; + } + } while (ret == KMF_ERR_KEYGEN_FAILED && retry < KEYGEN_RETRY); + + if (ret != KMF_OK) { + goto out; + } + + /* Concatenate 3 DES keys into a DES3 key */ + (void) memcpy((void *)newkey, (const void *)deskey1, 8); + (void) memcpy((void *)(newkey + 8), (const void *)deskey2, 8); + (void) memcpy((void *)(newkey + 16), (const void *)deskey3, 8); + *des3key = newkey; + +out: + if (deskey1 != NULL) + free(deskey1); + + if (deskey2 != NULL) + free(deskey2); + + if (deskey3 != NULL) + free(deskey3); + + if (ret != KMF_OK && newkey != NULL) + free(newkey); + + return (ret); +} + +KMF_RETURN +OpenSSL_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + char *fullpath = NULL; + KMF_RAW_SYM_KEY *rkey = NULL; + DES_cblock *deskey = NULL; + unsigned char *des3key = NULL; + unsigned char *random = NULL; + int fd = -1; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (params == NULL || params->sslparms.keyfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + fullpath = get_fullpath(params->sslparms.dirpath, + params->sslparms.keyfile); + if (fullpath == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* If the requested file exists, return an error */ + if (access(fullpath, F_OK) == 0) { + free(fullpath); + return (KMF_ERR_DUPLICATE_KEYFILE); + } + + fd = open(fullpath, O_CREAT|O_TRUNC|O_RDWR, 0400); + if (fd == -1) { + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + rkey = malloc(sizeof (KMF_RAW_SYM_KEY)); + if (rkey == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + (void) memset(rkey, 0, sizeof (KMF_RAW_SYM_KEY)); + + if (params->keytype == KMF_DES) { + if ((ret = create_deskey(&deskey)) != KMF_OK) { + goto out; + } + rkey->keydata.val = (uchar_t *)deskey; + rkey->keydata.len = 8; + + symkey->keyalg = KMF_DES; + + } else if (params->keytype == KMF_DES3) { + if ((ret = create_des3key(&des3key)) != KMF_OK) { + goto out; + } + rkey->keydata.val = (uchar_t *)des3key; + rkey->keydata.len = DES3_KEY_SIZE; + symkey->keyalg = KMF_DES3; + + } else if (params->keytype == KMF_AES || params->keytype == KMF_RC4) { + int bytes; + + if (params->keylength % 8 != 0) { + ret = KMF_ERR_BAD_KEY_SIZE; + goto out; + } + + if (params->keytype == KMF_AES) { + if (params->keylength != 128 && + params->keylength != 192 && + params->keylength != 256) { + ret = KMF_ERR_BAD_KEY_SIZE; + goto out; + } + } + + bytes = params->keylength/8; + random = malloc(bytes); + if (random == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + if (RAND_bytes(random, bytes) != 1) { + ret = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + rkey->keydata.val = (uchar_t *)random; + rkey->keydata.len = bytes; + symkey->keyalg = params->keytype; + + } else { + ret = KMF_ERR_BAD_KEY_TYPE; + goto out; + } + + (void) write(fd, (const void *) rkey->keydata.val, rkey->keydata.len); + + symkey->kstype = KMF_KEYSTORE_OPENSSL; + symkey->keyclass = KMF_SYMMETRIC; + symkey->keylabel = (char *)fullpath; + symkey->israw = TRUE; + symkey->keyp = rkey; + +out: + if (fd != -1) + (void) close(fd); + + if (ret != KMF_OK && fullpath != NULL) { + free(fullpath); + } + if (ret != KMF_OK) { + KMF_FreeRawSymKey(rkey); + symkey->keyp = NULL; + symkey->keyalg = KMF_KEYALG_NONE; + } + + return (ret); +} + + +KMF_RETURN +OpenSSL_VerifyCRLFile(KMF_HANDLE_T handle, KMF_VERIFYCRL_PARAMS *params) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bcrl = NULL; + X509_CRL *xcrl = NULL; + X509 *xcert = NULL; + EVP_PKEY *pkey; + int sslret; + KMF_ENCODE_FORMAT crl_format; + unsigned char *p; + long len; + + if (params->crl_name == NULL || params->tacert == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_GetFileFormat(params->crl_name, &crl_format); + if (ret != KMF_OK) + return (ret); + + bcrl = BIO_new_file(params->crl_name, "rb"); + if (bcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (crl_format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(bcrl, NULL); + } else if (crl_format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL); + } else { + ret = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto cleanup; + } + + p = params->tacert->Data; + len = params->tacert->Length; + xcert = d2i_X509(NULL, (const uchar_t **)&p, len); + + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERTFILE; + goto cleanup; + } + + /* Get issuer certificate public key */ + pkey = X509_get_pubkey(xcert); + if (!pkey) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + /* Verify CRL signature */ + sslret = X509_CRL_verify(xcrl, pkey); + EVP_PKEY_free(pkey); + if (sslret > 0) { + ret = KMF_OK; + } else { + SET_ERROR(kmfh, sslret); + ret = KMF_ERR_BAD_CRLFILE; + } + +cleanup: + if (bcrl != NULL) + (void) BIO_free(bcrl); + + if (xcrl != NULL) + X509_CRL_free(xcrl); + + if (xcert != NULL) + X509_free(xcert); + + return (ret); + +} + +KMF_RETURN +OpenSSL_CheckCRLDate(KMF_HANDLE_T handle, + KMF_CHECKCRLDATE_PARAMS *params) +{ + + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT crl_format; + BIO *bcrl = NULL; + X509_CRL *xcrl = NULL; + int i; + + if (params == NULL || params->crl_name == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_IsCRLFile(handle, params->crl_name, &crl_format); + if (ret != KMF_OK) + return (ret); + + bcrl = BIO_new_file(params->crl_name, "rb"); + if (bcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto cleanup; + } + + if (crl_format == KMF_FORMAT_ASN1) { + xcrl = d2i_X509_CRL_bio(bcrl, NULL); + } else if (crl_format == KMF_FORMAT_PEM) { + xcrl = PEM_read_bio_X509_CRL(bcrl, NULL, NULL, NULL); + } + + if (xcrl == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CRLFILE; + goto cleanup; + } + + i = X509_cmp_time(X509_CRL_get_lastUpdate(xcrl), NULL); + if (i >= 0) { + ret = KMF_ERR_VALIDITY_PERIOD; + goto cleanup; + } + + if (X509_CRL_get_nextUpdate(xcrl)) { + i = X509_cmp_time(X509_CRL_get_nextUpdate(xcrl), NULL); + + if (i <= 0) { + ret = KMF_ERR_VALIDITY_PERIOD; + goto cleanup; + } + } + + ret = KMF_OK; + +cleanup: + if (bcrl != NULL) + (void) BIO_free(bcrl); + + if (xcrl != NULL) + X509_CRL_free(xcrl); + + return (ret); +} + +/* + * Check a file to see if it is a CRL file with PEM or DER format. + * If success, return its format in the "pformat" argument. + */ +KMF_RETURN +OpenSSL_IsCRLFile(KMF_HANDLE_T handle, char *filename, int *pformat) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bio = NULL; + X509_CRL *xcrl = NULL; + + if (filename == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + if ((xcrl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) != NULL) { + *pformat = KMF_FORMAT_PEM; + goto out; + } + (void) BIO_free(bio); + + /* + * Now try to read it as raw DER data. + */ + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + if ((xcrl = d2i_X509_CRL_bio(bio, NULL)) != NULL) { + *pformat = KMF_FORMAT_ASN1; + } else { + ret = KMF_ERR_BAD_CRLFILE; + } + +out: + if (bio != NULL) + (void) BIO_free(bio); + + if (xcrl != NULL) + X509_CRL_free(xcrl); + + return (ret); +} + +/* + * Check a file to see if it is a certficate file with PEM or DER format. + * If success, return its format in the pformat argument. + */ +KMF_RETURN +OpenSSL_IsCertFile(KMF_HANDLE_T handle, char *filename, + KMF_ENCODE_FORMAT *pformat) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + BIO *bio = NULL; + X509 *xcert = NULL; + + if (filename == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + ret = KMF_GetFileFormat(filename, pformat); + if (ret != KMF_OK) + return (ret); + + bio = BIO_new_file(filename, "rb"); + if (bio == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_OPEN_FILE; + goto out; + } + + if ((*pformat) == KMF_FORMAT_PEM) { + if ((xcert = PEM_read_bio_X509(bio, NULL, + NULL, NULL)) == NULL) { + ret = KMF_ERR_BAD_CERTFILE; + } + } else if ((*pformat) == KMF_FORMAT_ASN1) { + if ((xcert = d2i_X509_bio(bio, NULL)) == NULL) { + ret = KMF_ERR_BAD_CERTFILE; + } + } else { + ret = KMF_ERR_BAD_CERTFILE; + } + +out: + if (bio != NULL) + (void) BIO_free(bio); + + if (xcert != NULL) + X509_free(xcert); + + return (ret); +} + +KMF_RETURN +OpenSSL_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_DATA keyvalue; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + else if (symkey->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (symkey->israw) { + KMF_RAW_SYM_KEY *rawkey = (KMF_RAW_SYM_KEY *)symkey->keyp; + + if (rawkey == NULL || + rawkey->keydata.val == NULL || + rawkey->keydata.len == 0) + return (KMF_ERR_BAD_KEYHANDLE); + + rkey->keydata.len = rawkey->keydata.len; + if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(rkey->keydata.val, rawkey->keydata.val, + rkey->keydata.len); + } else { + rv = KMF_ReadInputFile(handle, symkey->keylabel, &keyvalue); + if (rv != KMF_OK) + return (rv); + rkey->keydata.len = keyvalue.Length; + rkey->keydata.val = keyvalue.Data; + } + + return (rv); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile new file mode 100644 index 0000000000..443f78537a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile new file mode 100644 index 0000000000..472ac90a9a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile new file mode 100644 index 0000000000..e80bb3751a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/sparcv9/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../../Makefile.lib.64 + +LDLIBS += $(OPENSSLLIBS64) +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile new file mode 100644 index 0000000000..b65a323ef5 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) + +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com new file mode 100644 index 0000000000..f2a715de92 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/Makefile.com @@ -0,0 +1,65 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Makefile for KMF Plugins +# + +LIBRARY= kmf_pkcs11.a +VERS= .1 +OBJECTS= pkcs11_spi.o + +include $(SRC)/lib/Makefile.lib + +LIBLINKS= $(DYNLIB:.so.1=.so) +KMFINC= -I../../../include -I../../../ber_der/inc + +PKCS11LIBS= -lkmf -lkmfberder -lpkcs11 -lcryptoutil -lc + +SRCDIR= ../common +INCDIR= ../../include + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT $(KMFINC) -I$(INCDIR) -I/usr/include/libxml2 + +PICS= $(OBJECTS:%=pics/%) +SONAME= $(PLUGIN) + +LDLIBS += $(PKCS11LIBS) + +ROOTLIBDIR= $(ROOT)/usr/lib/security +ROOTLIBDIR64= $(ROOT)/usr/lib/security/$(MACH64) + +.KEEP_STATE: + +LIBS = $(DYNLIB) + +all: $(LIBS) $(LINTLIB) + +lint: lintcheck + +FRC: + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile new file mode 100644 index 0000000000..dfd8150806 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/amd64/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers new file mode 100644 index 0000000000..ee3b6bcb92 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/mapfile-vers @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + KMF_Plugin_Initialize; + KMFPK11_FindCert; + KMFPK11_FreeKMFCert; + KMFPK11_StoreCert; + KMFPK11_ImportCert; + KMFPK11_DeleteCert; + KMFPK11_CreateKeypair; + KMFPK11_FindKey; + KMFPK11_EncodePubKeyData; + KMFPK11_SignData; + KMFPK11_DeleteKey; + KMFPK11_GetErrorString; + KMFPK11_GetPrikeyByCert; + KMFPK11_DecryptData; + KMFPK11_StorePrivateKey; + KMFPK11_CreateSymKey; + KMFPK11_GetSymKeyValue; + KMFPK11_SetTokenPin; + local: + *; +}; diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c new file mode 100644 index 0000000000..e548c64eb8 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c @@ -0,0 +1,2945 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * PKCS11 token KMF Plugin + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> /* debugging only */ +#include <errno.h> +#include <values.h> + +#include <kmfapiP.h> +#include <oidsalg.h> +#include <ber_der.h> +#include <algorithm.h> + +#include <cryptoutil.h> +#include <security/cryptoki.h> +#include <security/pkcs11.h> + +#define SETATTR(t, n, atype, value, size) \ + t[n].type = atype; \ + t[n].pValue = (CK_BYTE *)value; \ + t[n].ulValueLen = (CK_ULONG)size; + +#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; \ + h->lasterr.errcode = c; + +typedef struct _objlist { + CK_OBJECT_HANDLE handle; + struct _objlist *next; +} OBJLIST; + +static KMF_RETURN +search_certs(KMF_HANDLE_T, char *, char *, char *, KMF_BIGINT *, + boolean_t, KMF_CERT_VALIDITY, OBJLIST **, uint32_t *); + +static KMF_RETURN +keyObj2RawKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_KEY_DATA **); + +KMF_RETURN +KMFPK11_ConfigureKeystore(KMF_HANDLE_T, KMF_CONFIG_PARAMS *); + +KMF_RETURN +KMFPK11_FindCert(KMF_HANDLE_T, + KMF_FINDCERT_PARAMS *, + KMF_X509_DER_CERT *, + uint32_t *); + +void +KMFPK11_FreeKMFCert(KMF_HANDLE_T, + KMF_X509_DER_CERT *kmf_cert); + +KMF_RETURN +KMFPK11_StoreCert(KMF_HANDLE_T, KMF_STORECERT_PARAMS *, KMF_DATA *); + +KMF_RETURN +KMFPK11_ImportCert(KMF_HANDLE_T, KMF_IMPORTCERT_PARAMS *); + +KMF_RETURN +KMFPK11_DeleteCert(KMF_HANDLE_T, KMF_DELETECERT_PARAMS *); + +KMF_RETURN +KMFPK11_CreateKeypair(KMF_HANDLE_T, KMF_CREATEKEYPAIR_PARAMS *, + KMF_KEY_HANDLE *, KMF_KEY_HANDLE *); + +KMF_RETURN +KMFPK11_DeleteKey(KMF_HANDLE_T, KMF_DELETEKEY_PARAMS *, + KMF_KEY_HANDLE *, boolean_t); + +KMF_RETURN +KMFPK11_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *); + +KMF_RETURN +KMFPK11_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +KMFPK11_GetErrorString(KMF_HANDLE_T, char **); + +KMF_RETURN +KMFPK11_GetPrikeyByCert(KMF_HANDLE_T, KMF_CRYPTOWITHCERT_PARAMS *, KMF_DATA *, + KMF_KEY_HANDLE *, KMF_KEY_ALG); + +KMF_RETURN +KMFPK11_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *, + KMF_DATA *, KMF_DATA *); + +KMF_RETURN +KMFPK11_FindKey(KMF_HANDLE_T, KMF_FINDKEY_PARAMS *, + KMF_KEY_HANDLE *, uint32_t *); + +KMF_RETURN +KMFPK11_StorePrivateKey(KMF_HANDLE_T, KMF_STOREKEY_PARAMS *, + KMF_RAW_KEY_DATA *); + +KMF_RETURN +KMFPK11_CreateSymKey(KMF_HANDLE_T, KMF_CREATESYMKEY_PARAMS *, + KMF_KEY_HANDLE *); + +KMF_RETURN +KMFPK11_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); + +KMF_RETURN +KMFPK11_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *); + +static +KMF_PLUGIN_FUNCLIST pk11token_plugin_table = +{ + 1, /* Version */ + KMFPK11_ConfigureKeystore, + KMFPK11_FindCert, + KMFPK11_FreeKMFCert, + KMFPK11_StoreCert, + KMFPK11_ImportCert, + NULL, /* ImportCRL */ + KMFPK11_DeleteCert, + NULL, /* DeleteCRL */ + KMFPK11_CreateKeypair, + KMFPK11_FindKey, + KMFPK11_EncodePubKeyData, + KMFPK11_SignData, + KMFPK11_DeleteKey, + NULL, /* ListCRL */ + NULL, /* FindCRL */ + NULL, /* FindCertInCRL */ + KMFPK11_GetErrorString, + KMFPK11_GetPrikeyByCert, + KMFPK11_DecryptData, + NULL, /* ExportP12 */ + KMFPK11_StorePrivateKey, + KMFPK11_CreateSymKey, + KMFPK11_GetSymKeyValue, + KMFPK11_SetTokenPin, + NULL /* Finalize */ +}; + +KMF_PLUGIN_FUNCLIST * +KMF_Plugin_Initialize() +{ + return (&pk11token_plugin_table); +} + +KMF_RETURN +KMFPK11_ConfigureKeystore(KMF_HANDLE_T handle, KMF_CONFIG_PARAMS *params) +{ + KMF_RETURN rv = KMF_OK; + + if (params == NULL || params->pkcs11config.label == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = KMF_SelectToken(handle, params->pkcs11config.label, + params->pkcs11config.readonly); + + return (rv); +} + +static KMF_RETURN +pk11_authenticate(KMF_HANDLE_T handle, + KMF_CREDENTIAL *cred) +{ + + CK_RV ck_rv = CKR_OK; + CK_SESSION_HANDLE hSession = (CK_SESSION_HANDLE)handle->pk11handle; + + if (hSession == NULL) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (cred == NULL || cred->cred == NULL || cred->credlen == 0) { + return (KMF_ERR_BAD_PARAMETER); + } + + if ((ck_rv = C_Login(hSession, CKU_USER, + (uchar_t *)cred->cred, cred->credlen)) != CKR_OK) { + if (ck_rv != CKR_USER_ALREADY_LOGGED_IN) { + handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + handle->lasterr.errcode = ck_rv; + return (KMF_ERR_AUTH_FAILED); + } + } + + return (KMF_OK); +} + +static KMF_RETURN +PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj, + KMF_X509_DER_CERT *kmfcert) +{ + KMF_RETURN rv = 0; + CK_RV ckrv = CKR_OK; + + CK_CERTIFICATE_TYPE cktype; + CK_OBJECT_CLASS class; + CK_BBOOL cktrusted, token; + CK_ULONG subject_len, value_len, issuer_len, serno_len, id_len; + CK_BYTE *subject = NULL, *value = NULL; + CK_BYTE *label = NULL; + CK_ULONG label_len = 0; + CK_ATTRIBUTE templ[10]; + + SETATTR(templ, 0, CKA_CLASS, &class, sizeof (class)); + + /* Is this a certificate object ? */ + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 1); + if (ckrv != CKR_OK || class != CKO_CERTIFICATE) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + SETATTR(templ, 0, CKA_CERTIFICATE_TYPE, &cktype, sizeof (cktype)); + SETATTR(templ, 1, CKA_TOKEN, &token, sizeof (token)); + SETATTR(templ, 2, CKA_TRUSTED, &cktrusted, sizeof (cktrusted)); + + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 3); + + if (ckrv != CKR_OK || cktype != CKC_X_509) { + SET_ERROR(kmfh, ckrv); + return (ckrv); + } else { + /* What attributes are available and how big are they? */ + subject_len = issuer_len = serno_len = id_len = value_len = + label_len = 0; + SETATTR(templ, 0, CKA_SUBJECT, NULL, subject_len); + SETATTR(templ, 1, CKA_ISSUER, NULL, issuer_len); + SETATTR(templ, 2, CKA_SERIAL_NUMBER, NULL, serno_len); + SETATTR(templ, 3, CKA_ID, NULL, id_len); + SETATTR(templ, 4, CKA_VALUE, NULL, value_len); + SETATTR(templ, 5, CKA_LABEL, NULL, label_len); + + /* + * Query the object with NULL values in the pValue spot + * so we know how much space to allocate for each field. + */ + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 6); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); /* TODO - Error messages ? */ + } + + subject_len = templ[0].ulValueLen; + issuer_len = templ[1].ulValueLen; + serno_len = templ[2].ulValueLen; + id_len = templ[3].ulValueLen; + value_len = templ[4].ulValueLen; + label_len = templ[5].ulValueLen; + + /* + * For PKCS#11 CKC_X_509 certificate objects, + * the following attributes must be defined. + * CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_SERIAL_NUMBER, + * CKA_VALUE. + */ + if (subject_len == 0 || issuer_len == 0 || + serno_len == 0 || value_len == 0) { + return (KMF_ERR_INTERNAL); + } + + /* Only fetch the value field if we are saving the data */ + if (kmfcert != NULL) { + int i = 0; + value = malloc(value_len); + if (value == NULL) { + rv = KMF_ERR_MEMORY; + goto errout; + } + + SETATTR(templ, i, CKA_VALUE, value, value_len); + i++; + if (label_len > 0) { + label = malloc(label_len + 1); + if (label == NULL) { + rv = KMF_ERR_MEMORY; + goto errout; + } + (void) memset(label, 0, label_len + 1); + SETATTR(templ, i, CKA_LABEL, label, + label_len); + i++; + } + + /* re-query the object with room for the value attr */ + ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, + templ, i); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + kmfcert->certificate.Data = value; + kmfcert->certificate.Length = value_len; + kmfcert->kmf_private.flags |= KMF_FLAG_CERT_SIGNED; + kmfcert->kmf_private.keystore_type = + KMF_KEYSTORE_PK11TOKEN; + kmfcert->kmf_private.label = (char *)label; + + rv = KMF_OK; + } + } + +errout: + if (rv != KMF_OK) { + if (subject) + free(subject); + if (value) + free(value); + + if (kmfcert) { + kmfcert->certificate.Data = NULL; + kmfcert->certificate.Length = 0; + } + } + return (rv); +} + +static void +free_objlist(OBJLIST *head) +{ + OBJLIST *temp = head; + + while (temp != NULL) { + head = head->next; + free(temp); + temp = head; + } +} + +/* + * The caller should make sure that the templ->pValue is NULL since + * it will be overwritten below. + */ +static KMF_RETURN +get_attr(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, + CK_ATTRIBUTE *templ) +{ + CK_RV rv; + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + if (templ->ulValueLen > 0) { + templ->pValue = malloc(templ->ulValueLen); + if (templ->pValue == NULL) + return (KMF_ERR_MEMORY); + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + } + + return (KMF_OK); +} + +/* + * Match a certificate with an issuer and/or subject name. + * This is tricky because we cannot reliably compare DER encodings + * because RDNs may have their AV-pairs in different orders even + * if the values are the same. You must compare individual + * AV pairs for the RDNs. + * + * RETURN: 0 for a match, non-zero for a non-match. + */ +static KMF_RETURN +matchcert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, + KMF_X509_NAME *issuer, KMF_X509_NAME *subject) +{ + KMF_RETURN rv = KMF_OK; + CK_ATTRIBUTE certattr; + KMF_DATA name; + KMF_X509_NAME dn; + + if (issuer->numberOfRDNs > 0) { + certattr.type = CKA_ISSUER; + certattr.pValue = NULL; + certattr.ulValueLen = 0; + + rv = get_attr(kmfh, obj, &certattr); + + if (rv == KMF_OK) { + name.Data = certattr.pValue; + name.Length = certattr.ulValueLen; + rv = DerDecodeName(&name, &dn); + if (rv == KMF_OK) { + rv = KMF_CompareRDNs(issuer, &dn); + KMF_FreeDN(&dn); + } + free(certattr.pValue); + } + + if (rv != KMF_OK) + return (rv); + } + if (subject->numberOfRDNs > 0) { + certattr.type = CKA_SUBJECT; + certattr.pValue = NULL; + certattr.ulValueLen = 0; + + rv = get_attr(kmfh, obj, &certattr); + + if (rv == KMF_OK) { + name.Data = certattr.pValue; + name.Length = certattr.ulValueLen; + rv = DerDecodeName(&name, &dn); + if (rv == KMF_OK) { + rv = KMF_CompareRDNs(subject, &dn); + KMF_FreeDN(&dn); + } + free(certattr.pValue); + } + } + + return (rv); +} + +/* + * delete "curr" node from the "newlist". + */ +static void +pk11_delete_obj_from_list(OBJLIST **newlist, + OBJLIST **prev, OBJLIST **curr) +{ + + if (*curr == *newlist) { + /* first node in the list */ + *newlist = (*curr)->next; + *prev = (*curr)->next; + free(*curr); + *curr = *newlist; + } else { + (*prev)->next = (*curr)->next; + free(*curr); + *curr = (*prev)->next; + } +} + +/* + * prepare_object_search + * + * Because this code is shared by the FindCert and + * DeleteCert functions, put it in a separate routine + * to save some work and make code easier to debug and + * read. + */ +static KMF_RETURN +search_certs(KMF_HANDLE_T handle, + char *label, char *issuer, char *subject, KMF_BIGINT *serial, + boolean_t private, KMF_CERT_VALIDITY validity, + OBJLIST **objlist, uint32_t *numobj) +{ + KMF_RETURN rv = KMF_OK; + CK_RV ckrv = CKR_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_ATTRIBUTE templ[10]; + CK_BBOOL true = TRUE; + CK_OBJECT_CLASS oclass = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE ctype = CKC_X_509; + KMF_X509_NAME subjectDN, issuerDN; + int i; + OBJLIST *newlist, *tail; + CK_ULONG num = 0; + uint32_t num_ok_certs = 0; /* number of non-expired or expired certs */ + + (void) memset(&templ, 0, 10 * sizeof (CK_ATTRIBUTE)); + (void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME)); + (void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME)); + i = 0; + SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); i++; + SETATTR(templ, i, CKA_CLASS, &oclass, sizeof (oclass)); i++; + SETATTR(templ, i, CKA_CERTIFICATE_TYPE, &ctype, + sizeof (ctype)); i++; + + if (label != NULL && strlen(label)) { + SETATTR(templ, i, CKA_LABEL, label, strlen(label)); + i++; + } + if (private) { + SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); i++; + } + + if (issuer != NULL && strlen(issuer)) { + if ((rv = KMF_DNParser(issuer, &issuerDN)) != KMF_OK) + return (rv); + } + if (subject != NULL && strlen(subject)) { + if ((rv = KMF_DNParser(subject, &subjectDN)) != KMF_OK) + return (rv); + } + + if (serial != NULL && serial->val != NULL && serial->len > 0) { + SETATTR(templ, i, CKA_SERIAL_NUMBER, + serial->val, serial->len); + i++; + } + + (*numobj) = 0; + *objlist = NULL; + newlist = NULL; + + ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, i); + if (ckrv != CKR_OK) + goto cleanup; + + tail = newlist = NULL; + while (ckrv == CKR_OK) { + CK_OBJECT_HANDLE tObj; + ckrv = C_FindObjects(kmfh->pk11handle, &tObj, 1, &num); + if (ckrv != CKR_OK || num == 0) + break; + + /* + * 'matchcert' returns 0 if subject/issuer match + * + * If no match, move on to the next one + */ + if (matchcert(kmfh, tObj, &issuerDN, &subjectDN)) + continue; + + if (newlist == NULL) { + newlist = malloc(sizeof (OBJLIST)); + if (newlist == NULL) { + rv = KMF_ERR_MEMORY; + break; + } + newlist->handle = tObj; + newlist->next = NULL; + tail = newlist; + } else { + tail->next = malloc(sizeof (OBJLIST)); + if (tail->next != NULL) { + tail = tail->next; + } else { + rv = KMF_ERR_MEMORY; + break; + } + tail->handle = tObj; + tail->next = NULL; + } + (*numobj)++; + } + ckrv = C_FindObjectsFinal(kmfh->pk11handle); + +cleanup: + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + if (newlist != NULL) { + free_objlist(newlist); + *numobj = 0; + newlist = NULL; + } + } else { + if (validity == KMF_ALL_CERTS) { + *objlist = newlist; + } else { + OBJLIST *node, *prev; + KMF_X509_DER_CERT tmp_kmf_cert; + uint32_t i = 0; + + node = prev = newlist; + /* + * Now check to see if any found certificate is expired + * or valid. + */ + while (node != NULL && i < (*numobj)) { + (void) memset(&tmp_kmf_cert, 0, + sizeof (KMF_X509_DER_CERT)); + rv = PK11Cert2KMFCert(kmfh, node->handle, + &tmp_kmf_cert); + if (rv != KMF_OK) { + goto cleanup1; + } + + rv = KMF_CheckCertDate(handle, + &tmp_kmf_cert.certificate); + + if (validity == KMF_NONEXPIRED_CERTS) { + if (rv == KMF_OK) { + num_ok_certs++; + prev = node; + node = node->next; + } else if (rv == + KMF_ERR_VALIDITY_PERIOD) { + /* + * expired - remove it from list + */ + pk11_delete_obj_from_list( + &newlist, &prev, &node); + } else { + goto cleanup1; + } + } + + if (validity == KMF_EXPIRED_CERTS) { + if (rv == KMF_ERR_VALIDITY_PERIOD) { + num_ok_certs++; + prev = node; + node = node->next; + rv = KMF_OK; + } else if (rv == KMF_OK) { + /* + * valid - remove it from list + */ + pk11_delete_obj_from_list( + &newlist, &prev, &node); + } else { + goto cleanup1; + } + } + i++; + KMF_FreeKMFCert(handle, &tmp_kmf_cert); + } + *numobj = num_ok_certs; + *objlist = newlist; + } + } + +cleanup1: + if (rv != KMF_OK && newlist != NULL) { + free_objlist(newlist); + *numobj = 0; + *objlist = NULL; + } + + if (issuer != NULL) + KMF_FreeDN(&issuerDN); + + if (subject != NULL) + KMF_FreeDN(&subjectDN); + + return (rv); +} + +/* + * The caller may pass a NULL value for kmf_cert below and the function will + * just return the number of certs found (in num_certs). + */ +KMF_RETURN +KMFPK11_FindCert(KMF_HANDLE_T handle, KMF_FINDCERT_PARAMS *params, + KMF_X509_DER_CERT *kmf_cert, + uint32_t *num_certs) +{ + KMF_RETURN rv = 0; + uint32_t want_certs; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + OBJLIST *objlist = NULL; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL || num_certs == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (*num_certs > 0) + want_certs = *num_certs; + else + want_certs = MAXINT; /* count them all */ + + *num_certs = 0; + + rv = search_certs(handle, + params->certLabel, params->issuer, + params->subject, params->serial, + params->pkcs11parms.private, + params->find_cert_validity, + &objlist, num_certs); + + if (rv == KMF_OK && objlist != NULL && kmf_cert != NULL) { + OBJLIST *node = objlist; + int i = 0; + while (node != NULL && i < want_certs) { + rv = PK11Cert2KMFCert(kmfh, node->handle, + &kmf_cert[i]); + i++; + node = node->next; + } + } + + if (objlist != NULL) + free_objlist(objlist); + + if (*num_certs == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + + return (rv); +} + +/*ARGSUSED*/ +void +KMFPK11_FreeKMFCert(KMF_HANDLE_T handle, + KMF_X509_DER_CERT *kmf_cert) +{ + if (kmf_cert != NULL && kmf_cert->certificate.Data != NULL) { + free(kmf_cert->certificate.Data); + kmf_cert->certificate.Data = NULL; + kmf_cert->certificate.Length = 0; + + if (kmf_cert->kmf_private.label != NULL) { + free(kmf_cert->kmf_private.label); + kmf_cert->kmf_private.label = NULL; + } + } +} + +KMF_RETURN +KMFPK11_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *pKey, + KMF_DATA *eData) +{ + KMF_RETURN ret = KMF_OK; + CK_RV rv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY; + CK_KEY_TYPE ckKeyType; + KMF_DATA Modulus, Exponent, Prime, Subprime, Base, Value; + KMF_OID *Algorithm; + BerElement *asn1 = NULL; + BerValue *PubKeyParams = NULL, *EncodedKey = NULL; + KMF_X509_SPKI spki; + + CK_ATTRIBUTE rsaTemplate[4]; + CK_ATTRIBUTE dsaTemplate[6]; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (pKey == NULL || pKey->keyp == CK_INVALID_HANDLE) + return (KMF_ERR_BAD_PARAMETER); + + (void) memset(&Modulus, 0, sizeof (Modulus)); + (void) memset(&Exponent, 0, sizeof (Exponent)); + (void) memset(&Prime, 0, sizeof (Prime)); + (void) memset(&Subprime, 0, sizeof (Subprime)); + (void) memset(&Base, 0, sizeof (Base)); + (void) memset(&Value, 0, sizeof (Value)); + + SETATTR(rsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass)); + SETATTR(rsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType)); + SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data, &Modulus.Length); + SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT, Exponent.Data, + &Exponent.Length); + + SETATTR(dsaTemplate, 0, CKA_CLASS, &ckObjClass, sizeof (ckObjClass)); + SETATTR(dsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType, sizeof (ckKeyType)); + SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data, &Prime.Length); + SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data, &Subprime.Length); + SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data, &Base.Length); + SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data, &Value.Length); + + switch (pKey->keyalg) { + case KMF_RSA: + /* Get the length of the fields */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + rsaTemplate, 4); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_BAD_PARAMETER); + } + + Modulus.Length = rsaTemplate[2].ulValueLen; + Modulus.Data = malloc(Modulus.Length); + if (Modulus.Data == NULL) + return (KMF_ERR_MEMORY); + + Exponent.Length = rsaTemplate[3].ulValueLen; + Exponent.Data = malloc(Exponent.Length); + if (Exponent.Data == NULL) { + free(Modulus.Data); + return (KMF_ERR_MEMORY); + } + + SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data, + Modulus.Length); + SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT, + Exponent.Data, Exponent.Length); + /* Now get the values */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + rsaTemplate, 4); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * This is the KEY algorithm, not the + * signature algorithm. + */ + Algorithm = X509_AlgIdToAlgorithmOid(KMF_ALGID_RSA); + if (Algorithm != NULL) { + + /* Encode the RSA Key Data */ + if ((asn1 = kmfder_alloc()) == NULL) { + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_MEMORY); + } + if (kmfber_printf(asn1, "{II}", + Modulus.Data, Modulus.Length, + Exponent.Data, Exponent.Length) == -1) { + kmfber_free(asn1, 1); + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_ENCODING); + } + if (kmfber_flatten(asn1, &EncodedKey) == -1) { + kmfber_free(asn1, 1); + free(Modulus.Data); + free(Exponent.Data); + return (KMF_ERR_ENCODING); + } + kmfber_free(asn1, 1); + } + + free(Exponent.Data); + free(Modulus.Data); + + break; + case KMF_DSA: + /* Get the length of the fields */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + dsaTemplate, 6); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_BAD_PARAMETER); + } + Prime.Length = dsaTemplate[2].ulValueLen; + Prime.Data = malloc(Prime.Length); + if (Prime.Data == NULL) { + return (KMF_ERR_MEMORY); + } + + Subprime.Length = dsaTemplate[3].ulValueLen; + Subprime.Data = malloc(Subprime.Length); + if (Subprime.Data == NULL) { + free(Prime.Data); + return (KMF_ERR_MEMORY); + } + + Base.Length = dsaTemplate[4].ulValueLen; + Base.Data = malloc(Base.Length); + if (Base.Data == NULL) { + free(Prime.Data); + free(Subprime.Data); + return (KMF_ERR_MEMORY); + } + + Value.Length = dsaTemplate[5].ulValueLen; + Value.Data = malloc(Value.Length); + if (Value.Data == NULL) { + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + return (KMF_ERR_MEMORY); + } + SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data, + Prime.Length); + SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data, + Subprime.Length); + SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data, + Base.Length); + SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data, + Value.Length); + + /* Now get the values */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pKey->keyp, + dsaTemplate, 6); + if (rv != CKR_OK) { + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + SET_ERROR(kmfh, rv); + return (KMF_ERR_BAD_PARAMETER); + } + /* + * This is the KEY algorithm, not the + * signature algorithm. + */ + Algorithm = + X509_AlgIdToAlgorithmOid(KMF_ALGID_DSA); + + /* Encode the DSA Algorithm Parameters */ + if ((asn1 = kmfder_alloc()) == NULL) { + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + return (KMF_ERR_MEMORY); + } + + if (kmfber_printf(asn1, "{III}", + Prime.Data, Prime.Length, + Subprime.Data, Subprime.Length, + Base.Data, Base.Length) == -1) { + + kmfber_free(asn1, 1); + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + if (kmfber_flatten(asn1, &PubKeyParams) == -1) { + kmfber_free(asn1, 1); + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + kmfber_free(asn1, 1); + free(Prime.Data); + free(Subprime.Data); + free(Base.Data); + + /* Encode the DSA Key Value */ + if ((asn1 = kmfder_alloc()) == NULL) { + free(Value.Data); + return (KMF_ERR_MEMORY); + } + + if (kmfber_printf(asn1, "I", + Value.Data, Value.Length) == -1) { + kmfber_free(asn1, 1); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + if (kmfber_flatten(asn1, &EncodedKey) == -1) { + kmfber_free(asn1, 1); + free(Value.Data); + return (KMF_ERR_ENCODING); + } + kmfber_free(asn1, 1); + free(Value.Data); + break; + default: + return (KMF_ERR_BAD_PARAMETER); + } + + /* Now, build an SPKI structure for the final encoding step */ + spki.algorithm.algorithm = *Algorithm; + if (PubKeyParams != NULL) { + spki.algorithm.parameters.Data = + (uchar_t *)PubKeyParams->bv_val; + spki.algorithm.parameters.Length = PubKeyParams->bv_len; + } else { + spki.algorithm.parameters.Data = NULL; + spki.algorithm.parameters.Length = 0; + } + + if (EncodedKey != NULL) { + spki.subjectPublicKey.Data = (uchar_t *)EncodedKey->bv_val; + spki.subjectPublicKey.Length = EncodedKey->bv_len; + } else { + spki.subjectPublicKey.Data = NULL; + spki.subjectPublicKey.Length = 0; + } + + /* Finally, encode the entire SPKI record */ + ret = DerEncodeSPKI(&spki, eData); + +cleanup: + if (EncodedKey) { + free(EncodedKey->bv_val); + free(EncodedKey); + } + + if (PubKeyParams) { + free(PubKeyParams->bv_val); + free(PubKeyParams); + } + + return (ret); +} + + +static KMF_RETURN +CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + KMF_X509_CERTIFICATE *signed_cert_ptr = NULL; + KMF_DATA data; + KMF_DATA Id; + + CK_RV ckrv; + CK_ULONG subject_len, issuer_len, serno_len; + CK_BYTE *subject, *issuer, *serial; + CK_BBOOL true = TRUE; + CK_CERTIFICATE_TYPE certtype = CKC_X_509; + CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; + CK_ATTRIBUTE x509templ[11]; + CK_OBJECT_HANDLE hCert = NULL; + int i; + + if (!kmfh) + return (KMF_ERR_INTERNAL); /* should not happen */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_INTERNAL); /* should not happen */ + + if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) + return (KMF_ERR_INTERNAL); /* should not happen */ + + /* + * The data *must* be a DER encoded X.509 certificate. + * Convert it to a CSSM cert and then parse the fields so + * the PKCS#11 attributes can be filled in correctly. + */ + rv = DerDecodeSignedCertificate((const KMF_DATA *)pcert, + &signed_cert_ptr); + if (rv != KMF_OK) { + return (KMF_ERR_ENCODING); + } + + /* + * Encode fields into PKCS#11 attributes. + */ + + /* Get the subject name */ + rv = DerEncodeName(&signed_cert_ptr->certificate.subject, &data); + if (rv == KMF_OK) { + subject = data.Data; + subject_len = data.Length; + } else { + rv = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Encode the issuer */ + rv = DerEncodeName(&signed_cert_ptr->certificate.issuer, &data); + if (rv == KMF_OK) { + issuer = data.Data; + issuer_len = data.Length; + } else { + rv = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Encode serial number */ + if (signed_cert_ptr->certificate.serialNumber.len > 0 && + signed_cert_ptr->certificate.serialNumber.val != NULL) { + serial = signed_cert_ptr->certificate.serialNumber.val; + serno_len = signed_cert_ptr->certificate.serialNumber.len; + } else { + rv = KMF_ERR_ENCODING; + goto cleanup; + } + + /* Generate an ID from the SPKI data */ + rv = GetIDFromSPKI(&signed_cert_ptr->certificate.subjectPublicKeyInfo, + &Id); + + if (rv != KMF_OK) { + SET_ERROR(kmfh, rv); + goto cleanup; + } + + i = 0; + SETATTR(x509templ, i, CKA_CLASS, &certClass, + sizeof (certClass)); i++; + SETATTR(x509templ, i, CKA_CERTIFICATE_TYPE, &certtype, + sizeof (certtype)); i++; + SETATTR(x509templ, i, CKA_TOKEN, &true, sizeof (true)); i++; + SETATTR(x509templ, i, CKA_SUBJECT, subject, subject_len); i++; + SETATTR(x509templ, i, CKA_ISSUER, issuer, issuer_len); i++; + SETATTR(x509templ, i, CKA_SERIAL_NUMBER, serial, serno_len); i++; + SETATTR(x509templ, i, CKA_VALUE, pcert->Data, pcert->Length); i++; + SETATTR(x509templ, i, CKA_ID, Id.Data, Id.Length); i++; + if (label != NULL && strlen(label)) { + SETATTR(x509templ, i, CKA_LABEL, label, strlen(label)); + i++; + } + + /* + * The cert object handle is actually "leaked" here. If the app + * really wants to clean up the data space, it will have to call + * KMF_DeleteCert and specify the softtoken keystore. + */ + ckrv = C_CreateObject(kmfh->pk11handle, x509templ, i, &hCert); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_INTERNAL; + } + free(subject); + free(issuer); + +cleanup: + if (Id.Data != NULL) + free(Id.Data); + + if (signed_cert_ptr) { + KMF_FreeSignedCert(signed_cert_ptr); + free(signed_cert_ptr); + } + return (rv); +} + + +KMF_RETURN +KMFPK11_StoreCert(KMF_HANDLE_T handle, KMF_STORECERT_PARAMS *params, + KMF_DATA *pcert) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0) + return (KMF_ERR_BAD_PARAMETER); + + rv = CreateCertObject(handle, params->certLabel, pcert); + return (rv); +} + + + +KMF_RETURN +KMFPK11_ImportCert(KMF_HANDLE_T handle, KMF_IMPORTCERT_PARAMS *params) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_ENCODE_FORMAT format; + KMF_DATA cert1 = { NULL, 0}; + KMF_DATA cert2 = { NULL, 0}; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL || params->certfile == NULL) { + return (KMF_ERR_BAD_PARAMETER); + } + + /* + * Check if the input cert file is a valid certificate and + * auto-detect the file format of it. + */ + rv = KMF_IsCertFile(handle, params->certfile, &format); + if (rv != KMF_OK) + return (rv); + + /* Read in the CERT file */ + rv = KMF_ReadInputFile(handle, params->certfile, &cert1); + if (rv != KMF_OK) { + return (rv); + } + + /* + * If the input certificate is in PEM format, we need to convert + * it to DER first. + */ + if (format == KMF_FORMAT_PEM) { + int derlen; + rv = KMF_Pem2Der(cert1.Data, cert1.Length, + &cert2.Data, &derlen); + if (rv != KMF_OK) { + goto out; + } + cert2.Length = (size_t)derlen; + } + + rv = CreateCertObject(handle, params->certLabel, + format == KMF_FORMAT_ASN1 ? &cert1 : &cert2); + +out: + if (cert1.Data != NULL) { + free(cert1.Data); + } + + if (cert2.Data != NULL) { + free(cert2.Data); + } + + return (rv); +} + +KMF_RETURN +KMFPK11_DeleteCert(KMF_HANDLE_T handle, KMF_DELETECERT_PARAMS *params) +{ + KMF_RETURN rv = 0; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + OBJLIST *objlist; + uint32_t numObjects = 0; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* + * Use the same search routine as is used for the FindCert + * operation. + */ + objlist = NULL; + rv = search_certs(handle, + params->certLabel, params->issuer, + params->subject, params->serial, + params->pkcs11parms.private, + params->find_cert_validity, + &objlist, &numObjects); + + if (rv == KMF_OK && objlist != NULL) { + OBJLIST *node = objlist; + + while (node != NULL) { + CK_RV ckrv; + ckrv = C_DestroyObject(kmfh->pk11handle, + node->handle); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + break; + } + node = node->next; + } + free_objlist(objlist); + } + + if (rv == KMF_OK && numObjects == 0) + rv = KMF_ERR_CERT_NOT_FOUND; + +out: + return (rv); +} + +KMF_RETURN +KMFPK11_CreateKeypair(KMF_HANDLE_T handle, KMF_CREATEKEYPAIR_PARAMS *params, + KMF_KEY_HANDLE *privkey, KMF_KEY_HANDLE *pubkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + CK_RV ckrv = 0; + CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priKey = CK_INVALID_HANDLE; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + + static CK_OBJECT_CLASS priClass = CKO_PRIVATE_KEY; + static CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; + + static CK_ULONG rsaKeyType = CKK_RSA; + static CK_ULONG modulusBits = 1024; + static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01}; + static CK_BBOOL true = TRUE; + static CK_BBOOL ontoken = TRUE; + static CK_BBOOL false = FALSE; + static CK_ULONG dsaKeyType = CKK_DSA; + + CK_ATTRIBUTE rsaPubKeyTemplate[8]; + CK_ATTRIBUTE rsaPriKeyTemplate[6]; + + static CK_BYTE ckDsaPrime[128] = { + 0xb2, 0x6b, 0xc3, 0xfb, 0xe3, 0x26, 0xf4, 0xc2, + 0xcf, 0xdd, 0xf9, 0xae, 0x3e, 0x39, 0x7f, 0x9c, + 0xa7, 0x73, 0xc3, 0x00, 0xa3, 0x50, 0x67, 0xc3, + 0xab, 0x49, 0x2c, 0xea, 0x59, 0x10, 0xa4, 0xbc, + 0x09, 0x94, 0xa9, 0x05, 0x3b, 0x0d, 0x35, 0x3c, + 0x55, 0x52, 0x47, 0xf0, 0xe3, 0x72, 0x5b, 0xe8, + 0x72, 0xa0, 0x71, 0x1c, 0x23, 0x4f, 0x6d, 0xe8, + 0xac, 0xe5, 0x21, 0x1b, 0xc0, 0xd8, 0x42, 0xd3, + 0x87, 0xae, 0x83, 0x5e, 0x52, 0x7e, 0x46, 0x09, + 0xb5, 0xc7, 0x3d, 0xd6, 0x00, 0xf5, 0xf2, 0x9c, + 0x84, 0x30, 0x81, 0x7e, 0x7b, 0x30, 0x5b, 0xd5, + 0xab, 0xd0, 0x2f, 0x21, 0xb3, 0xd8, 0xed, 0xdb, + 0x97, 0x77, 0xe4, 0x7e, 0x6c, 0xcc, 0xb9, 0x6b, + 0xdd, 0xaa, 0x96, 0x04, 0xe7, 0xd4, 0x55, 0x11, + 0x53, 0xab, 0xba, 0x95, 0x9a, 0xa2, 0x8c, 0x27, + 0xd9, 0xcf, 0xad, 0xf3, 0xcf, 0x3a, 0x0c, 0x4b}; + + static CK_BYTE ckDsaSubPrime[20] = { + 0xa4, 0x5f, 0x2a, 0x27, 0x09, 0x49, 0xb6, 0xfe, + 0x73, 0xeb, 0x95, 0x7d, 0x00, 0xf3, 0x42, 0xfc, + 0x78, 0x47, 0xb0, 0xd5}; + + static CK_BYTE ckDsaBase[128] = { + 0x5c, 0x57, 0x16, 0x49, 0xef, 0xc8, 0xfb, 0x4b, + 0xee, 0x07, 0x45, 0x3b, 0x6a, 0x1d, 0xf3, 0xe5, + 0xeb, 0xee, 0xad, 0x11, 0x13, 0xe3, 0x52, 0xe3, + 0x0d, 0xc0, 0x21, 0x25, 0xfa, 0xf0, 0x93, 0x1c, + 0x53, 0x4d, 0xdc, 0x0d, 0x76, 0xd2, 0xfe, 0xc2, + 0xd7, 0x72, 0x64, 0x69, 0x53, 0x3d, 0x33, 0xbd, + 0xe1, 0x34, 0xf2, 0x5a, 0x67, 0x83, 0xe0, 0xd3, + 0x1c, 0xd6, 0x41, 0x4d, 0x16, 0xe8, 0x6c, 0x5a, + 0x07, 0x95, 0x21, 0x9a, 0xa3, 0xc4, 0xb9, 0x05, + 0x9d, 0x11, 0xcb, 0xc8, 0xc4, 0x9d, 0x00, 0x1a, + 0xf4, 0x85, 0x2a, 0xa9, 0x20, 0x3c, 0xba, 0x67, + 0xe5, 0xed, 0x31, 0xb2, 0x11, 0xfb, 0x1f, 0x73, + 0xec, 0x61, 0x29, 0xad, 0xc7, 0x68, 0xb2, 0x3f, + 0x38, 0xea, 0xd9, 0x87, 0x83, 0x9e, 0x7e, 0x19, + 0x18, 0xdd, 0xc2, 0xc3, 0x5b, 0x16, 0x6d, 0xce, + 0xcf, 0x88, 0x91, 0x07, 0xe0, 0x2b, 0xa8, 0x54 }; + + static CK_ATTRIBUTE ckDsaPubKeyTemplate[] = { + { CKA_CLASS, &pubClass, sizeof (pubClass) }, + { CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType) }, + { CKA_TOKEN, &ontoken, sizeof (ontoken)}, + { CKA_PRIVATE, &false, sizeof (false)}, + { CKA_PRIME, &ckDsaPrime, sizeof (ckDsaPrime) }, + { CKA_SUBPRIME, &ckDsaSubPrime, sizeof (ckDsaSubPrime)}, + { CKA_BASE, &ckDsaBase, sizeof (ckDsaBase) }, + { CKA_VERIFY, &true, sizeof (true) }, +}; + +#define NUMBER_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) +#define MAX_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) + + static CK_ATTRIBUTE ckDsaPriKeyTemplate[] = { + {CKA_CLASS, &priClass, sizeof (priClass)}, + {CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType)}, + {CKA_TOKEN, &ontoken, sizeof (ontoken)}, + {CKA_PRIVATE, &true, sizeof (true)}, + {CKA_SIGN, &true, sizeof (true)}, + }; + + CK_ATTRIBUTE labelattr[1]; + CK_ATTRIBUTE idattr[1]; + char IDHashData[SHA1_HASH_LENGTH]; + KMF_DATA IDInput, IDOutput; + +#define NUMBER_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) +#define MAX_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \ + sizeof (CK_ATTRIBUTE)) + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + if (params->keytype == KMF_RSA) { + CK_MECHANISM keyGenMech = {CKM_RSA_PKCS_KEY_PAIR_GEN, + NULL, 0}; + CK_BYTE *modulus; + CK_ULONG modulusLength; + CK_ATTRIBUTE modattr[1]; + + SETATTR(rsaPubKeyTemplate, 0, CKA_CLASS, + &pubClass, sizeof (pubClass)); + SETATTR(rsaPubKeyTemplate, 1, CKA_KEY_TYPE, + &rsaKeyType, sizeof (rsaKeyType)); + SETATTR(rsaPubKeyTemplate, 2, CKA_TOKEN, + &false, sizeof (false)); + SETATTR(rsaPubKeyTemplate, 3, CKA_PRIVATE, + &false, sizeof (false)); + SETATTR(rsaPubKeyTemplate, 4, CKA_MODULUS_BITS, + &modulusBits, sizeof (modulusBits)); + if (params->rsa_exponent.len > 0 && + params->rsa_exponent.val != NULL) { + SETATTR(rsaPubKeyTemplate, 5, + CKA_PUBLIC_EXPONENT, + params->rsa_exponent.val, + params->rsa_exponent.len); + } else { + SETATTR(rsaPubKeyTemplate, 5, + CKA_PUBLIC_EXPONENT, &PubExpo, + sizeof (PubExpo)); + } + SETATTR(rsaPubKeyTemplate, 6, CKA_ENCRYPT, + &true, sizeof (true)); + SETATTR(rsaPubKeyTemplate, 7, CKA_VERIFY, + &true, sizeof (true)); + + SETATTR(rsaPriKeyTemplate, 0, CKA_CLASS, &priClass, + sizeof (priClass)); + SETATTR(rsaPriKeyTemplate, 1, CKA_KEY_TYPE, &rsaKeyType, + sizeof (rsaKeyType)); + SETATTR(rsaPriKeyTemplate, 2, CKA_TOKEN, &ontoken, + sizeof (ontoken)); + SETATTR(rsaPriKeyTemplate, 3, CKA_PRIVATE, &true, + sizeof (true)); + SETATTR(rsaPriKeyTemplate, 4, CKA_DECRYPT, &true, + sizeof (true)); + SETATTR(rsaPriKeyTemplate, 5, CKA_SIGN, &true, + sizeof (true)); + + SETATTR(modattr, 0, CKA_MODULUS, NULL, &modulusLength); + + modulusBits = params->keylength; + + pubKey = CK_INVALID_HANDLE; + priKey = CK_INVALID_HANDLE; + ckrv = C_GenerateKeyPair(hSession, &keyGenMech, + rsaPubKeyTemplate, + (sizeof (rsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)), + rsaPriKeyTemplate, + (sizeof (rsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)), + &pubKey, &priKey); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_KEYGEN_FAILED); + } + + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_PK11TOKEN; + privkey->keyalg = KMF_RSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->keyp = (void *)priKey; + } + if (pubkey != NULL) { + pubkey->kstype = KMF_KEYSTORE_PK11TOKEN; + pubkey->keyalg = KMF_RSA; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keyp = (void *)pubKey; + } + + /* Get the Modulus field to use as input for creating the ID */ + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pubKey, + modattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_BAD_PARAMETER); + } + + modulusLength = modattr[0].ulValueLen; + modulus = malloc(modulusLength); + if (modulus == NULL) + return (KMF_ERR_MEMORY); + + modattr[0].pValue = modulus; + rv = C_GetAttributeValue(kmfh->pk11handle, + (CK_OBJECT_HANDLE)pubKey, + modattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + free(modulus); + return (KMF_ERR_BAD_PARAMETER); + } + + IDInput.Data = modulus; + IDInput.Length = modulusLength; + + } else if (params->keytype == KMF_DSA) { + CK_MECHANISM keyGenMech = {CKM_DSA_KEY_PAIR_GEN, NULL, 0}; + CK_BYTE *keyvalue; + CK_ULONG valueLen; + CK_ATTRIBUTE valattr[1]; + + SETATTR(ckDsaPriKeyTemplate, 2, CKA_TOKEN, + &ontoken, sizeof (ontoken)); + SETATTR(valattr, 0, CKA_VALUE, NULL, &valueLen); + + ckrv = C_GenerateKeyPair(hSession, &keyGenMech, + ckDsaPubKeyTemplate, + (sizeof (ckDsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)), + ckDsaPriKeyTemplate, + (sizeof (ckDsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)), + &pubKey, &priKey); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_KEYGEN_FAILED); + } + + if (privkey != NULL) { + privkey->kstype = KMF_KEYSTORE_PK11TOKEN; + privkey->keyalg = KMF_DSA; + privkey->keyclass = KMF_ASYM_PRI; + privkey->keyp = (void *)priKey; + } + if (pubkey != NULL) { + pubkey->kstype = KMF_KEYSTORE_PK11TOKEN; + pubkey->keyalg = KMF_DSA; + pubkey->keyclass = KMF_ASYM_PUB; + pubkey->keyp = (void *)pubKey; + } + /* Get the Public Value to use as input for creating the ID */ + rv = C_GetAttributeValue(hSession, + (CK_OBJECT_HANDLE)pubKey, + valattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_BAD_PARAMETER); + } + + valueLen = valattr[0].ulValueLen; + keyvalue = malloc(valueLen); + if (keyvalue == NULL) + return (KMF_ERR_MEMORY); + + valattr[0].pValue = keyvalue; + rv = C_GetAttributeValue(hSession, + (CK_OBJECT_HANDLE)pubKey, + valattr, 1); + if (rv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + free(keyvalue); + return (KMF_ERR_BAD_PARAMETER); + } + + IDInput.Data = keyvalue; + IDInput.Length = valueLen; + } else { + return (KMF_ERR_BAD_PARAMETER); + } + + if (params->keylabel != NULL && + strlen(params->keylabel)) { + + SETATTR(labelattr, 0, CKA_LABEL, params->keylabel, + strlen(params->keylabel)); + + /* Set the CKA_LABEL if one was indicated */ + if ((ckrv = C_SetAttributeValue(hSession, pubKey, + labelattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + if (pubkey != NULL) { + pubkey->keylabel = + (char *)strdup(params->keylabel); + if (pubkey->keylabel == NULL) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + } + if ((ckrv = C_SetAttributeValue(hSession, priKey, + labelattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + if (privkey != NULL) { + privkey->keylabel = + (char *)strdup(params->keylabel); + if (privkey->keylabel == NULL) { + rv = KMF_ERR_MEMORY; + goto cleanup; + } + } + } + + /* Now, assign a CKA_ID value so it can be searched */ + /* ID_Input was assigned above in the RSA or DSA keygen section */ + IDOutput.Data = (uchar_t *)IDHashData; + IDOutput.Length = sizeof (IDHashData); + + rv = DigestData(hSession, &IDInput, &IDOutput); + free(IDInput.Data); + + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + goto cleanup; + } + SETATTR(idattr, 0, CKA_ID, IDOutput.Data, IDOutput.Length); + if ((ckrv = C_SetAttributeValue(hSession, pubKey, + idattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + if ((ckrv = C_SetAttributeValue(hSession, priKey, + idattr, 1)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + +cleanup: + if (rv != KMF_OK) { + if (pubKey != CK_INVALID_HANDLE) + (void) C_DestroyObject(hSession, pubKey); + if (priKey != CK_INVALID_HANDLE) + (void) C_DestroyObject(hSession, priKey); + if (privkey) { + privkey->keyp = NULL; + if (privkey->keylabel) + free(privkey->keylabel); + } + if (pubkey) { + pubkey->keyp = NULL; + if (pubkey->keylabel) + free(pubkey->keylabel); + } + } + return (rv); +} + +KMF_RETURN +KMFPK11_DeleteKey(KMF_HANDLE_T handle, KMF_DELETEKEY_PARAMS *params, + KMF_KEY_HANDLE *key, boolean_t destroy) +{ + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_RV ckrv = CKR_OK; + KMF_RETURN rv = KMF_OK; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (key == NULL || key->keyp == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (key->keyclass != KMF_ASYM_PUB && + key->keyclass != KMF_ASYM_PRI && + key->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (destroy) { + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + } + + if (!key->israw && destroy) + ckrv = C_DestroyObject(kmfh->pk11handle, + (CK_OBJECT_HANDLE)key->keyp); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + /* Report authentication failures to the caller */ + if (ckrv == CKR_PIN_EXPIRED || + ckrv == CKR_SESSION_READ_ONLY) + rv = KMF_ERR_AUTH_FAILED; + else + rv = KMF_ERR_INTERNAL; + } + return (rv); + +} + +KMF_RETURN +KMFPK11_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp, + KMF_OID *algOID, + KMF_DATA *tobesigned, + KMF_DATA *output) +{ + CK_RV ckrv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + CK_MECHANISM mechanism; + PKCS_ALGORITHM_MAP *pAlgMap; + KMF_ALGORITHM_INDEX AlgId; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (keyp == NULL || algOID == NULL || + tobesigned == NULL || output == NULL) + return (KMF_ERR_BAD_PARAMETER); + + /* These functions are available to the plugin from libkmf */ + AlgId = X509_AlgorithmOidToAlgId(algOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the Algorithm OID to a PKCS#11 mechanism */ + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgId, PKCS_GetDefaultSignatureMode(AlgId)); + + if (pAlgMap == NULL) + return (KMF_ERR_BAD_PARAMETER); + + mechanism.mechanism = pAlgMap->pkcs_mechanism; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + + ckrv = C_SignInit(hSession, &mechanism, (CK_OBJECT_HANDLE)keyp->keyp); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + ckrv = C_Sign(hSession, + tobesigned->Data, tobesigned->Length, + output->Data, (CK_ULONG *)&output->Length); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + return (KMF_OK); +} + +KMF_RETURN +KMFPK11_GetErrorString(KMF_HANDLE_T handle, char **msgstr) +{ + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + *msgstr = NULL; + if (kmfh->lasterr.errcode != 0) { + char *e = pkcs11_strerror(kmfh->lasterr.errcode); + if (e == NULL || (*msgstr = (char *)strdup(e)) == NULL) { + return (KMF_ERR_MEMORY); + } + } + + return (KMF_OK); +} + +static CK_RV +getObjectKeytype(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj, + CK_ULONG *keytype) +{ + CK_RV rv = CKR_OK; + CK_ATTRIBUTE templ; + CK_ULONG len = sizeof (CK_ULONG); + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + templ.type = CKA_KEY_TYPE; + templ.pValue = keytype; + templ.ulValueLen = len; + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1); + + return (rv); + +} +static CK_RV +getObjectLabel(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj, + char **outlabel) +{ + CK_RV rv = CKR_OK; + CK_ATTRIBUTE templ; + char Label[BUFSIZ]; + CK_ULONG len = sizeof (Label); + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + (void) memset(Label, 0, len); + templ.type = CKA_LABEL; + templ.pValue = Label; + templ.ulValueLen = len; + + rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1); + if (rv == CKR_OK) { + *outlabel = (char *)strdup(Label); + } else { + *outlabel = NULL; + } + return (rv); +} + +KMF_RETURN +KMFPK11_GetPrikeyByCert(KMF_HANDLE_T handle, + KMF_CRYPTOWITHCERT_PARAMS *params, + KMF_DATA *SignerCertData, KMF_KEY_HANDLE *key, + KMF_KEY_ALG keytype) +{ + KMF_X509_SPKI *pubkey; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + KMF_RETURN rv = KMF_OK; + CK_RV ckrv = CKR_OK; + CK_ATTRIBUTE templ[4]; + CK_OBJECT_HANDLE pri_obj = CK_INVALID_HANDLE; + CK_ULONG obj_count; + CK_OBJECT_CLASS certClass = CKO_PRIVATE_KEY; + CK_BBOOL true = TRUE; + KMF_DATA Id = { NULL, 0 }; + + /* Decode the signer cert so we can get the SPKI data */ + if ((rv = DerDecodeSignedCertificate(SignerCertData, + &SignerCert)) != KMF_OK) + return (rv); + + /* Get the public key info from the signer certificate */ + pubkey = &SignerCert->certificate.subjectPublicKeyInfo; + + /* Generate an ID from the SPKI data */ + rv = GetIDFromSPKI(pubkey, &Id); + + if (rv != KMF_OK) { + SET_ERROR(kmfh, rv); + goto errout; + } + + SETATTR(templ, 0, CKA_CLASS, &certClass, sizeof (certClass)); + SETATTR(templ, 1, CKA_TOKEN, &true, sizeof (true)); + SETATTR(templ, 2, CKA_PRIVATE, &true, sizeof (true)); + SETATTR(templ, 3, CKA_ID, Id.Data, Id.Length); + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + if ((ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, 4)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + if ((rv = C_FindObjects(kmfh->pk11handle, &pri_obj, 1, + &obj_count)) != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + if (obj_count == 0) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_INTERNAL; + goto errout; + } + + key->kstype = KMF_KEYSTORE_PK11TOKEN; + key->keyclass = KMF_ASYM_PRI; + key->keyalg = keytype; + key->keyp = (void *)pri_obj; + + (void) C_FindObjectsFinal(kmfh->pk11handle); + + ckrv = getObjectLabel(handle, (CK_OBJECT_HANDLE)key->keyp, + &key->keylabel); + + if (ckrv != CKR_OK) { + SET_ERROR(handle, ckrv); + rv = KMF_ERR_INTERNAL; + } else { + rv = KMF_OK; + } + + if (rv == KMF_OK && params->format == KMF_FORMAT_RAWKEY) { + KMF_RAW_KEY_DATA *rkey = NULL; + rv = keyObj2RawKey(handle, key, &rkey); + if (rv == KMF_OK) { + key->keyp = rkey; + key->israw = TRUE; + } + } + +errout: + if (Id.Data != NULL) + free(Id.Data); + + if (SignerCert != NULL) { + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + } + return (rv); +} + +KMF_RETURN +KMFPK11_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, + KMF_OID *algOID, KMF_DATA *ciphertext, + KMF_DATA *output) +{ + CK_RV ckrv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + CK_MECHANISM mechanism; + PKCS_ALGORITHM_MAP *pAlgMap; + KMF_ALGORITHM_INDEX AlgId; + CK_ULONG out_len = 0, block_len = 0, total_decrypted = 0; + uint8_t *in_data, *out_data; + int i, blocks; + CK_ATTRIBUTE ckTemplate[1]; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (key == NULL || algOID == NULL || + ciphertext == NULL || output == NULL) + return (KMF_ERR_BAD_PARAMETER); + + AlgId = X509_AlgorithmOidToAlgId(algOID); + if (AlgId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_PARAMETER); + + /* Map the Algorithm ID to a PKCS#11 mechanism */ + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgId, PKCS_GetDefaultSignatureMode(AlgId)); + + if (pAlgMap == NULL) + return (KMF_ERR_BAD_PARAMETER); + + mechanism.mechanism = pAlgMap->pkcs_mechanism; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + + SETATTR(ckTemplate, 0, CKA_MODULUS, (CK_BYTE *)NULL, + sizeof (CK_ULONG)); + + /* Get the modulus length */ + ckrv = C_GetAttributeValue(hSession, + (CK_OBJECT_HANDLE)key->keyp, ckTemplate, 1); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + block_len = ckTemplate[0].ulValueLen; + + /* Compute the number of times to do single-part decryption */ + blocks = ciphertext->Length/block_len; + + out_data = output->Data; + in_data = ciphertext->Data; + out_len = block_len - 11; + + for (i = 0; i < blocks; i++) { + ckrv = C_DecryptInit(hSession, &mechanism, + (CK_OBJECT_HANDLE)key->keyp); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + ckrv = C_Decrypt(hSession, in_data, block_len, + out_data, (CK_ULONG *)&out_len); + + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + out_data += out_len; + total_decrypted += out_len; + in_data += block_len; + + } + + output->Length = total_decrypted; + return (KMF_OK); +} + +static void +attr2bigint(CK_ATTRIBUTE_PTR attr, KMF_BIGINT *big) +{ + big->val = attr->pValue; + big->len = attr->ulValueLen; +} + + +static KMF_RETURN +get_raw_rsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_RSA_KEY *rawrsa) +{ + KMF_RETURN rv = KMF_OK; + CK_SESSION_HANDLE sess = kmfh->pk11handle; + CK_ATTRIBUTE rsa_pri_attrs[8] = { + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + { CKA_PRIVATE_EXPONENT, NULL, 0 }, /* optional */ + { CKA_PRIME_1, NULL, 0 }, /* | */ + { CKA_PRIME_2, NULL, 0 }, /* | */ + { CKA_EXPONENT_1, NULL, 0 }, /* | */ + { CKA_EXPONENT_2, NULL, 0 }, /* | */ + { CKA_COEFFICIENT, NULL, 0 } /* V */ + }; + CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE); + int i; + + if ((rv = C_GetAttributeValue(sess, obj, + rsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + /* Allocate memory for each attribute. */ + for (i = 0; i < count; i++) { + if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || + rsa_pri_attrs[i].ulValueLen == 0) { + rsa_pri_attrs[i].ulValueLen = 0; + continue; + } + if ((rsa_pri_attrs[i].pValue = + malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) { + rv = KMF_ERR_MEMORY; + goto end; + } + } + /* Now that we have space, really get the attributes */ + if ((rv = C_GetAttributeValue(sess, obj, + rsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_INTERNAL; + goto end; + } + i = 0; + attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->mod); + attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->pubexp); + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->priexp); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime1); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->prime2); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp1); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->exp2); + i++; + + if (rsa_pri_attrs[i].ulValueLen != (CK_ULONG)-1 && + rsa_pri_attrs[i].ulValueLen != 0) + attr2bigint(&(rsa_pri_attrs[i]), &rawrsa->coef); + i++; + +end: + if (rv != KMF_OK) { + for (i = 0; i < count; i++) { + if (rsa_pri_attrs[i].pValue != NULL) + free(rsa_pri_attrs[i].pValue); + } + (void) memset(rawrsa, 0, sizeof (KMF_RAW_RSA_KEY)); + } + return (rv); +} + +static KMF_RETURN +get_raw_dsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_DSA_KEY *rawdsa) +{ + KMF_RETURN rv = KMF_OK; + CK_SESSION_HANDLE sess = kmfh->pk11handle; + CK_ATTRIBUTE dsa_pri_attrs[8] = { + { CKA_PRIME, NULL, 0 }, + { CKA_SUBPRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + { CKA_VALUE, NULL, 0 } + }; + CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE); + int i; + + if ((rv = C_GetAttributeValue(sess, obj, + dsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + return (KMF_ERR_INTERNAL); + } + + /* Allocate memory for each attribute. */ + for (i = 0; i < count; i++) { + if (dsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 || + dsa_pri_attrs[i].ulValueLen == 0) { + dsa_pri_attrs[i].ulValueLen = 0; + continue; + } + if ((dsa_pri_attrs[i].pValue = + malloc(dsa_pri_attrs[i].ulValueLen)) == NULL) { + rv = KMF_ERR_MEMORY; + goto end; + } + } + if ((rv = C_GetAttributeValue(sess, obj, + dsa_pri_attrs, count)) != CKR_OK) { + SET_ERROR(kmfh, rv); + rv = KMF_ERR_INTERNAL; + goto end; + } + + /* Fill in all the temp variables. They are all required. */ + i = 0; + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->prime); + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->subprime); + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->base); + attr2bigint(&(dsa_pri_attrs[i++]), &rawdsa->value); + +end: + if (rv != KMF_OK) { + for (i = 0; i < count; i++) { + if (dsa_pri_attrs[i].pValue != NULL) + free(dsa_pri_attrs[i].pValue); + } + (void) memset(rawdsa, 0, sizeof (KMF_RAW_DSA_KEY)); + } + return (rv); +} + +static KMF_RETURN +get_raw_sym(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_SYM_KEY *rawsym) +{ + KMF_RETURN rv = KMF_OK; + CK_RV ckrv; + CK_SESSION_HANDLE sess = kmfh->pk11handle; + CK_ATTRIBUTE sym_attr[1]; + CK_ULONG value_len = 0; + + /* find the key length first */ + sym_attr[0].type = CKA_VALUE; + sym_attr[0].pValue = NULL; + sym_attr[0].ulValueLen = value_len; + if ((ckrv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) { + /* + * Don't return error if the key is sensitive, just + * don't return any raw data. Operations like "list" + * need to succeed even if the raw data is not + * available. + */ + if (ckrv == CKR_ATTRIBUTE_SENSITIVE) { + rawsym->keydata.val = NULL; + rawsym->keydata.len = 0; + return (CKR_OK); + } + SET_ERROR(kmfh, ckrv); + return (KMF_ERR_INTERNAL); + } + + /* Allocate memory for pValue */ + sym_attr[0].pValue = malloc(sym_attr[0].ulValueLen); + if (sym_attr[0].pValue == NULL) { + return (KMF_ERR_MEMORY); + } + + /* get the key data */ + if ((rv = C_GetAttributeValue(sess, obj, sym_attr, 1)) != CKR_OK) { + SET_ERROR(kmfh, rv); + free(sym_attr[0].pValue); + return (KMF_ERR_INTERNAL); + } + + rawsym->keydata.val = sym_attr[0].pValue; + rawsym->keydata.len = sym_attr[0].ulValueLen; + return (rv); +} + +static KMF_RETURN +keyObj2RawKey(KMF_HANDLE_T handle, KMF_KEY_HANDLE *inkey, + KMF_RAW_KEY_DATA **outkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_RAW_KEY_DATA *rkey; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + rkey = malloc(sizeof (KMF_RAW_KEY_DATA)); + if (rkey == NULL) + return (KMF_ERR_MEMORY); + + (void) memset(rkey, 0, sizeof (KMF_RAW_KEY_DATA)); + + rkey->keytype = inkey->keyalg; + + if (inkey->keyalg == KMF_RSA) { + rv = get_raw_rsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp, + &rkey->rawdata.rsa); + } else if (inkey->keyalg == KMF_DSA) { + rv = get_raw_dsa(kmfh, (CK_OBJECT_HANDLE)inkey->keyp, + &rkey->rawdata.dsa); + } else if (inkey->keyalg == KMF_AES || + inkey->keyalg == KMF_RC4 || + inkey->keyalg == KMF_DES || + inkey->keyalg == KMF_DES3) { + rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)inkey->keyp, + &rkey->rawdata.sym); + } else { + rv = KMF_ERR_BAD_PARAMETER; + } + + if (rv == KMF_OK) { + *outkey = rkey; + } else if (rkey != NULL) { + free(rkey); + *outkey = NULL; + } + + return (rv); +} + + +static KMF_RETURN +kmf2pk11keytype(KMF_KEY_ALG keyalg, CK_KEY_TYPE *type) +{ + switch (keyalg) { + case KMF_RSA: + *type = CKK_RSA; + break; + case KMF_DSA: + *type = CKK_DSA; + break; + case KMF_AES: + *type = CKK_AES; + break; + case KMF_RC4: + *type = CKK_RC4; + break; + case KMF_DES: + *type = CKK_DES; + break; + case KMF_DES3: + *type = CKK_DES3; + break; + default: + return (KMF_ERR_BAD_KEY_TYPE); + } + + return (KMF_OK); +} + +static int +IDStringToData(char *idstr, KMF_DATA *iddata) +{ + int len, i; + char *iddup, *byte; + uint_t lvalue; + + if (idstr == NULL || !strlen(idstr)) + return (-1); + + iddup = (char *)strdup(idstr); + if (iddup == NULL) + return (KMF_ERR_MEMORY); + + len = strlen(iddup) / 3 + 1; + iddata->Data = malloc(len); + if (iddata->Data == NULL) + return (KMF_ERR_MEMORY); + (void) memset(iddata->Data, 0, len); + iddata->Length = len; + + byte = strtok(iddup, ":"); + if (byte == NULL) { + free(iddup); + free(iddata->Data); + iddata->Data = NULL; + iddata->Length = 0; + return (-1); + } + + i = 0; + do { + (void) sscanf(byte, "%x", &lvalue); + iddata->Data[i++] = (uchar_t)(lvalue & 0x000000FF); + byte = strtok(NULL, ":"); + } while (byte != NULL && i < len); + + iddata->Length = i; + free(iddup); + return (0); +} + +KMF_RETURN +KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms, + KMF_KEY_HANDLE *keys, uint32_t *numkeys) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + uint32_t want_keys, i; + CK_RV ckrv; + CK_ATTRIBUTE pTmpl[10]; + CK_OBJECT_CLASS class; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ULONG alg; + CK_BBOOL is_token; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (parms == NULL || numkeys == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (numkeys != NULL && *numkeys > 0) + want_keys = *numkeys; + else + want_keys = MAXINT; /* count them all */ + + if (parms->keyclass == KMF_ASYM_PUB) { + class = CKO_PUBLIC_KEY; + is_token = false; + } else if (parms->keyclass == KMF_ASYM_PRI) { + class = CKO_PRIVATE_KEY; + is_token = true; + } else if (parms->keyclass == KMF_SYMMETRIC) { + class = CKO_SECRET_KEY; + is_token = true; + } else { + return (KMF_ERR_BAD_KEY_CLASS); + } + + i = 0; + pTmpl[i].type = CKA_TOKEN; + pTmpl[i].pValue = &is_token; + pTmpl[i].ulValueLen = sizeof (CK_BBOOL); + i++; + + pTmpl[i].type = CKA_CLASS; + pTmpl[i].pValue = &class; + pTmpl[i].ulValueLen = sizeof (class); + i++; + + if (parms->findLabel != NULL && strlen(parms->findLabel)) { + pTmpl[i].type = CKA_LABEL; + pTmpl[i].pValue = parms->findLabel; + pTmpl[i].ulValueLen = strlen(parms->findLabel); + i++; + } + + if (parms->keytype != 0) { + rv = kmf2pk11keytype(parms->keytype, &alg); + if (rv != KMF_OK) { + return (KMF_ERR_BAD_KEY_TYPE); + } + pTmpl[i].type = CKA_KEY_TYPE; + pTmpl[i].pValue = &alg; + pTmpl[i].ulValueLen = sizeof (alg); + i++; + } + + if (parms->idstr != NULL) { + KMF_DATA iddata = { NULL, 0 }; + + /* + * ID String parameter is assumed to be of form: + * XX:XX:XX:XX:XX ... :XX + * where XX is a hex number. + * + * We must convert this back to binary in order to + * use it in a search. + */ + rv = IDStringToData(parms->idstr, &iddata); + if (rv == KMF_OK) { + pTmpl[i].type = CKA_ID; + pTmpl[i].pValue = iddata.Data; + pTmpl[i].ulValueLen = iddata.Length; + i++; + } else { + return (rv); + } + } + + if (parms->pkcs11parms.private) { + pTmpl[i].type = CKA_PRIVATE; + pTmpl[i].pValue = &true; + pTmpl[i].ulValueLen = sizeof (true); + i++; + } + + if (is_token) { + rv = pk11_authenticate(handle, &parms->cred); + if (rv != KMF_OK) { + return (rv); + } + } + + ckrv = C_FindObjectsInit(kmfh->pk11handle, pTmpl, i); + if (ckrv == CKR_OK) { + CK_ULONG obj_count, n = 0; + while (ckrv == CKR_OK && n < want_keys) { + CK_OBJECT_HANDLE hObj; + + ckrv = C_FindObjects(kmfh->pk11handle, &hObj, + 1, &obj_count); + if (ckrv == CKR_OK && obj_count == 1) { + if (keys != NULL) { + CK_ULONG keytype; + keys[n].kstype = KMF_KEYSTORE_PK11TOKEN; + keys[n].keyclass = parms->keyclass; + keys[n].israw = FALSE; + keys[n].keyp = (void *)hObj; + + ckrv = getObjectKeytype(handle, + (CK_OBJECT_HANDLE)keys[n].keyp, + &keytype); + if (ckrv != CKR_OK) + goto end; + + ckrv = getObjectLabel(handle, + (CK_OBJECT_HANDLE)keys[n].keyp, + &(keys[n].keylabel)); + if (ckrv != CKR_OK) + goto end; + + if (keytype == CKK_RSA) + keys[n].keyalg = KMF_RSA; + else if (keytype == CKK_DSA) + keys[n].keyalg = KMF_DSA; + else if (keytype == CKK_AES) + keys[n].keyalg = KMF_AES; + else if (keytype == CKK_RC4) + keys[n].keyalg = KMF_RC4; + else if (keytype == CKK_DES) + keys[n].keyalg = KMF_DES; + else if (keytype == CKK_DES3) + keys[n].keyalg = KMF_DES3; + + } + n++; + } else { + break; + } + } + ckrv = C_FindObjectsFinal(kmfh->pk11handle); + + /* "numkeys" indicates the number that were actually found */ + *numkeys = n; + } + if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0 && + parms->format == KMF_FORMAT_RAWKEY) { + /* Convert keys to "rawkey" format */ + for (i = 0; i < (*numkeys); i++) { + KMF_RAW_KEY_DATA *rkey = NULL; + rv = keyObj2RawKey(handle, &keys[i], &rkey); + if (rv == KMF_OK) { + keys[i].keyp = rkey; + keys[i].israw = TRUE; + } else { + break; + } + } + } +end: + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + /* Report authentication failures to the caller */ + if (ckrv == CKR_USER_NOT_LOGGED_IN || + ckrv == CKR_PIN_INCORRECT || + ckrv == CKR_PIN_INVALID || + ckrv == CKR_PIN_EXPIRED || + ckrv == CKR_PIN_LOCKED || + ckrv == CKR_SESSION_READ_ONLY) + rv = KMF_ERR_AUTH_FAILED; + else + rv = KMF_ERR_INTERNAL; + } else if ((*numkeys) == 0) { + rv = KMF_ERR_KEY_NOT_FOUND; + } + + return (rv); +} + +static char * +convertDate(char *fulldate) +{ + struct tm tms; + char newtime[9]; + + (void) strptime(fulldate, "%b %d %T %Y %Z", &tms); + + if (tms.tm_year < 69) + tms.tm_year += 100; + + (void) strftime(newtime, sizeof (newtime), "m%d", &tms); + + newtime[8] = 0; + + /* memory returned must be freed by the caller */ + return ((char *)strdup(newtime)); +} + +KMF_RETURN +KMFPK11_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params, + KMF_RAW_KEY_DATA *rawkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + int i; + CK_RV ckrv = CKR_OK; + CK_ATTRIBUTE templ[32]; + CK_OBJECT_HANDLE keyobj; + CK_KEY_TYPE keytype; + CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY; + CK_BBOOL cktrue = TRUE; + CK_DATE startdate, enddate; + KMF_DATA id = {NULL, 0}; + KMF_DATA subject = {NULL, 0}; + KMF_X509EXT_KEY_USAGE kuext; + KMF_X509_CERTIFICATE *x509 = NULL; + CK_BBOOL kufound; + char *notbefore = NULL, *start = NULL; + char *notafter = NULL, *end = NULL; + + if (!kmfh) + return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */ + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL || params->certificate == NULL || + rawkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + + if (rawkey->keytype == KMF_RSA) + keytype = CKK_RSA; + else if (rawkey->keytype == KMF_DSA) + keytype = CKK_DSA; + else + return (KMF_ERR_BAD_PARAMETER); + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + id.Data = NULL; + id.Length = 0; + rv = KMF_GetCertIDData(params->certificate, &id); + if (rv != KMF_OK) { + goto cleanup; + } + + rv = DerDecodeSignedCertificate( + (const KMF_DATA *)params->certificate, &x509); + if (rv != KMF_OK) { + goto cleanup; + } + + rv = DerEncodeName(&x509->certificate.subject, &subject); + if (rv != KMF_OK) { + goto cleanup; + } + + rv = KMF_GetCertStartDateString(handle, params->certificate, + ¬before); + if (rv != KMF_OK) { + goto cleanup; + } + start = convertDate(notbefore); + + rv = KMF_GetCertEndDateString(handle, params->certificate, + ¬after); + if (rv != KMF_OK) { + goto cleanup; + } + end = convertDate(notafter); + + if ((rv = KMF_GetCertKeyUsageExt(params->certificate, &kuext)) + != KMF_OK && rv != KMF_ERR_EXTENSION_NOT_FOUND) + goto cleanup; + + kufound = (rv == KMF_OK); + rv = KMF_OK; /* reset if we got KMF_ERR_EXTENSION_NOT_FOUND above */ + + i = 0; + SETATTR(templ, i, CKA_CLASS, &oClass, sizeof (CK_OBJECT_CLASS)); i++; + SETATTR(templ, i, CKA_KEY_TYPE, &keytype, sizeof (keytype)); i++; + SETATTR(templ, i, CKA_TOKEN, &cktrue, sizeof (cktrue)); i++; + SETATTR(templ, i, CKA_PRIVATE, &cktrue, sizeof (cktrue)); i++; + SETATTR(templ, i, CKA_SUBJECT, subject.Data, subject.Length); i++; + + /* + * Only set the KeyUsage stuff if the KU extension was present. + */ + if (kufound) { + CK_BBOOL condition; + + condition = (kuext.KeyUsageBits & KMF_keyEncipherment) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_UNWRAP, &condition, + sizeof (CK_BBOOL)); i++; + condition = (kuext.KeyUsageBits & KMF_dataEncipherment) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_DECRYPT, &condition, + sizeof (CK_BBOOL)); i++; + condition = (kuext.KeyUsageBits & KMF_digitalSignature) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_SIGN, &condition, + sizeof (CK_BBOOL)); i++; + condition = (kuext.KeyUsageBits & KMF_digitalSignature) ? + B_TRUE : B_FALSE; + SETATTR(templ, i, CKA_SIGN_RECOVER, &condition, + sizeof (CK_BBOOL)); i++; + } + if (params->label != NULL) { + SETATTR(templ, i, CKA_LABEL, params->label, + strlen(params->label)); + i++; + } + if (id.Data != NULL && + id.Data != NULL && id.Length > 0) { + SETATTR(templ, i, CKA_ID, id.Data, id.Length); + i++; + } + if (start != NULL) { + /* + * This make some potentially dangerous assumptions: + * 1. that the startdate in the parameter block is + * properly formatted as YYYYMMDD + * 2. That the CK_DATE structure is always the same. + */ + (void) memcpy(&startdate, start, sizeof (CK_DATE)); + SETATTR(templ, i, CKA_START_DATE, &startdate, + sizeof (startdate)); + i++; + } + if (end != NULL) { + (void) memcpy(&enddate, end, sizeof (CK_DATE)); + SETATTR(templ, i, CKA_END_DATE, &enddate, sizeof (enddate)); + i++; + } + if (keytype == CKK_RSA) { + SETATTR(templ, i, CKA_MODULUS, + rawkey->rawdata.rsa.mod.val, + rawkey->rawdata.rsa.mod.len); + i++; + SETATTR(templ, i, CKA_PUBLIC_EXPONENT, + rawkey->rawdata.rsa.pubexp.val, + rawkey->rawdata.rsa.pubexp.len); + i++; + if (rawkey->rawdata.rsa.priexp.val != NULL) { + SETATTR(templ, i, CKA_PRIVATE_EXPONENT, + rawkey->rawdata.rsa.priexp.val, + rawkey->rawdata.rsa.priexp.len); + i++; + } + if (rawkey->rawdata.rsa.prime1.val != NULL) { + SETATTR(templ, i, CKA_PRIME_1, + rawkey->rawdata.rsa.prime1.val, + rawkey->rawdata.rsa.prime1.len); + i++; + } + if (rawkey->rawdata.rsa.prime2.val != NULL) { + SETATTR(templ, i, CKA_PRIME_2, + rawkey->rawdata.rsa.prime2.val, + rawkey->rawdata.rsa.prime2.len); + i++; + } + if (rawkey->rawdata.rsa.exp1.val != NULL) { + SETATTR(templ, i, CKA_EXPONENT_1, + rawkey->rawdata.rsa.exp1.val, + rawkey->rawdata.rsa.exp1.len); + i++; + } + if (rawkey->rawdata.rsa.exp2.val != NULL) { + SETATTR(templ, i, CKA_EXPONENT_2, + rawkey->rawdata.rsa.exp2.val, + rawkey->rawdata.rsa.exp2.len); + i++; + } + if (rawkey->rawdata.rsa.coef.val != NULL) { + SETATTR(templ, i, CKA_COEFFICIENT, + rawkey->rawdata.rsa.coef.val, + rawkey->rawdata.rsa.coef.len); + i++; + } + } else { + SETATTR(templ, i, CKA_PRIME, + rawkey->rawdata.dsa.prime.val, + rawkey->rawdata.dsa.prime.len); + i++; + SETATTR(templ, i, CKA_SUBPRIME, + rawkey->rawdata.dsa.subprime.val, + rawkey->rawdata.dsa.subprime.len); + i++; + SETATTR(templ, i, CKA_BASE, + rawkey->rawdata.dsa.base.val, + rawkey->rawdata.dsa.base.len); + i++; + SETATTR(templ, i, CKA_VALUE, + rawkey->rawdata.dsa.value.val, + rawkey->rawdata.dsa.value.len); + i++; + } + + ckrv = C_CreateObject(kmfh->pk11handle, templ, i, &keyobj); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + + /* Report authentication failures to the caller */ + if (ckrv == CKR_USER_NOT_LOGGED_IN || + ckrv == CKR_PIN_INCORRECT || + ckrv == CKR_PIN_INVALID || + ckrv == CKR_PIN_EXPIRED || + ckrv == CKR_PIN_LOCKED || + ckrv == CKR_SESSION_READ_ONLY) + rv = KMF_ERR_AUTH_FAILED; + else + rv = KMF_ERR_INTERNAL; + } +cleanup: + KMF_FreeData(&id); + KMF_FreeData(&subject); + KMF_FreeSignedCert(x509); + free(x509); + + return (rv); +} + +KMF_RETURN +KMFPK11_CreateSymKey(KMF_HANDLE_T handle, KMF_CREATESYMKEY_PARAMS *params, + KMF_KEY_HANDLE *symkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_RV ckrv; + CK_SESSION_HANDLE hSession = kmfh->pk11handle; + CK_OBJECT_HANDLE keyhandle; + CK_MECHANISM keyGenMech; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_ULONG secKeyType; + CK_ULONG secKeyLen; /* for RC4 and AES */ + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ATTRIBUTE templ[15]; + int i; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (params == NULL) + return (KMF_ERR_BAD_PARAMETER); + + keyGenMech.pParameter = NULL_PTR; + keyGenMech.ulParameterLen = 0; + switch (params->keytype) { + case KMF_AES: + keyGenMech.mechanism = CKM_AES_KEY_GEN; + secKeyType = CKK_AES; + break; + case KMF_RC4: + keyGenMech.mechanism = CKM_RC4_KEY_GEN; + secKeyType = CKK_RC4; + break; + case KMF_DES: + keyGenMech.mechanism = CKM_DES_KEY_GEN; + secKeyType = CKK_DES; + break; + case KMF_DES3: + keyGenMech.mechanism = CKM_DES3_KEY_GEN; + secKeyType = CKK_DES3; + break; + default: + return (KMF_ERR_BAD_KEY_TYPE); + } + + i = 0; + SETATTR(templ, i, CKA_CLASS, &class, sizeof (class)); + i++; + SETATTR(templ, i, CKA_KEY_TYPE, &secKeyType, sizeof (secKeyType)); + i++; + + if (params->keytype == KMF_AES || params->keytype == KMF_RC4) { + if ((params->keylength % 8) != 0) { + return (KMF_ERR_BAD_KEY_SIZE); + } + secKeyLen = params->keylength/8; /* in bytes for RC4/AES */ + SETATTR(templ, i, CKA_VALUE_LEN, &secKeyLen, + sizeof (secKeyLen)); + i++; + } + + if (params->keylabel != NULL) { + SETATTR(templ, i, CKA_LABEL, params->keylabel, + strlen(params->keylabel)); + i++; + } + + if (params->pkcs11parms.sensitive == B_TRUE) { + SETATTR(templ, i, CKA_SENSITIVE, &true, sizeof (true)); + } else { + SETATTR(templ, i, CKA_SENSITIVE, &false, sizeof (false)); + } + i++; + + if (params->pkcs11parms.not_extractable == B_TRUE) { + SETATTR(templ, i, CKA_EXTRACTABLE, &false, sizeof (false)); + } else { + SETATTR(templ, i, CKA_EXTRACTABLE, &true, sizeof (true)); + } + i++; + + SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_ENCRYPT, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_DECRYPT, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_SIGN, &true, sizeof (true)); + i++; + SETATTR(templ, i, CKA_VERIFY, &true, sizeof (true)); + i++; + + rv = pk11_authenticate(handle, ¶ms->cred); + if (rv != KMF_OK) { + return (rv); + } + + ckrv = C_GenerateKey(hSession, &keyGenMech, templ, i, &keyhandle); + if (ckrv != CKR_OK) { + SET_ERROR(kmfh, ckrv); + rv = KMF_ERR_KEYGEN_FAILED; + goto out; + } + + symkey->kstype = KMF_KEYSTORE_PK11TOKEN; + symkey->keyalg = params->keytype; + symkey->keyclass = KMF_SYMMETRIC; + symkey->israw = FALSE; + symkey->keyp = (void *)keyhandle; + +out: + return (rv); +} + + +KMF_RETURN +KMFPK11_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, + KMF_RAW_SYM_KEY *rkey) +{ + KMF_RETURN rv = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + + if (kmfh == NULL) + return (KMF_ERR_UNINITIALIZED); + + if (kmfh->pk11handle == CK_INVALID_HANDLE) + return (KMF_ERR_NO_TOKEN_SELECTED); + + if (symkey == NULL || rkey == NULL) + return (KMF_ERR_BAD_PARAMETER); + else if (symkey->keyclass != KMF_SYMMETRIC) + return (KMF_ERR_BAD_KEY_CLASS); + + if (symkey->israw) { + KMF_RAW_KEY_DATA *rawkey = (KMF_RAW_KEY_DATA *)symkey->keyp; + + if (rawkey == NULL || + rawkey->rawdata.sym.keydata.val == NULL || + rawkey->rawdata.sym.keydata.len == 0) + return (KMF_ERR_BAD_KEYHANDLE); + + rkey->keydata.len = rawkey->rawdata.sym.keydata.len; + if ((rkey->keydata.val = malloc(rkey->keydata.len)) == NULL) + return (KMF_ERR_MEMORY); + (void) memcpy(rkey->keydata.val, + rawkey->rawdata.sym.keydata.val, rkey->keydata.len); + } else { + rv = get_raw_sym(kmfh, (CK_OBJECT_HANDLE)symkey->keyp, rkey); + } + + return (rv); +} + +KMF_RETURN +KMFPK11_SetTokenPin(KMF_HANDLE_T handle, KMF_SETPIN_PARAMS *params, + KMF_CREDENTIAL *newpin) +{ + KMF_RETURN ret = KMF_OK; + CK_RV rv = CKR_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE session = NULL; + + if (handle == NULL || params == NULL || newpin == NULL) + return (KMF_ERR_BAD_PARAMETER); + + rv = C_OpenSession(params->pkcs11parms.slot, + CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &session); + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + ret = KMF_ERR_UNINITIALIZED; + goto end; + } + + rv = C_SetPIN(session, + (CK_BYTE *)params->cred.cred, params->cred.credlen, + (CK_BYTE *)newpin->cred, newpin->credlen); + + if (rv != CKR_OK) { + SET_ERROR(kmfh, rv); + if (rv == CKR_PIN_INCORRECT || + rv == CKR_PIN_INVALID || + rv == CKR_PIN_EXPIRED || + rv == CKR_PIN_LOCKED) + ret = KMF_ERR_AUTH_FAILED; + else + ret = KMF_ERR_INTERNAL; + } +end: + if (session != NULL) + (void) C_CloseSession(session); + return (ret); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile new file mode 100644 index 0000000000..443f78537a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/i386/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile new file mode 100644 index 0000000000..472ac90a9a --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparc/Makefile @@ -0,0 +1,29 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: $(ROOTLIBS) diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile new file mode 100644 index 0000000000..0dd91e1065 --- /dev/null +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/sparcv9/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../../Makefile.lib.64 + +install: $(ROOTLIBS64) diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt index 020c2ab0c6..5883a81cd7 100644 --- a/usr/src/lib/libsecdb/exec_attr.txt +++ b/usr/src/lib/libsecdb/exec_attr.txt @@ -41,6 +41,7 @@ Contract Observer:solaris:cmd:::/usr/bin/ctwatch:\ privs=contract_event,contract_observer Cron Management:suser:cmd:::/usr/bin/crontab:euid=0 Crypto Management:suser:cmd:::/usr/sbin/cryptoadm:euid=0 +Crypto Management:suser:cmd:::/usr/bin/kfmcfg:euid=0 Crypto Management:suser:cmd:::/usr/sfw/bin/openssl:euid=0 Crypto Management:suser:cmd:::/usr/sfw/bin/CA.pl:euid=0 DHCP Management:suser:cmd:::/usr/lib/inet/dhcp/svcadm/dhcpconfig:uid=0 diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com index 7272645f33..bc4f649b6b 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_com +++ b/usr/src/pkgdefs/SUNWarc/prototype_com @@ -122,6 +122,8 @@ f none usr/lib/llib-lipmp 644 root bin f none usr/lib/llib-lipmp.ln 644 root bin f none usr/lib/llib-lipp 644 root bin f none usr/lib/llib-lipp.ln 644 root bin +f none usr/lib/llib-lkmf.ln 644 root bin +f none usr/lib/llib-lkmfberder.ln 644 root bin s none usr/lib/llib-lkstat=../../lib/llib-lkstat s none usr/lib/llib-lkstat.ln=../../lib/llib-lkstat.ln f none usr/lib/llib-lkvm 644 root bin diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386 index 8099c626ab..627f850a9d 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarc/prototype_i386 @@ -91,6 +91,8 @@ s none usr/lib/amd64/llib-lgen.ln=../../../lib/amd64/llib-lgen.ln f none usr/lib/amd64/llib-lgss.ln 644 root bin s none usr/lib/amd64/llib-lintl.ln=../../../lib/amd64/llib-lintl.ln f none usr/lib/amd64/llib-lipp.ln 644 root bin +f none usr/lib/amd64/llib-lkmf.ln 644 root bin +f none usr/lib/amd64/llib-lkmfberder.ln 644 root bin s none usr/lib/amd64/llib-lkstat.ln=../../../lib/amd64/llib-lkstat.ln f none usr/lib/amd64/llib-lkvm.ln 644 root bin f none usr/lib/amd64/llib-lldap.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc index 37f008e017..5c4fc485f4 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc @@ -87,6 +87,8 @@ s none usr/lib/sparcv9/llib-lgen.ln=../../../lib/sparcv9/llib-lgen.ln f none usr/lib/sparcv9/llib-lgss.ln 644 root bin s none usr/lib/sparcv9/llib-lintl.ln=../../../lib/sparcv9/llib-lintl.ln f none usr/lib/sparcv9/llib-lipp.ln 644 root bin +f none usr/lib/sparcv9/llib-lkmf.ln 644 root bin +f none usr/lib/sparcv9/llib-lkmfberder.ln 644 root bin s none usr/lib/sparcv9/llib-lkstat.ln=../../../lib/sparcv9/llib-lkstat.ln f none usr/lib/sparcv9/llib-lkvm.ln 644 root bin f none usr/lib/sparcv9/llib-lldap.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com index a8e9305623..5e557a0004 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_com +++ b/usr/src/pkgdefs/SUNWcsl/prototype_com @@ -146,6 +146,10 @@ f none usr/lib/libipp.so.1 755 root bin f none usr/lib/libipsecutil.so.1 755 root bin s none usr/lib/libkstat.so=../../lib/libkstat.so.1 s none usr/lib/libkstat.so.1=../../lib/libkstat.so.1 +f none usr/lib/libkmf.so.1 755 root bin +s none usr/lib/libkmf.so=./libkmf.so.1 +f none usr/lib/libkmfberder.so.1 755 root bin +s none usr/lib/libkmfberder.so=./libkmfberder.so.1 s none usr/lib/libkvm.so=./libkvm.so.1 f none usr/lib/libkvm.so.1 755 root bin s none usr/lib/libl.so=./libl.so.1 @@ -294,6 +298,9 @@ f none usr/lib/security/crypt_bsdbf.so.1 755 root bin s none usr/lib/security/crypt_bsdbf.so=./crypt_bsdbf.so.1 f none usr/lib/security/crypt_sunmd5.so.1 755 root bin s none usr/lib/security/crypt_sunmd5.so=./crypt_sunmd5.so.1 +f none usr/lib/security/kmf_nss.so.1 755 root bin +f none usr/lib/security/kmf_openssl.so.1 755 root bin +f none usr/lib/security/kmf_pkcs11.so.1 755 root bin f none usr/lib/security/pam_ldap.so.1 755 root bin s none usr/lib/security/pam_ldap.so=./pam_ldap.so.1 f none usr/lib/security/pam_allow.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386 index 21dc389597..4c65a8fd58 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386 @@ -94,6 +94,9 @@ f none usr/lib/security/amd64/crypt_bsdbf.so.1 755 root bin s none usr/lib/security/amd64/crypt_bsdbf.so=./crypt_bsdbf.so.1 f none usr/lib/security/amd64/crypt_sunmd5.so.1 755 root bin s none usr/lib/security/amd64/crypt_sunmd5.so=./crypt_sunmd5.so.1 +f none usr/lib/security/amd64/kmf_nss.so.1 755 root bin +f none usr/lib/security/amd64/kmf_openssl.so.1 755 root bin +f none usr/lib/security/amd64/kmf_pkcs11.so.1 755 root bin f none usr/lib/security/amd64/pam_ldap.so.1 755 root bin s none usr/lib/security/amd64/pam_ldap.so=./pam_ldap.so.1 f none usr/lib/security/amd64/pam_allow.so.1 755 root bin @@ -165,6 +168,10 @@ s none usr/lib/amd64/libgen.so=../../../lib/amd64/libgen.so.1 s none usr/lib/amd64/libinetutil.so.1=../../../lib/amd64/libinetutil.so.1 f none usr/lib/amd64/libipp.so.1 755 root bin s none usr/lib/amd64/libipp.so=libipp.so.1 +f none usr/lib/amd64/libkmf.so.1 755 root bin +s none usr/lib/amd64/libkmf.so=libkmf.so.1 +f none usr/lib/amd64/libkmfberder.so.1 755 root bin +s none usr/lib/amd64/libkmfberder.so=libkmfberder.so.1 f none usr/lib/amd64/libldap.so.4 755 root bin f none usr/lib/amd64/libldap.so.5 755 root bin s none usr/lib/amd64/libldap.so=libldap.so.5 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc index f83c4c616e..1bcdad558d 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc @@ -87,6 +87,9 @@ f none usr/lib/security/sparcv9/crypt_bsdbf.so.1 755 root bin s none usr/lib/security/sparcv9/crypt_bsdbf.so=./crypt_bsdbf.so.1 f none usr/lib/security/sparcv9/crypt_sunmd5.so.1 755 root bin s none usr/lib/security/sparcv9/crypt_sunmd5.so=./crypt_sunmd5.so.1 +f none usr/lib/security/sparcv9/kmf_nss.so.1 755 root bin +f none usr/lib/security/sparcv9/kmf_openssl.so.1 755 root bin +f none usr/lib/security/sparcv9/kmf_pkcs11.so.1 755 root bin f none usr/lib/security/sparcv9/pam_ldap.so.1 755 root bin s none usr/lib/security/sparcv9/pam_ldap.so=./pam_ldap.so.1 f none usr/lib/security/sparcv9/pam_allow.so.1 755 root bin @@ -158,6 +161,10 @@ s none usr/lib/sparcv9/libgen.so=../../../lib/sparcv9/libgen.so.1 s none usr/lib/sparcv9/libinetutil.so.1=../../../lib/sparcv9/libinetutil.so.1 f none usr/lib/sparcv9/libipp.so.1 755 root bin s none usr/lib/sparcv9/libipp.so=libipp.so.1 +f none usr/lib/sparcv9/libkmf.so.1 755 root bin +s none usr/lib/sparcv9/libkmf.so=libkmf.so.1 +f none usr/lib/sparcv9/libkmfberder.so.1 755 root bin +s none usr/lib/sparcv9/libkmfberder.so=libkmfberder.so.1 f none usr/lib/sparcv9/libldap.so.4 755 root bin f none usr/lib/sparcv9/libldap.so.5 755 root bin s none usr/lib/sparcv9/libldap.so=libldap.so.5 diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com index be5acf70a4..00aab420fd 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -275,6 +275,7 @@ f none etc/security/dev/fd0 400 root bin f none etc/security/dev/sr0 400 root bin f none etc/security/dev/st0 400 root bin f none etc/security/dev/st1 400 root bin +f none etc/security/kmfpolicy.xml 644 root bin d none etc/security/lib 755 root sys f none etc/security/lib/audio_clean 555 root sys f none etc/security/lib/fd_clean 555 root sys diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 65a9eac914..00f5b80e1c 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com @@ -163,6 +163,7 @@ f none usr/bin/kbd 555 root bin f none usr/bin/keylogin 555 root bin f none usr/bin/keylogout 555 root bin l none usr/bin/kill=../../usr/bin/alias +f none usr/bin/kmfcfg 555 root bin f none usr/bin/ksh 555 root bin f none usr/bin/line 555 root bin f none usr/bin/listdgrp 555 root bin @@ -975,6 +976,7 @@ f none usr/share/lib/unittab 444 root bin d none usr/share/lib/xml 755 root sys d none usr/share/lib/xml/dtd 755 root sys f none usr/share/lib/xml/dtd/adt_record.dtd.1 444 root bin +f none usr/share/lib/xml/dtd/kmfpolicy.dtd 444 root bin f none usr/share/lib/xml/dtd/service_bundle.dtd.1 0444 root sys d none usr/share/lib/xml/style 755 root sys f none usr/share/lib/xml/style/adt_record.xsl.1 444 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index 7306f102cd..20f6f0e581 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -174,6 +174,8 @@ f none usr/include/kerberosv5/com_err.h 644 root bin f none usr/include/kerberosv5/krb5.h 644 root bin f none usr/include/kerberosv5/mit_copyright.h 644 root bin f none usr/include/kerberosv5/mit-sipb-copyright.h 644 root bin +f none usr/include/kmfapi.h 644 root bin +f none usr/include/kmftypes.h 644 root bin f none usr/include/kstat.h 644 root bin f none usr/include/kvm.h 644 root bin f none usr/include/lber.h 644 root bin |