clasn1.c revision 02b8f7bbc995d1c58c013c6ae56040d8df009a4f
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* 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) {
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);
}