diff options
Diffstat (limited to 'usr/src/lib/libkmf/ber_der/common/clasn1.c')
-rw-r--r-- | usr/src/lib/libkmf/ber_der/common/clasn1.c | 2452 |
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); +} |