summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmf/ber_der/common/clasn1.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libkmf/ber_der/common/clasn1.c')
-rw-r--r--usr/src/lib/libkmf/ber_der/common/clasn1.c2452
1 files changed, 2452 insertions, 0 deletions
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);
+}