199ebb4caSwyllys /*
2*e65e5c2dSWyllys Ingersoll  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
399ebb4caSwyllys  * Use is subject to license terms.
49a767088Shaimay  */
59a767088Shaimay /*
699ebb4caSwyllys  * Copyright (c) 1995-1999 Intel Corporation. All rights reserved.
799ebb4caSwyllys  */
899ebb4caSwyllys 
999ebb4caSwyllys #include <strings.h>
1099ebb4caSwyllys #include <kmftypes.h>
1199ebb4caSwyllys #include <ber_der.h>
12*e65e5c2dSWyllys Ingersoll #include <kmfber_int.h>
1399ebb4caSwyllys #include <kmfapi.h>
1499ebb4caSwyllys #include <kmfapiP.h>
1599ebb4caSwyllys 
1699ebb4caSwyllys #include <stdio.h>
1799ebb4caSwyllys 
1899ebb4caSwyllys #define	DSA_RAW_SIG_LEN	40
1999ebb4caSwyllys 
2099ebb4caSwyllys static uint8_t OID_ExtensionRequest[] = { OID_PKCS_9, 14 };
2199ebb4caSwyllys const KMF_OID extension_request_oid = {OID_PKCS_9_LENGTH + 1,
2299ebb4caSwyllys 	OID_ExtensionRequest};
2399ebb4caSwyllys 
2499ebb4caSwyllys static KMF_RETURN
encode_algoid(BerElement * asn1,KMF_X509_ALGORITHM_IDENTIFIER * algoid,boolean_t encode_params)25*e65e5c2dSWyllys Ingersoll encode_algoid(BerElement *asn1, KMF_X509_ALGORITHM_IDENTIFIER *algoid,
26*e65e5c2dSWyllys Ingersoll     boolean_t encode_params)
2799ebb4caSwyllys {
2899ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
2999ebb4caSwyllys 
3099ebb4caSwyllys 	if (kmfber_printf(asn1, "{D", &algoid->algorithm) == -1) {
3199ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
3299ebb4caSwyllys 	}
33*e65e5c2dSWyllys Ingersoll 	if (!encode_params) {
34*e65e5c2dSWyllys Ingersoll 		if (kmfber_printf(asn1, "}") == -1)
35*e65e5c2dSWyllys Ingersoll 			return (KMF_ERR_BAD_CERT_FORMAT);
36*e65e5c2dSWyllys Ingersoll 	} else if (algoid->parameters.Data == NULL ||
372cbed729Swyllys 	    algoid->parameters.Length == 0) {
3899ebb4caSwyllys 		if (kmfber_printf(asn1, "n}") == -1)
3999ebb4caSwyllys 			return (KMF_ERR_BAD_CERT_FORMAT);
4099ebb4caSwyllys 	} else {
4199ebb4caSwyllys 		/*
4299ebb4caSwyllys 		 * The algorithm data can be anything, so we just write it
4399ebb4caSwyllys 		 * straight into the buffer.  It is already DER encoded.
4499ebb4caSwyllys 		 */
4599ebb4caSwyllys 		(void) kmfber_write(asn1, (char *)algoid->parameters.Data,
462cbed729Swyllys 		    algoid->parameters.Length, 0);
4799ebb4caSwyllys 		if (kmfber_printf(asn1, "}") == -1) {
4899ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
4999ebb4caSwyllys 		}
5099ebb4caSwyllys 	}
5199ebb4caSwyllys 
5299ebb4caSwyllys 	return (ret);
5399ebb4caSwyllys }
5499ebb4caSwyllys 
5599ebb4caSwyllys static void
free_data(KMF_DATA * data)5699ebb4caSwyllys free_data(KMF_DATA *data)
5799ebb4caSwyllys {
5899ebb4caSwyllys 	if (data == NULL || data->Data == NULL)
5999ebb4caSwyllys 		return;
6099ebb4caSwyllys 
6199ebb4caSwyllys 	free(data->Data);
6299ebb4caSwyllys 	data->Data = NULL;
6399ebb4caSwyllys 	data->Length = 0;
6499ebb4caSwyllys }
6599ebb4caSwyllys 
6699ebb4caSwyllys static void
free_algoid(KMF_X509_ALGORITHM_IDENTIFIER * algoid)6799ebb4caSwyllys free_algoid(KMF_X509_ALGORITHM_IDENTIFIER *algoid)
6899ebb4caSwyllys {
6999ebb4caSwyllys 	free_data(&algoid->algorithm);
7099ebb4caSwyllys 	free_data(&algoid->parameters);
7199ebb4caSwyllys }
7299ebb4caSwyllys 
7399ebb4caSwyllys static void
free_decoded_spki(KMF_X509_SPKI * spki)7499ebb4caSwyllys free_decoded_spki(KMF_X509_SPKI *spki)
7599ebb4caSwyllys {
7699ebb4caSwyllys 	if (spki != NULL) {
7799ebb4caSwyllys 		free_algoid(&spki->algorithm);
7899ebb4caSwyllys 		free_data(&spki->subjectPublicKey);
7999ebb4caSwyllys 	}
8099ebb4caSwyllys }
8199ebb4caSwyllys 
8299ebb4caSwyllys static void
free_rdn_data(KMF_X509_NAME * name)8399ebb4caSwyllys free_rdn_data(KMF_X509_NAME *name)
8499ebb4caSwyllys {
8599ebb4caSwyllys 	KMF_X509_RDN 		*newrdn = NULL;
8699ebb4caSwyllys 	KMF_X509_TYPE_VALUE_PAIR *av = NULL;
8799ebb4caSwyllys 	int i, j;
8899ebb4caSwyllys 
8999ebb4caSwyllys 	if (name && name->numberOfRDNs) {
9099ebb4caSwyllys 		for (i = 0; i < name->numberOfRDNs; i++) {
9199ebb4caSwyllys 			newrdn = &name->RelativeDistinguishedName[i];
9299ebb4caSwyllys 			for (j = 0; j < newrdn->numberOfPairs; j++) {
9399ebb4caSwyllys 				av = &newrdn->AttributeTypeAndValue[j];
9499ebb4caSwyllys 				free_data(&av->type);
9599ebb4caSwyllys 				free_data(&av->value);
9699ebb4caSwyllys 			}
9799ebb4caSwyllys 			free(newrdn->AttributeTypeAndValue);
9899ebb4caSwyllys 		}
9999ebb4caSwyllys 		free(name->RelativeDistinguishedName);
10099ebb4caSwyllys 		name->numberOfRDNs = 0;
10199ebb4caSwyllys 		name->RelativeDistinguishedName = NULL;
10299ebb4caSwyllys 	}
10399ebb4caSwyllys }
10499ebb4caSwyllys 
10599ebb4caSwyllys static void
free_validity(KMF_X509_VALIDITY * validity)10699ebb4caSwyllys free_validity(KMF_X509_VALIDITY *validity)
10799ebb4caSwyllys {
10899ebb4caSwyllys 	free_data(&validity->notBefore.time);
10999ebb4caSwyllys 	free_data(&validity->notAfter.time);
11099ebb4caSwyllys }
11199ebb4caSwyllys 
11299ebb4caSwyllys static void
free_one_extension(KMF_X509_EXTENSION * exptr)11399ebb4caSwyllys free_one_extension(KMF_X509_EXTENSION *exptr)
11499ebb4caSwyllys {
11599ebb4caSwyllys 	free_data(&exptr->extnId);
11699ebb4caSwyllys 	free_data(&exptr->BERvalue);
11799ebb4caSwyllys 
11899ebb4caSwyllys 	if (exptr->value.tagAndValue) {
11999ebb4caSwyllys 		free_data(&exptr->value.tagAndValue->value);
12099ebb4caSwyllys 		free(exptr->value.tagAndValue);
12199ebb4caSwyllys 	}
12299ebb4caSwyllys }
12399ebb4caSwyllys 
12499ebb4caSwyllys static void
free_extensions(KMF_X509_EXTENSIONS * extns)12599ebb4caSwyllys free_extensions(KMF_X509_EXTENSIONS *extns)
12699ebb4caSwyllys {
12799ebb4caSwyllys 	int i;
12899ebb4caSwyllys 	KMF_X509_EXTENSION *exptr;
12999ebb4caSwyllys 
13099ebb4caSwyllys 	if (extns && extns->numberOfExtensions > 0) {
13199ebb4caSwyllys 		for (i = 0; i < extns->numberOfExtensions; i++) {
13299ebb4caSwyllys 			exptr = &extns->extensions[i];
13399ebb4caSwyllys 			free_one_extension(exptr);
13499ebb4caSwyllys 		}
13599ebb4caSwyllys 		free(extns->extensions);
13699ebb4caSwyllys 		extns->numberOfExtensions = 0;
13799ebb4caSwyllys 		extns->extensions = NULL;
13899ebb4caSwyllys 	}
13999ebb4caSwyllys }
14099ebb4caSwyllys 
14199ebb4caSwyllys static void
free_tbscsr(KMF_TBS_CSR * tbscsr)14299ebb4caSwyllys free_tbscsr(KMF_TBS_CSR *tbscsr)
14399ebb4caSwyllys {
14499ebb4caSwyllys 	if (tbscsr) {
14599ebb4caSwyllys 		free_data(&tbscsr->version);
14699ebb4caSwyllys 
14799ebb4caSwyllys 		free_rdn_data(&tbscsr->subject);
14899ebb4caSwyllys 
14999ebb4caSwyllys 		free_decoded_spki(&tbscsr->subjectPublicKeyInfo);
15099ebb4caSwyllys 
15199ebb4caSwyllys 		free_extensions(&tbscsr->extensions);
15299ebb4caSwyllys 	}
15399ebb4caSwyllys }
15499ebb4caSwyllys 
15599ebb4caSwyllys 
15699ebb4caSwyllys static void
free_bigint(KMF_BIGINT * bn)15799ebb4caSwyllys free_bigint(KMF_BIGINT *bn)
15899ebb4caSwyllys {
15999ebb4caSwyllys 	if (bn != NULL && bn->val != NULL) {
16099ebb4caSwyllys 		free(bn->val);
16199ebb4caSwyllys 		bn->val = NULL;
16299ebb4caSwyllys 		bn->len = 0;
16399ebb4caSwyllys 	}
16499ebb4caSwyllys }
16599ebb4caSwyllys 
16699ebb4caSwyllys static void
free_tbscert(KMF_X509_TBS_CERT * tbscert)16799ebb4caSwyllys free_tbscert(KMF_X509_TBS_CERT *tbscert)
16899ebb4caSwyllys {
16999ebb4caSwyllys 	if (tbscert) {
17099ebb4caSwyllys 		free_data(&tbscert->version);
17199ebb4caSwyllys 		free_bigint(&tbscert->serialNumber);
17299ebb4caSwyllys 		free_algoid(&tbscert->signature);
17399ebb4caSwyllys 
17499ebb4caSwyllys 		free_rdn_data(&tbscert->issuer);
17599ebb4caSwyllys 		free_rdn_data(&tbscert->subject);
17699ebb4caSwyllys 
17799ebb4caSwyllys 		free_validity(&tbscert->validity);
17899ebb4caSwyllys 
17999ebb4caSwyllys 		free_data(&tbscert->issuerUniqueIdentifier);
18099ebb4caSwyllys 		free_data(&tbscert->subjectUniqueIdentifier);
18199ebb4caSwyllys 		free_decoded_spki(&tbscert->subjectPublicKeyInfo);
18299ebb4caSwyllys 		free_extensions(&tbscert->extensions);
18399ebb4caSwyllys 
18499ebb4caSwyllys 		free_data(&tbscert->issuerUniqueIdentifier);
18599ebb4caSwyllys 		free_data(&tbscert->subjectUniqueIdentifier);
18699ebb4caSwyllys 	}
18799ebb4caSwyllys }
18899ebb4caSwyllys 
18999ebb4caSwyllys static void
free_decoded_cert(KMF_X509_CERTIFICATE * certptr)19099ebb4caSwyllys free_decoded_cert(KMF_X509_CERTIFICATE *certptr)
19199ebb4caSwyllys {
19299ebb4caSwyllys 	if (!certptr)
19399ebb4caSwyllys 		return;
19499ebb4caSwyllys 
19599ebb4caSwyllys 	free_tbscert(&certptr->certificate);
19699ebb4caSwyllys 
19799ebb4caSwyllys 	free_algoid(&certptr->signature.algorithmIdentifier);
19899ebb4caSwyllys 	free_data(&certptr->signature.encrypted);
19999ebb4caSwyllys }
20099ebb4caSwyllys 
20199ebb4caSwyllys static KMF_RETURN
get_sequence_data(BerElement * asn1,BerValue * seqdata)202*e65e5c2dSWyllys Ingersoll get_sequence_data(BerElement *asn1, BerValue *seqdata)
20399ebb4caSwyllys {
204*e65e5c2dSWyllys Ingersoll 	ber_tag_t tag;
20599ebb4caSwyllys 	ber_len_t size;
20699ebb4caSwyllys 
20799ebb4caSwyllys 	tag = kmfber_next_element(asn1, &size, NULL);
208*e65e5c2dSWyllys Ingersoll 	if (tag == BER_OBJECT_IDENTIFIER) {
209*e65e5c2dSWyllys Ingersoll 		/* The whole block is the OID. */
210*e65e5c2dSWyllys Ingersoll 		size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size);
211*e65e5c2dSWyllys Ingersoll 		seqdata->bv_val = malloc(size);
212*e65e5c2dSWyllys Ingersoll 		if (seqdata->bv_val == NULL) {
213*e65e5c2dSWyllys Ingersoll 			return (KMF_ERR_MEMORY);
214*e65e5c2dSWyllys Ingersoll 		}
215*e65e5c2dSWyllys Ingersoll 		/* read the raw data into the Algoritm params area. */
216*e65e5c2dSWyllys Ingersoll 		if (kmfber_read(asn1, seqdata->bv_val, size) ==
217*e65e5c2dSWyllys Ingersoll 		    -1) {
218*e65e5c2dSWyllys Ingersoll 			return (KMF_ERR_BAD_CERT_FORMAT);
219*e65e5c2dSWyllys Ingersoll 		}
220*e65e5c2dSWyllys Ingersoll 		seqdata->bv_len = size;
221*e65e5c2dSWyllys Ingersoll 		return (KMF_OK);
222*e65e5c2dSWyllys Ingersoll 	} else if (tag != BER_CONSTRUCTED_SEQUENCE)
223*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_BAD_CERT_FORMAT);
224*e65e5c2dSWyllys Ingersoll 
225*e65e5c2dSWyllys Ingersoll 	if ((kmfber_scanf(asn1, "tl", &tag, &size)) == -1) {
22699ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
227*e65e5c2dSWyllys Ingersoll 	}
228*e65e5c2dSWyllys Ingersoll 	/*
229*e65e5c2dSWyllys Ingersoll 	 * We need to read the tag and the length bytes too,
230*e65e5c2dSWyllys Ingersoll 	 * so adjust the size.
231*e65e5c2dSWyllys Ingersoll 	 */
232*e65e5c2dSWyllys Ingersoll 	size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size);
233*e65e5c2dSWyllys Ingersoll 	seqdata->bv_val = malloc(size);
234*e65e5c2dSWyllys Ingersoll 	if (seqdata->bv_val == NULL) {
235*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_MEMORY);
236*e65e5c2dSWyllys Ingersoll 	}
237*e65e5c2dSWyllys Ingersoll 	/* read the raw data into the Algoritm params area. */
238*e65e5c2dSWyllys Ingersoll 	if (kmfber_read(asn1, seqdata->bv_val, size) ==
239*e65e5c2dSWyllys Ingersoll 	    -1) {
240*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_BAD_CERT_FORMAT);
241*e65e5c2dSWyllys Ingersoll 	}
242*e65e5c2dSWyllys Ingersoll 	seqdata->bv_len = size;
243*e65e5c2dSWyllys Ingersoll 	return (KMF_OK);
244*e65e5c2dSWyllys Ingersoll }
245*e65e5c2dSWyllys Ingersoll 
246*e65e5c2dSWyllys Ingersoll static KMF_RETURN
get_algoid(BerElement * asn1,KMF_X509_ALGORITHM_IDENTIFIER * algoid)247*e65e5c2dSWyllys Ingersoll get_algoid(BerElement *asn1, KMF_X509_ALGORITHM_IDENTIFIER *algoid)
248*e65e5c2dSWyllys Ingersoll {
249*e65e5c2dSWyllys Ingersoll 	KMF_RETURN rv = KMF_OK;
250*e65e5c2dSWyllys Ingersoll 	ber_tag_t tag;
251*e65e5c2dSWyllys Ingersoll 	ber_len_t size;
252*e65e5c2dSWyllys Ingersoll 	BerValue algoid_data;
253*e65e5c2dSWyllys Ingersoll 	BerValue AlgOID;
254*e65e5c2dSWyllys Ingersoll 	BerElement *oidasn1 = NULL;
255*e65e5c2dSWyllys Ingersoll 
256*e65e5c2dSWyllys Ingersoll 	/* Read the entire OID seq into it's own data block */
257*e65e5c2dSWyllys Ingersoll 	rv = get_sequence_data(asn1, &algoid_data);
258*e65e5c2dSWyllys Ingersoll 	if (rv != KMF_OK)
259*e65e5c2dSWyllys Ingersoll 		return (rv);
260*e65e5c2dSWyllys Ingersoll 
261*e65e5c2dSWyllys Ingersoll 	/* Now parse just this block so we don't overrun */
262*e65e5c2dSWyllys Ingersoll 	if ((oidasn1 = kmfder_init(&algoid_data)) == NULL)
263*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_MEMORY);
264*e65e5c2dSWyllys Ingersoll 	tag = kmfber_next_element(oidasn1, &size, NULL);
265*e65e5c2dSWyllys Ingersoll 	if (tag == BER_OBJECT_IDENTIFIER) {
266*e65e5c2dSWyllys Ingersoll 		algoid->algorithm.Data = (uchar_t *)algoid_data.bv_val;
267*e65e5c2dSWyllys Ingersoll 		algoid->algorithm.Length = algoid_data.bv_len;
268*e65e5c2dSWyllys Ingersoll 		algoid->parameters.Data = NULL;
269*e65e5c2dSWyllys Ingersoll 		algoid->parameters.Length = 0;
270*e65e5c2dSWyllys Ingersoll 		kmfber_free(oidasn1, 1);
271*e65e5c2dSWyllys Ingersoll 		return (KMF_OK);
272*e65e5c2dSWyllys Ingersoll 	}
27399ebb4caSwyllys 
274*e65e5c2dSWyllys Ingersoll 	if ((tag = kmfber_scanf(oidasn1, "{D", &AlgOID)) == -1) {
275*e65e5c2dSWyllys Ingersoll 		kmfber_free(oidasn1, 1);
27699ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
27799ebb4caSwyllys 	}
27899ebb4caSwyllys 	algoid->algorithm.Data = (uchar_t *)AlgOID.bv_val;
27999ebb4caSwyllys 	algoid->algorithm.Length = AlgOID.bv_len;
28099ebb4caSwyllys 
281*e65e5c2dSWyllys Ingersoll 	tag = kmfber_next_element(oidasn1, &size, NULL);
282*e65e5c2dSWyllys Ingersoll 	if (tag == BER_NULL) {
283*e65e5c2dSWyllys Ingersoll 		(void) kmfber_scanf(oidasn1, "n}");
284*e65e5c2dSWyllys Ingersoll 		algoid->parameters.Data = NULL;
285*e65e5c2dSWyllys Ingersoll 		algoid->parameters.Length = 0;
286*e65e5c2dSWyllys Ingersoll 	} else if (tag == KMFBER_END_OF_SEQORSET || tag == KMFBER_DEFAULT) {
287*e65e5c2dSWyllys Ingersoll 		/* close sequence, we are done with Algoid */
28899ebb4caSwyllys 		algoid->parameters.Data = NULL;
28999ebb4caSwyllys 		algoid->parameters.Length = 0;
29099ebb4caSwyllys 	} else {
291*e65e5c2dSWyllys Ingersoll 		/* The rest of the data is the algorithm parameters */
292*e65e5c2dSWyllys Ingersoll 		if ((kmfber_scanf(oidasn1, "tl", &tag, &size)) == -1) {
293*e65e5c2dSWyllys Ingersoll 			rv = KMF_ERR_BAD_CERT_FORMAT;
29499ebb4caSwyllys 			goto cleanup;
29599ebb4caSwyllys 		}
29699ebb4caSwyllys 
29799ebb4caSwyllys 		/*
29899ebb4caSwyllys 		 * We need to read the tag and the length bytes too,
29999ebb4caSwyllys 		 * so adjust the size.
30099ebb4caSwyllys 		 */
30199ebb4caSwyllys 		size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size);
30299ebb4caSwyllys 		algoid->parameters.Data = malloc(size);
30399ebb4caSwyllys 		if (algoid->parameters.Data == NULL) {
304*e65e5c2dSWyllys Ingersoll 			rv = KMF_ERR_MEMORY;
30599ebb4caSwyllys 			goto cleanup;
30699ebb4caSwyllys 		}
30799ebb4caSwyllys 		/* read the raw data into the Algoritm params area. */
308*e65e5c2dSWyllys Ingersoll 		if (kmfber_read(oidasn1, (char *)algoid->parameters.Data,
3092cbed729Swyllys 		    size) == -1) {
310*e65e5c2dSWyllys Ingersoll 			rv = KMF_ERR_BAD_CERT_FORMAT;
31199ebb4caSwyllys 			goto cleanup;
31299ebb4caSwyllys 		}
31399ebb4caSwyllys 		algoid->parameters.Length = size;
31499ebb4caSwyllys 	}
31599ebb4caSwyllys cleanup:
316*e65e5c2dSWyllys Ingersoll 	if (rv != KMF_OK) {
31799ebb4caSwyllys 		free_algoid(algoid);
31899ebb4caSwyllys 	}
319*e65e5c2dSWyllys Ingersoll 	kmfber_free(oidasn1, 1);
32099ebb4caSwyllys 
321*e65e5c2dSWyllys Ingersoll 	return (rv);
32299ebb4caSwyllys }
32399ebb4caSwyllys 
32499ebb4caSwyllys static KMF_RETURN
CopyData(KMF_DATA * src,KMF_DATA * dst)32599ebb4caSwyllys CopyData(KMF_DATA *src, KMF_DATA *dst)
32699ebb4caSwyllys {
32799ebb4caSwyllys 	if (src && dst && src->Data != NULL && src->Length > 0) {
32899ebb4caSwyllys 		dst->Length = src->Length;
32997732469Shaimay 		dst->Data = malloc(dst->Length);
33099ebb4caSwyllys 		if (dst->Data == NULL)
33199ebb4caSwyllys 			return (KMF_ERR_MEMORY);
33299ebb4caSwyllys 		(void) memcpy(dst->Data, src->Data, src->Length);
33399ebb4caSwyllys 	}
33499ebb4caSwyllys 	return (KMF_OK);
33599ebb4caSwyllys }
33699ebb4caSwyllys 
33799ebb4caSwyllys static KMF_RETURN
encode_spki(BerElement * asn1,KMF_X509_SPKI * spki)33899ebb4caSwyllys encode_spki(BerElement *asn1, KMF_X509_SPKI *spki)
33999ebb4caSwyllys {
34099ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
34199ebb4caSwyllys 
34299ebb4caSwyllys 	if (kmfber_printf(asn1, "{") == -1)
34399ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
34499ebb4caSwyllys 
345*e65e5c2dSWyllys Ingersoll 	/*
346*e65e5c2dSWyllys Ingersoll 	 * The SPKI is the only place where algorithm parameters
347*e65e5c2dSWyllys Ingersoll 	 * should be encoded.
348*e65e5c2dSWyllys Ingersoll 	 */
349*e65e5c2dSWyllys Ingersoll 	if ((ret = encode_algoid(asn1, &spki->algorithm, TRUE)) != KMF_OK)
35099ebb4caSwyllys 		return (ret);
35199ebb4caSwyllys 
35299ebb4caSwyllys 	if (kmfber_printf(asn1, "B}", spki->subjectPublicKey.Data,
3532cbed729Swyllys 	    spki->subjectPublicKey.Length * 8) == -1)
35499ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
35599ebb4caSwyllys 
35699ebb4caSwyllys 	return (ret);
35799ebb4caSwyllys }
35899ebb4caSwyllys 
35999ebb4caSwyllys KMF_RETURN
DerEncodeSPKI(KMF_X509_SPKI * spki,KMF_DATA * EncodedSPKI)36099ebb4caSwyllys DerEncodeSPKI(KMF_X509_SPKI *spki, KMF_DATA *EncodedSPKI)
36199ebb4caSwyllys {
36299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
36399ebb4caSwyllys 	BerElement *asn1;
36499ebb4caSwyllys 	BerValue *result;
36599ebb4caSwyllys 
36699ebb4caSwyllys 	if (spki == NULL || EncodedSPKI == NULL)
36799ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
36899ebb4caSwyllys 
36999ebb4caSwyllys 	if ((asn1 = kmfder_alloc()) == NULL)
37099ebb4caSwyllys 		return (KMF_ERR_MEMORY);
37199ebb4caSwyllys 
37299ebb4caSwyllys 	if ((ret = encode_spki(asn1, spki)) != KMF_OK) {
37399ebb4caSwyllys 		return (ret);
37499ebb4caSwyllys 	}
37599ebb4caSwyllys 
37699ebb4caSwyllys 	if (kmfber_flatten(asn1, &result) == -1) {
37799ebb4caSwyllys 		kmfber_free(asn1, 1);
37899ebb4caSwyllys 		return (KMF_ERR_ENCODING);
37999ebb4caSwyllys 	}
38099ebb4caSwyllys 
38199ebb4caSwyllys 	EncodedSPKI->Data = (uchar_t *)result->bv_val;
38299ebb4caSwyllys 	EncodedSPKI->Length = result->bv_len;
38399ebb4caSwyllys 
38499ebb4caSwyllys 	free(result);
38599ebb4caSwyllys 	kmfber_free(asn1, 1);
38699ebb4caSwyllys 	return (KMF_OK);
38799ebb4caSwyllys }
38899ebb4caSwyllys 
38999ebb4caSwyllys static KMF_RETURN
get_spki(BerElement * asn1,KMF_X509_SPKI * spki)39099ebb4caSwyllys get_spki(BerElement *asn1, KMF_X509_SPKI *spki)
39199ebb4caSwyllys {
39299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
39399ebb4caSwyllys 	char *bitstr = NULL;
39499ebb4caSwyllys 	ber_len_t size;
39599ebb4caSwyllys 
39699ebb4caSwyllys 	if (kmfber_scanf(asn1, "{") == -1)
39799ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
39899ebb4caSwyllys 
39999ebb4caSwyllys 	if ((ret = get_algoid(asn1, &spki->algorithm)) != KMF_OK)
40099ebb4caSwyllys 		return (ret);
40199ebb4caSwyllys 
40299ebb4caSwyllys 	if (kmfber_scanf(asn1, "B}", &bitstr, &size) == BER_BIT_STRING) {
40399ebb4caSwyllys 		spki->subjectPublicKey.Data = (uchar_t *)bitstr;
40499ebb4caSwyllys 		spki->subjectPublicKey.Length = size / 8;
40599ebb4caSwyllys 	} else {
40699ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
40799ebb4caSwyllys 		goto cleanup;
40899ebb4caSwyllys 	}
40999ebb4caSwyllys cleanup:
41099ebb4caSwyllys 	if (ret != KMF_OK) {
41199ebb4caSwyllys 		if (bitstr != NULL)
41299ebb4caSwyllys 			free(bitstr);
41399ebb4caSwyllys 		spki->subjectPublicKey.Data = NULL;
41499ebb4caSwyllys 		spki->subjectPublicKey.Length = 0;
41599ebb4caSwyllys 
41699ebb4caSwyllys 		free_algoid(&spki->algorithm);
41799ebb4caSwyllys 	}
41899ebb4caSwyllys 	return (ret);
41999ebb4caSwyllys }
42099ebb4caSwyllys 
421*e65e5c2dSWyllys Ingersoll 
42299ebb4caSwyllys KMF_RETURN
DerEncodeDSASignature(KMF_DATA * rawdata,KMF_DATA * signature)42399ebb4caSwyllys DerEncodeDSASignature(KMF_DATA *rawdata, KMF_DATA *signature)
42499ebb4caSwyllys {
42599ebb4caSwyllys 	BerElement *asn1;
42699ebb4caSwyllys 	BerValue *buf;
42799ebb4caSwyllys 	int n;
42899ebb4caSwyllys 
42999ebb4caSwyllys 	if (rawdata == NULL || signature == NULL)
43099ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
43199ebb4caSwyllys 
432*e65e5c2dSWyllys Ingersoll 	if (rawdata->Data == NULL || rawdata->Length == 0)
43399ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
43499ebb4caSwyllys 
43599ebb4caSwyllys 	asn1 = kmfder_alloc();
43699ebb4caSwyllys 	if (asn1 == NULL)
43799ebb4caSwyllys 		return (KMF_ERR_MEMORY);
43899ebb4caSwyllys 
43999ebb4caSwyllys 	/*
440*e65e5c2dSWyllys Ingersoll 	 * The [EC]DSA signature is the concatenation of 2
44199ebb4caSwyllys 	 * bignum values.
44299ebb4caSwyllys 	 */
443*e65e5c2dSWyllys Ingersoll 	n = rawdata->Length/2;
44499ebb4caSwyllys 	if (kmfber_printf(asn1, "{II}",
4452cbed729Swyllys 	    rawdata->Data, n, &rawdata->Data[n], n) == -1) {
44699ebb4caSwyllys 		kmfber_free(asn1, 1);
44799ebb4caSwyllys 		return (KMF_ERR_MEMORY);
44899ebb4caSwyllys 	}
44999ebb4caSwyllys 
45099ebb4caSwyllys 	if (kmfber_flatten(asn1, &buf) == -1) {
45199ebb4caSwyllys 		kmfber_free(asn1, 1);
45299ebb4caSwyllys 		return (KMF_ERR_ENCODING);
45399ebb4caSwyllys 	}
45499ebb4caSwyllys 
45599ebb4caSwyllys 	signature->Data = (uchar_t *)buf->bv_val;
45699ebb4caSwyllys 	signature->Length = buf->bv_len;
45799ebb4caSwyllys 
45899ebb4caSwyllys 	kmfber_free(asn1, 1);
45999ebb4caSwyllys 	free(buf);
46099ebb4caSwyllys 
46199ebb4caSwyllys 	return (KMF_OK);
46299ebb4caSwyllys }
46399ebb4caSwyllys 
464*e65e5c2dSWyllys Ingersoll /*
465*e65e5c2dSWyllys Ingersoll  * ECDSA and DSA encode signatures the same way.
466*e65e5c2dSWyllys Ingersoll  */
467*e65e5c2dSWyllys Ingersoll KMF_RETURN
DerEncodeECDSASignature(KMF_DATA * rawdata,KMF_DATA * signature)468*e65e5c2dSWyllys Ingersoll DerEncodeECDSASignature(KMF_DATA *rawdata, KMF_DATA *signature)
469*e65e5c2dSWyllys Ingersoll {
470*e65e5c2dSWyllys Ingersoll 	return (DerEncodeDSASignature(rawdata, signature));
471*e65e5c2dSWyllys Ingersoll }
472*e65e5c2dSWyllys Ingersoll 
473*e65e5c2dSWyllys Ingersoll /*
474*e65e5c2dSWyllys Ingersoll  * Convert a signed DSA sig to a fixed-length unsigned one.
475*e65e5c2dSWyllys Ingersoll  * This is necessary because DER encoding seeks to use the
476*e65e5c2dSWyllys Ingersoll  * minimal amount of bytes but we need a full 20 byte DSA
477*e65e5c2dSWyllys Ingersoll  * value with leading 0x00 bytes.
478*e65e5c2dSWyllys Ingersoll  */
479*e65e5c2dSWyllys Ingersoll static KMF_RETURN
convert_signed_to_fixed(BerValue * src,BerValue * dst)480*e65e5c2dSWyllys Ingersoll convert_signed_to_fixed(BerValue *src, BerValue *dst)
481*e65e5c2dSWyllys Ingersoll {
482*e65e5c2dSWyllys Ingersoll 	int cnt;
483*e65e5c2dSWyllys Ingersoll 	char *p;
484*e65e5c2dSWyllys Ingersoll 	if (dst->bv_len > src->bv_len) {
485*e65e5c2dSWyllys Ingersoll 		cnt = dst->bv_len - src->bv_len;
486*e65e5c2dSWyllys Ingersoll 		/* prepend with leading 0s */
487*e65e5c2dSWyllys Ingersoll 		(void) memset(dst->bv_val, 0x00, cnt);
488*e65e5c2dSWyllys Ingersoll 		(void) memcpy(dst->bv_val + cnt, src->bv_val,
489*e65e5c2dSWyllys Ingersoll 		    src->bv_len);
490*e65e5c2dSWyllys Ingersoll 		return (KMF_OK);
491*e65e5c2dSWyllys Ingersoll 	}
492*e65e5c2dSWyllys Ingersoll 	if (dst->bv_len == src->bv_len) {
493*e65e5c2dSWyllys Ingersoll 		(void) memcpy(dst->bv_val, src->bv_val,
494*e65e5c2dSWyllys Ingersoll 		    dst->bv_len);
495*e65e5c2dSWyllys Ingersoll 		return (KMF_OK);
496*e65e5c2dSWyllys Ingersoll 	}
497*e65e5c2dSWyllys Ingersoll 	/*
498*e65e5c2dSWyllys Ingersoll 	 * src is larger than dest, strip leading 0s.
499*e65e5c2dSWyllys Ingersoll 	 * This should not be necessary, but do it just in case.
500*e65e5c2dSWyllys Ingersoll 	 */
501*e65e5c2dSWyllys Ingersoll 	cnt = src->bv_len - dst->bv_len;
502*e65e5c2dSWyllys Ingersoll 	p = src->bv_val;
503*e65e5c2dSWyllys Ingersoll 	while (cnt-- > 0) {
504*e65e5c2dSWyllys Ingersoll 		if (*p++ != 0x00)
505*e65e5c2dSWyllys Ingersoll 			return (KMF_ERR_ENCODING);
506*e65e5c2dSWyllys Ingersoll 	}
507*e65e5c2dSWyllys Ingersoll 	(void) memcpy(dst->bv_val, p, dst->bv_len);
508*e65e5c2dSWyllys Ingersoll 	return (KMF_OK);
509*e65e5c2dSWyllys Ingersoll }
510*e65e5c2dSWyllys Ingersoll 
51199ebb4caSwyllys KMF_RETURN
DerDecodeDSASignature(KMF_DATA * encoded,KMF_DATA * signature)51299ebb4caSwyllys DerDecodeDSASignature(KMF_DATA *encoded, KMF_DATA *signature)
51399ebb4caSwyllys {
51499ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
51599ebb4caSwyllys 	BerElement *asn1 = NULL;
51699ebb4caSwyllys 	BerValue buf, *R = NULL, *S = NULL;
517*e65e5c2dSWyllys Ingersoll 	BerValue fixedR, fixedS;
51899ebb4caSwyllys 
51999ebb4caSwyllys 	buf.bv_val = (char *)encoded->Data;
52099ebb4caSwyllys 	buf.bv_len = encoded->Length;
52199ebb4caSwyllys 
52299ebb4caSwyllys 	if (encoded == NULL || encoded->Data == NULL ||
52399ebb4caSwyllys 	    signature == NULL)
52499ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
52599ebb4caSwyllys 
52699ebb4caSwyllys 	signature->Data = NULL;
52799ebb4caSwyllys 	signature->Length = 0;
52899ebb4caSwyllys 
52999ebb4caSwyllys 	if ((asn1 = kmfder_init(&buf)) == NULL)
53099ebb4caSwyllys 		return (KMF_ERR_MEMORY);
53199ebb4caSwyllys 
53299ebb4caSwyllys 	if (kmfber_scanf(asn1, "{II}", &R, &S) == -1) {
53399ebb4caSwyllys 		ret = KMF_ERR_BAD_PARAMETER;
53499ebb4caSwyllys 		goto cleanup;
53599ebb4caSwyllys 	}
53699ebb4caSwyllys 	signature->Length = R->bv_len + S->bv_len;
537*e65e5c2dSWyllys Ingersoll 	/*
538*e65e5c2dSWyllys Ingersoll 	 * If either of the values had a leading 0 lopped off
539*e65e5c2dSWyllys Ingersoll 	 * they will be 1 byte short and need to be adjusted below.
540*e65e5c2dSWyllys Ingersoll 	 * The stripping is correct as per ASN.1 rules.
541*e65e5c2dSWyllys Ingersoll 	 *
542*e65e5c2dSWyllys Ingersoll 	 * We don't know the exact length that the R and S values
543*e65e5c2dSWyllys Ingersoll 	 * must be, it depends on the signature algorithm and,
544*e65e5c2dSWyllys Ingersoll 	 * in the case of EC, the curve used. So instead of
545*e65e5c2dSWyllys Ingersoll 	 * checking for a specific length, we just check to see
546*e65e5c2dSWyllys Ingersoll 	 * if the value came out to be an odd number.  If so,
547*e65e5c2dSWyllys Ingersoll 	 * then we know it needs a leading 0x00 byte which
548*e65e5c2dSWyllys Ingersoll 	 * will be added below when we convert it to a fixed
549*e65e5c2dSWyllys Ingersoll 	 * length.
550*e65e5c2dSWyllys Ingersoll 	 */
551*e65e5c2dSWyllys Ingersoll 	if ((R->bv_len % 2) != 0)
552*e65e5c2dSWyllys Ingersoll 		signature->Length++;
553*e65e5c2dSWyllys Ingersoll 	if ((S->bv_len % 2) != 0)
554*e65e5c2dSWyllys Ingersoll 		signature->Length++;
555*e65e5c2dSWyllys Ingersoll 
55699ebb4caSwyllys 	signature->Data = malloc(signature->Length);
55799ebb4caSwyllys 	if (signature->Data == NULL)  {
55899ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
55999ebb4caSwyllys 		goto cleanup;
56099ebb4caSwyllys 	}
561*e65e5c2dSWyllys Ingersoll 	fixedR.bv_val = (char *)signature->Data;
562*e65e5c2dSWyllys Ingersoll 	/* adjust length if it needs a leading 0x00 byte */
563*e65e5c2dSWyllys Ingersoll 	fixedR.bv_len = R->bv_len + (R->bv_len % 2);
564*e65e5c2dSWyllys Ingersoll 
565*e65e5c2dSWyllys Ingersoll 	fixedS.bv_val = (char *)(signature->Data + fixedR.bv_len);
566*e65e5c2dSWyllys Ingersoll 	/* adjust length if it needs a leading 0x00 byte */
567*e65e5c2dSWyllys Ingersoll 	fixedS.bv_len = S->bv_len + (S->bv_len % 2);
568*e65e5c2dSWyllys Ingersoll 
569*e65e5c2dSWyllys Ingersoll 	/*
570*e65e5c2dSWyllys Ingersoll 	 * This will add back any missing leading 0's
571*e65e5c2dSWyllys Ingersoll 	 * that were stripped off earlier when the signature
572*e65e5c2dSWyllys Ingersoll 	 * was parsed.  This ensures that the 2 parts of the
573*e65e5c2dSWyllys Ingersoll 	 * signature are the right length and have the proper
574*e65e5c2dSWyllys Ingersoll 	 * leading 0's prepended.
575*e65e5c2dSWyllys Ingersoll 	 */
576*e65e5c2dSWyllys Ingersoll 	ret = convert_signed_to_fixed(R, &fixedR);
577*e65e5c2dSWyllys Ingersoll 	if (ret)
578*e65e5c2dSWyllys Ingersoll 		goto cleanup;
57999ebb4caSwyllys 
580*e65e5c2dSWyllys Ingersoll 	ret = convert_signed_to_fixed(S, &fixedS);
58199ebb4caSwyllys cleanup:
58299ebb4caSwyllys 	if (R && R->bv_val)
58399ebb4caSwyllys 		free(R->bv_val);
58499ebb4caSwyllys 	if (S && S->bv_val)
58599ebb4caSwyllys 		free(S->bv_val);
58699ebb4caSwyllys 
58799ebb4caSwyllys 	if (S) free(S);
58899ebb4caSwyllys 	if (R) free(R);
58999ebb4caSwyllys 
59099ebb4caSwyllys 	if (asn1) kmfber_free(asn1, 1);
59199ebb4caSwyllys 
59299ebb4caSwyllys 	return (ret);
59399ebb4caSwyllys }
59499ebb4caSwyllys 
595*e65e5c2dSWyllys Ingersoll KMF_RETURN
DerDecodeECDSASignature(KMF_DATA * encoded,KMF_DATA * signature)596*e65e5c2dSWyllys Ingersoll DerDecodeECDSASignature(KMF_DATA *encoded, KMF_DATA *signature)
597*e65e5c2dSWyllys Ingersoll {
598*e65e5c2dSWyllys Ingersoll 	/* ECDSA can be decoded using same code as standard DSA */
599*e65e5c2dSWyllys Ingersoll 	return (DerDecodeDSASignature(encoded, signature));
600*e65e5c2dSWyllys Ingersoll }
601*e65e5c2dSWyllys Ingersoll 
60299ebb4caSwyllys KMF_RETURN
DerDecodeSPKI(KMF_DATA * EncodedSPKI,KMF_X509_SPKI * spki)60399ebb4caSwyllys DerDecodeSPKI(KMF_DATA *EncodedSPKI, KMF_X509_SPKI *spki)
60499ebb4caSwyllys {
60599ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
60699ebb4caSwyllys 	BerElement *asn1;
60799ebb4caSwyllys 	BerValue bv;
60899ebb4caSwyllys 
60999ebb4caSwyllys 	if (EncodedSPKI == NULL || EncodedSPKI->Data == NULL ||
6102cbed729Swyllys 	    spki == NULL)
61199ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
61299ebb4caSwyllys 
61399ebb4caSwyllys 	(void) memset(spki, 0, sizeof (KMF_X509_SPKI));
61499ebb4caSwyllys 
61599ebb4caSwyllys 	bv.bv_val = (char *)EncodedSPKI->Data;
61699ebb4caSwyllys 	bv.bv_len = EncodedSPKI->Length;
61799ebb4caSwyllys 
61899ebb4caSwyllys 	if ((asn1 = kmfder_init(&bv)) == NULL)
61999ebb4caSwyllys 		return (KMF_ERR_MEMORY);
62099ebb4caSwyllys 
62199ebb4caSwyllys 	ret = get_spki(asn1, spki);
62299ebb4caSwyllys 
62399ebb4caSwyllys cleanup:
62499ebb4caSwyllys 	if (ret != KMF_OK) {
62599ebb4caSwyllys 		free_decoded_spki(spki);
62699ebb4caSwyllys 	}
62799ebb4caSwyllys 	kmfber_free(asn1, 1);
62899ebb4caSwyllys 
62999ebb4caSwyllys 	return (ret);
63099ebb4caSwyllys }
63199ebb4caSwyllys 
63299ebb4caSwyllys KMF_RETURN
CopySPKI(KMF_X509_SPKI * src,KMF_X509_SPKI ** dest)63399ebb4caSwyllys CopySPKI(KMF_X509_SPKI *src,
63499ebb4caSwyllys 		KMF_X509_SPKI **dest)
63599ebb4caSwyllys {
63699ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
63799ebb4caSwyllys 	KMF_X509_SPKI *newspki;
63899ebb4caSwyllys 
63999ebb4caSwyllys 	*dest = NULL;
64099ebb4caSwyllys 
64199ebb4caSwyllys 	newspki = malloc(sizeof (KMF_X509_SPKI));
64299ebb4caSwyllys 	if (newspki == NULL)
64399ebb4caSwyllys 		return (KMF_ERR_MEMORY);
64499ebb4caSwyllys 	(void) memset(newspki, 0, sizeof (KMF_X509_SPKI));
64599ebb4caSwyllys 
64699ebb4caSwyllys 	ret = CopyData(&src->algorithm.algorithm,
6472cbed729Swyllys 	    &newspki->algorithm.algorithm);
64899ebb4caSwyllys 	if (ret != KMF_OK)
64999ebb4caSwyllys 		goto cleanup;
65099ebb4caSwyllys 
65199ebb4caSwyllys 	ret = CopyData(&src->algorithm.parameters,
6522cbed729Swyllys 	    &newspki->algorithm.parameters);
65399ebb4caSwyllys 	if (ret != KMF_OK)
65499ebb4caSwyllys 		goto cleanup;
65599ebb4caSwyllys 
65699ebb4caSwyllys 	ret = CopyData(&src->subjectPublicKey,
6572cbed729Swyllys 	    &newspki->subjectPublicKey);
65899ebb4caSwyllys 	if (ret != KMF_OK)
65999ebb4caSwyllys 		goto cleanup;
66099ebb4caSwyllys 
66199ebb4caSwyllys 	*dest = newspki;
66299ebb4caSwyllys cleanup:
66399ebb4caSwyllys 	if (ret != KMF_OK) {
66499ebb4caSwyllys 		if (newspki)
66599ebb4caSwyllys 			free_decoded_spki(newspki);
66699ebb4caSwyllys 	}
66799ebb4caSwyllys 	return (ret);
66899ebb4caSwyllys }
66999ebb4caSwyllys 
67099ebb4caSwyllys static KMF_RETURN
encode_validity(BerElement * asn1,KMF_X509_VALIDITY * validity)67199ebb4caSwyllys encode_validity(BerElement *asn1, KMF_X509_VALIDITY *validity)
67299ebb4caSwyllys {
67399ebb4caSwyllys 	int ret;
67499ebb4caSwyllys 
67599ebb4caSwyllys 	ret = kmfber_printf(asn1, "{tsts}",
6762cbed729Swyllys 	    validity->notBefore.timeType,
6772cbed729Swyllys 	    validity->notBefore.time.Data,
6782cbed729Swyllys 	    validity->notAfter.timeType,
6792cbed729Swyllys 	    validity->notAfter.time.Data);
68099ebb4caSwyllys 
68199ebb4caSwyllys 	if (ret == -1)
68299ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
68399ebb4caSwyllys 
68499ebb4caSwyllys 	return (KMF_OK);
68599ebb4caSwyllys }
68699ebb4caSwyllys 
68799ebb4caSwyllys static KMF_RETURN
get_validity(BerElement * asn1,KMF_X509_VALIDITY * validity)68899ebb4caSwyllys get_validity(BerElement *asn1, KMF_X509_VALIDITY *validity)
68999ebb4caSwyllys {
69099ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
69199ebb4caSwyllys 	int tag;
69299ebb4caSwyllys 	int t1, t2;
69399ebb4caSwyllys 	ber_len_t size;
69499ebb4caSwyllys 	char *t1str, *t2str;
69599ebb4caSwyllys 
69699ebb4caSwyllys 	(void) memset(validity, 0, sizeof (KMF_X509_VALIDITY));
69799ebb4caSwyllys 
69899ebb4caSwyllys 	tag = kmfber_next_element(asn1, &size, NULL);
69999ebb4caSwyllys 	if (tag != BER_CONSTRUCTED_SEQUENCE) {
70099ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
70199ebb4caSwyllys 	}
70299ebb4caSwyllys 
70399ebb4caSwyllys 	if (kmfber_scanf(asn1, "{tata}", &t1, &t1str, &t2, &t2str) == -1) {
70499ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
70599ebb4caSwyllys 	}
70699ebb4caSwyllys 
70799ebb4caSwyllys 	validity->notBefore.timeType = t1;
70899ebb4caSwyllys 	validity->notBefore.time.Data = (uchar_t *)t1str;
70999ebb4caSwyllys 	validity->notBefore.time.Length = strlen(t1str);
71099ebb4caSwyllys 
71199ebb4caSwyllys 	validity->notAfter.timeType = t2;
71299ebb4caSwyllys 	validity->notAfter.time.Data = (uchar_t *)t2str;
71399ebb4caSwyllys 	validity->notAfter.time.Length = strlen(t2str);
71499ebb4caSwyllys 
71599ebb4caSwyllys 	return (ret);
71699ebb4caSwyllys }
71799ebb4caSwyllys 
71899ebb4caSwyllys KMF_RETURN
AddRDN(KMF_X509_NAME * name,KMF_X509_RDN * newrdn)71999ebb4caSwyllys AddRDN(KMF_X509_NAME *name, KMF_X509_RDN *newrdn)
72099ebb4caSwyllys {
72199ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
72299ebb4caSwyllys 	KMF_X509_RDN *rdnslot = NULL;
72399ebb4caSwyllys 
72499ebb4caSwyllys 	/* Add new RDN record to existing list */
72599ebb4caSwyllys 	name->numberOfRDNs++;
72699ebb4caSwyllys 	name->RelativeDistinguishedName =
7272cbed729Swyllys 	    realloc(name->RelativeDistinguishedName,
7282cbed729Swyllys 	    name->numberOfRDNs * sizeof (KMF_X509_RDN));
72999ebb4caSwyllys 
73099ebb4caSwyllys 	if (name->RelativeDistinguishedName == NULL) {
73199ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
73299ebb4caSwyllys 		goto cleanup;
73399ebb4caSwyllys 	}
73499ebb4caSwyllys 	rdnslot = &name->RelativeDistinguishedName[name->numberOfRDNs-1];
73599ebb4caSwyllys 
73699ebb4caSwyllys 	if (newrdn) {
73799ebb4caSwyllys 		(void) memcpy(rdnslot, newrdn, sizeof (KMF_X509_RDN));
73899ebb4caSwyllys 	} else {
73999ebb4caSwyllys 		rdnslot->numberOfPairs = 0;
74099ebb4caSwyllys 		rdnslot->AttributeTypeAndValue = NULL;
74199ebb4caSwyllys 	}
74299ebb4caSwyllys 
74399ebb4caSwyllys cleanup:
74499ebb4caSwyllys 	/* No cleanup needed here */
74599ebb4caSwyllys 	return (ret);
74699ebb4caSwyllys }
74799ebb4caSwyllys 
74899ebb4caSwyllys static KMF_RETURN
encode_rdn(BerElement * asn1,KMF_X509_NAME * name)74999ebb4caSwyllys encode_rdn(BerElement *asn1, KMF_X509_NAME *name)
75099ebb4caSwyllys {
75199ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
75299ebb4caSwyllys 	KMF_X509_TYPE_VALUE_PAIR *attrtvpair = NULL;
75399ebb4caSwyllys 	int i;
75499ebb4caSwyllys 	KMF_X509_RDN *rdn;
75599ebb4caSwyllys 
75699ebb4caSwyllys 	if (kmfber_printf(asn1, "{") == -1) {
75799ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
75899ebb4caSwyllys 		goto cleanup;
75999ebb4caSwyllys 	}
76099ebb4caSwyllys 
76199ebb4caSwyllys 	for (i = 0; i < name->numberOfRDNs; i++) {
76299ebb4caSwyllys 		if (kmfber_printf(asn1, "[") == -1) {
76399ebb4caSwyllys 			ret = KMF_ERR_MEMORY;
76499ebb4caSwyllys 			goto cleanup;
76599ebb4caSwyllys 		}
76699ebb4caSwyllys 		rdn = &name->RelativeDistinguishedName[i];
76799ebb4caSwyllys 		attrtvpair = rdn->AttributeTypeAndValue;
76899ebb4caSwyllys 
76999ebb4caSwyllys 		if (rdn->numberOfPairs > 0) {
77099ebb4caSwyllys 			if (kmfber_printf(asn1, "{Dto}",
7712cbed729Swyllys 			    &attrtvpair->type,
7722cbed729Swyllys 			    attrtvpair->valueType,
7732cbed729Swyllys 			    attrtvpair->value.Data,
7742cbed729Swyllys 			    attrtvpair->value.Length) == -1) {
77599ebb4caSwyllys 				ret = KMF_ERR_MEMORY;
77699ebb4caSwyllys 				goto cleanup;
77799ebb4caSwyllys 			}
77899ebb4caSwyllys 		}
77999ebb4caSwyllys 		if (kmfber_printf(asn1, "]") == -1) {
78099ebb4caSwyllys 			ret = KMF_ERR_MEMORY;
78199ebb4caSwyllys 			goto cleanup;
78299ebb4caSwyllys 		}
78399ebb4caSwyllys 	}
78499ebb4caSwyllys 
78599ebb4caSwyllys 	if (kmfber_printf(asn1, "}") == -1) {
78699ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
78799ebb4caSwyllys 		goto cleanup;
78899ebb4caSwyllys 	}
78999ebb4caSwyllys 
79099ebb4caSwyllys cleanup:
79199ebb4caSwyllys 	/* No cleanup needed here */
79299ebb4caSwyllys 
79399ebb4caSwyllys 	return (ret);
79499ebb4caSwyllys }
79599ebb4caSwyllys 
79699ebb4caSwyllys 
79799ebb4caSwyllys KMF_RETURN
CopyRDN(KMF_X509_NAME * srcname,KMF_X509_NAME ** destname)79899ebb4caSwyllys CopyRDN(KMF_X509_NAME *srcname, KMF_X509_NAME **destname)
79999ebb4caSwyllys {
80099ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
80199ebb4caSwyllys 	KMF_X509_NAME 		*newname = NULL;
80299ebb4caSwyllys 	KMF_X509_RDN 		*rdn, *dstrdn;
80399ebb4caSwyllys 	KMF_X509_TYPE_VALUE_PAIR *av = NULL;
80499ebb4caSwyllys 	KMF_X509_TYPE_VALUE_PAIR *srcav = NULL;
80599ebb4caSwyllys 	KMF_X509_TYPE_VALUE_PAIR *dstav = NULL;
80699ebb4caSwyllys 	int i, j;
80799ebb4caSwyllys 
80899ebb4caSwyllys 	newname = malloc(sizeof (KMF_X509_NAME));
80999ebb4caSwyllys 	if (newname == NULL)
81099ebb4caSwyllys 		return (KMF_ERR_MEMORY);
81199ebb4caSwyllys 	(void) memset(newname, 0, sizeof (KMF_X509_NAME));
81299ebb4caSwyllys 
81399ebb4caSwyllys 	newname->numberOfRDNs = srcname->numberOfRDNs;
81499ebb4caSwyllys 	newname->RelativeDistinguishedName = malloc(newname->numberOfRDNs *
8152cbed729Swyllys 	    sizeof (KMF_X509_RDN));
81699ebb4caSwyllys 	if (newname->RelativeDistinguishedName == NULL) {
81799ebb4caSwyllys 		free(newname);
81899ebb4caSwyllys 		return (KMF_ERR_MEMORY);
81999ebb4caSwyllys 	}
82099ebb4caSwyllys 	/* Copy each RDN in the list */
82199ebb4caSwyllys 	for (i = 0; i < newname->numberOfRDNs; i++) {
82299ebb4caSwyllys 		rdn = &srcname->RelativeDistinguishedName[i];
82399ebb4caSwyllys 
82499ebb4caSwyllys 		dstrdn = &newname->RelativeDistinguishedName[i];
82599ebb4caSwyllys 		(void) memset(dstrdn, 0, sizeof (KMF_X509_RDN));
82699ebb4caSwyllys 
82799ebb4caSwyllys 		dstrdn->numberOfPairs = rdn->numberOfPairs;
82899ebb4caSwyllys 		if (dstrdn->numberOfPairs > 0) {
82999ebb4caSwyllys 			av = malloc(dstrdn->numberOfPairs *
8302cbed729Swyllys 			    sizeof (KMF_X509_TYPE_VALUE_PAIR));
83199ebb4caSwyllys 			if (av == NULL) {
83299ebb4caSwyllys 				ret = KMF_ERR_MEMORY;
83399ebb4caSwyllys 				goto cleanup;
83499ebb4caSwyllys 			}
83599ebb4caSwyllys 			(void) memset(av, 0, dstrdn->numberOfPairs *
8362cbed729Swyllys 			    sizeof (KMF_X509_TYPE_VALUE_PAIR));
83799ebb4caSwyllys 
83899ebb4caSwyllys 			dstrdn->AttributeTypeAndValue = av;
83999ebb4caSwyllys 			if (av == NULL) {
84099ebb4caSwyllys 				ret = KMF_ERR_MEMORY;
84199ebb4caSwyllys 				goto cleanup;
84299ebb4caSwyllys 			}
84399ebb4caSwyllys 			/* Copy each A/V pair in the list */
84499ebb4caSwyllys 			for (j = 0; j < dstrdn->numberOfPairs; j++) {
84599ebb4caSwyllys 				srcav = &rdn->AttributeTypeAndValue[j];
84699ebb4caSwyllys 				dstav = &dstrdn->AttributeTypeAndValue[j];
84799ebb4caSwyllys 				if ((ret = CopyData(&srcav->type,
8482cbed729Swyllys 				    &dstav->type)) != KMF_OK)
84999ebb4caSwyllys 					goto cleanup;
85099ebb4caSwyllys 				dstav->valueType = srcav->valueType;
85199ebb4caSwyllys 				if ((ret = CopyData(&srcav->value,
8522cbed729Swyllys 				    &dstav->value)) != KMF_OK)
85399ebb4caSwyllys 					goto cleanup;
85499ebb4caSwyllys 			}
85599ebb4caSwyllys 		} else {
85699ebb4caSwyllys 			dstrdn->AttributeTypeAndValue = NULL;
85799ebb4caSwyllys 		}
85899ebb4caSwyllys 	}
85999ebb4caSwyllys 	*destname = newname;
86099ebb4caSwyllys 
86199ebb4caSwyllys cleanup:
86299ebb4caSwyllys 	if (ret != KMF_OK) {
86399ebb4caSwyllys 		if (newname)
86499ebb4caSwyllys 			free_rdn_data(newname);
86599ebb4caSwyllys 
86699ebb4caSwyllys 		free(newname);
86799ebb4caSwyllys 		*destname = NULL;
86899ebb4caSwyllys 	}
86999ebb4caSwyllys 	return (ret);
87099ebb4caSwyllys }
87199ebb4caSwyllys 
87299ebb4caSwyllys #define	VALID_DIRECTORYSTRING_TAG(t) ( \
87399ebb4caSwyllys 	(t == BER_UTF8_STRING) || \
87499ebb4caSwyllys 	(t == BER_PRINTABLE_STRING) || \
87599ebb4caSwyllys 	(t == BER_IA5STRING) || \
87699ebb4caSwyllys 	(t == BER_T61STRING) || \
87799ebb4caSwyllys 	(t == BER_BMP_STRING) || \
87899ebb4caSwyllys 	(t == BER_UNIVERSAL_STRING))
87999ebb4caSwyllys 
88099ebb4caSwyllys static KMF_RETURN
get_rdn(BerElement * asn1,KMF_X509_NAME * name)88199ebb4caSwyllys get_rdn(BerElement *asn1, KMF_X509_NAME *name)
88299ebb4caSwyllys {
88399ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
88499ebb4caSwyllys 	ber_len_t size;
88599ebb4caSwyllys 	char *end;
88699ebb4caSwyllys 	int tag;
88799ebb4caSwyllys 	BerValue AttrOID;
88899ebb4caSwyllys 	char *AttrValue = NULL;
88999ebb4caSwyllys 	KMF_X509_TYPE_VALUE_PAIR *newpair = NULL;
89099ebb4caSwyllys 	KMF_X509_RDN 		newrdn;
89199ebb4caSwyllys 
89299ebb4caSwyllys 	/*
89399ebb4caSwyllys 	 * AttributeType	::=  OBJECT IDENTIFIER
89499ebb4caSwyllys 	 * AttributeValue	::=  ANY
89599ebb4caSwyllys 	 *
89699ebb4caSwyllys 	 * AttributeTypeAndValue	::=  SEQUENCE {
89799ebb4caSwyllys 	 *	type    AttributeType,
89899ebb4caSwyllys 	 *	value   AttributeValue }
89999ebb4caSwyllys 	 *
90099ebb4caSwyllys 	 * Name ::= CHOICE { -- only one possibility for now --
90199ebb4caSwyllys 	 * 		rdnSequence  RDNSequence }
90299ebb4caSwyllys 	 *
90399ebb4caSwyllys 	 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
90499ebb4caSwyllys 	 *
90599ebb4caSwyllys 	 * DistinguishedName ::=   RDNSequence
90699ebb4caSwyllys 	 *
90799ebb4caSwyllys 	 * RelativeDistinguishedName  ::=
90899ebb4caSwyllys 	 *		 SET SIZE (1 .. MAX) OF AttributeTypeAndValue
90999ebb4caSwyllys 	 *
91099ebb4caSwyllys 	 */
91199ebb4caSwyllys 
91299ebb4caSwyllys 	name->numberOfRDNs = 0;
91399ebb4caSwyllys 	name->RelativeDistinguishedName = NULL;
91499ebb4caSwyllys 
91599ebb4caSwyllys 	/* Get the beginning of the RDN Set and a ptr to the end */
91699ebb4caSwyllys 	tag = kmfber_first_element(asn1, &size, &end);
91799ebb4caSwyllys 	if (tag != BER_CONSTRUCTED_SET) {
91899ebb4caSwyllys 		goto cleanup;
91999ebb4caSwyllys 	}
92099ebb4caSwyllys 
92199ebb4caSwyllys 	/* Walk through the individual SET items until the "end" is reached */
92299ebb4caSwyllys 	while ((tag = kmfber_next_element(asn1, &size, end)) ==
9232cbed729Swyllys 	    BER_CONSTRUCTED_SET) {
92499ebb4caSwyllys 		/* Skip over the SET tag */
92599ebb4caSwyllys 		if (kmfber_scanf(asn1, "T", &tag) == -1) {
92699ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
92799ebb4caSwyllys 			break;
92899ebb4caSwyllys 		}
92999ebb4caSwyllys 
93099ebb4caSwyllys 		/* An "empty" set member means we tack on an empty node */
93199ebb4caSwyllys 		if (size == 0) {
93299ebb4caSwyllys 			if ((ret = AddRDN(name, NULL)) != KMF_OK)
93399ebb4caSwyllys 				goto cleanup;
93499ebb4caSwyllys 			continue;
93599ebb4caSwyllys 		}
93699ebb4caSwyllys 
93799ebb4caSwyllys 		/* Attr OID and peek at the next tag and field length */
93899ebb4caSwyllys 		if (kmfber_scanf(asn1, "{Dtl", &AttrOID, &tag, &size) == -1) {
93999ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
94099ebb4caSwyllys 			break;
94199ebb4caSwyllys 		}
94299ebb4caSwyllys 
94399ebb4caSwyllys 		if (!(VALID_DIRECTORYSTRING_TAG(tag))) {
94499ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
94599ebb4caSwyllys 			break;
94699ebb4caSwyllys 		}
94799ebb4caSwyllys 
94899ebb4caSwyllys 		if (kmfber_scanf(asn1, "a}]", &AttrValue) == -1) {
94999ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
95099ebb4caSwyllys 			break;
95199ebb4caSwyllys 		}
95299ebb4caSwyllys 
95399ebb4caSwyllys 		/* Allocate a new name/value pair record */
95499ebb4caSwyllys 		newpair = malloc(sizeof (KMF_X509_TYPE_VALUE_PAIR));
95599ebb4caSwyllys 		if (newpair == NULL) {
95699ebb4caSwyllys 			ret = KMF_ERR_MEMORY;
95799ebb4caSwyllys 			break;
95899ebb4caSwyllys 		}
95999ebb4caSwyllys 		(void) memset(newpair, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR));
96099ebb4caSwyllys 		newpair->type.Data = (uchar_t *)AttrOID.bv_val;
96199ebb4caSwyllys 		newpair->type.Length = AttrOID.bv_len;
96299ebb4caSwyllys 		newpair->valueType = tag; /* what kind of string is it? */
96399ebb4caSwyllys 		newpair->value.Data = (uchar_t *)AttrValue;
96499ebb4caSwyllys 		newpair->value.Length = strlen(AttrValue);
96599ebb4caSwyllys 
96699ebb4caSwyllys 		(void) memset(&newrdn, 0, sizeof (KMF_X509_RDN));
96799ebb4caSwyllys 		newrdn.numberOfPairs = 1;
96899ebb4caSwyllys 		newrdn.AttributeTypeAndValue = newpair;
96999ebb4caSwyllys 
97099ebb4caSwyllys 		if ((ret = AddRDN(name, &newrdn)) != KMF_OK)
97199ebb4caSwyllys 			break;
97299ebb4caSwyllys 	}
97399ebb4caSwyllys 
97499ebb4caSwyllys cleanup:
97599ebb4caSwyllys 	if (ret != KMF_OK) {
97699ebb4caSwyllys 		free_rdn_data(name);
97799ebb4caSwyllys 	}
97899ebb4caSwyllys 	return (ret);
97999ebb4caSwyllys }
98099ebb4caSwyllys 
98199ebb4caSwyllys static KMF_RETURN
set_der_integer(KMF_DATA * data,int value)98299ebb4caSwyllys set_der_integer(KMF_DATA *data, int value)
98399ebb4caSwyllys {
98499ebb4caSwyllys 	if (data == NULL)
98599ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
98699ebb4caSwyllys 
98799ebb4caSwyllys 	data->Data = malloc(sizeof (int));
98899ebb4caSwyllys 	if (data->Data == NULL)
98999ebb4caSwyllys 		return (KMF_ERR_MEMORY);
99099ebb4caSwyllys 
99199ebb4caSwyllys 	data->Length = sizeof (int);
99299ebb4caSwyllys 	(void) memcpy((void *)data->Data, (const void *)&value, sizeof (int));
99399ebb4caSwyllys 
99499ebb4caSwyllys 	return (KMF_OK);
99599ebb4caSwyllys }
99699ebb4caSwyllys 
99799ebb4caSwyllys static KMF_RETURN
set_bigint(KMF_BIGINT * data,KMF_BIGINT * bigint)99899ebb4caSwyllys set_bigint(KMF_BIGINT *data, KMF_BIGINT *bigint)
99999ebb4caSwyllys {
100099ebb4caSwyllys 	if (data == NULL || bigint == NULL)
100199ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
100299ebb4caSwyllys 
100399ebb4caSwyllys 	data->val = malloc(bigint->len);
100499ebb4caSwyllys 	if (data->val == NULL)
100599ebb4caSwyllys 		return (KMF_ERR_MEMORY);
100699ebb4caSwyllys 
100799ebb4caSwyllys 	data->len = bigint->len;
100899ebb4caSwyllys 	(void) memcpy((void *)data->val, (const void *)bigint->val,
10092cbed729Swyllys 	    bigint->len);
101099ebb4caSwyllys 
101199ebb4caSwyllys 	return (KMF_OK);
101299ebb4caSwyllys }
101399ebb4caSwyllys 
101499ebb4caSwyllys static KMF_RETURN
encode_uniqueid(BerElement * asn1,int tag,KMF_DATA * id)101599ebb4caSwyllys encode_uniqueid(BerElement *asn1, int tag, KMF_DATA *id)
101699ebb4caSwyllys {
101799ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
101899ebb4caSwyllys 	uint32_t len;
101999ebb4caSwyllys 
102099ebb4caSwyllys 	len = kmfber_calc_taglen(BER_BIT_STRING) +
10212cbed729Swyllys 	    kmfber_calc_lenlen(id->Length * 8) + id->Length;
102299ebb4caSwyllys 	if (kmfber_printf(asn1, "TlB", tag, len,
10232cbed729Swyllys 	    id->Data, id->Length * 8) == -1)
102499ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
102599ebb4caSwyllys 
102699ebb4caSwyllys 	return (ret);
102799ebb4caSwyllys }
102899ebb4caSwyllys 
102999ebb4caSwyllys static KMF_RETURN
encode_extension_list(BerElement * asn1,KMF_X509_EXTENSIONS * extns)103099ebb4caSwyllys encode_extension_list(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
103199ebb4caSwyllys {
103299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
103399ebb4caSwyllys 	int i;
103499ebb4caSwyllys 
103599ebb4caSwyllys 	for (i = 0; i < extns->numberOfExtensions; i++) {
103699ebb4caSwyllys 		BerValue v;
103799ebb4caSwyllys 		v.bv_val = (char *)extns->extensions[i].extnId.Data;
103899ebb4caSwyllys 		v.bv_len = extns->extensions[i].extnId.Length;
103999ebb4caSwyllys 
104099ebb4caSwyllys 		if (kmfber_printf(asn1, "{D", &v) == -1)  {
104199ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
104299ebb4caSwyllys 			goto cleanup;
104399ebb4caSwyllys 		}
104499ebb4caSwyllys 
104599ebb4caSwyllys 		if (extns->extensions[i].critical) {
104699ebb4caSwyllys 			if (kmfber_printf(asn1, "b",
10472cbed729Swyllys 			    extns->extensions[i].critical) == -1) {
104899ebb4caSwyllys 				ret = KMF_ERR_ENCODING;
104999ebb4caSwyllys 				goto cleanup;
105099ebb4caSwyllys 			}
105199ebb4caSwyllys 		}
105299ebb4caSwyllys 
105399ebb4caSwyllys 		if (kmfber_printf(asn1, "o}",
10542cbed729Swyllys 		    extns->extensions[i].BERvalue.Data,
10552cbed729Swyllys 		    extns->extensions[i].BERvalue.Length) == -1) {
105699ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
105799ebb4caSwyllys 			goto cleanup;
105899ebb4caSwyllys 		}
105999ebb4caSwyllys 	}
106099ebb4caSwyllys cleanup:
106199ebb4caSwyllys 	return (ret);
106299ebb4caSwyllys }
106399ebb4caSwyllys 
106499ebb4caSwyllys static KMF_RETURN
encode_extensions(BerElement * asn1,KMF_X509_EXTENSIONS * extns)106599ebb4caSwyllys encode_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
106699ebb4caSwyllys {
106799ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
106899ebb4caSwyllys 	BerElement *extn = NULL;
106999ebb4caSwyllys 	BerValue *extnvalue = NULL;
107099ebb4caSwyllys 
107199ebb4caSwyllys 	extn = kmfder_alloc();
107299ebb4caSwyllys 	if (extn == NULL)
107399ebb4caSwyllys 		return (KMF_ERR_MEMORY);
107499ebb4caSwyllys 
107599ebb4caSwyllys 	if (kmfber_printf(extn, "{") == -1) {
107699ebb4caSwyllys 		ret = KMF_ERR_ENCODING;
107799ebb4caSwyllys 		goto cleanup;
107899ebb4caSwyllys 	}
107999ebb4caSwyllys 
108099ebb4caSwyllys 	ret = encode_extension_list(extn, extns);
108199ebb4caSwyllys 
108299ebb4caSwyllys 	if (kmfber_printf(extn, "}") == -1) {
108399ebb4caSwyllys 		ret = KMF_ERR_ENCODING;
108499ebb4caSwyllys 		goto cleanup;
108599ebb4caSwyllys 	}
108699ebb4caSwyllys 
108799ebb4caSwyllys 	if (kmfber_flatten(extn, &extnvalue) == -1) {
108899ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
108999ebb4caSwyllys 		goto cleanup;
109099ebb4caSwyllys 	}
109199ebb4caSwyllys 
109299ebb4caSwyllys 	if (kmfber_printf(asn1, "Tl", 0xA3, extnvalue->bv_len) == -1) {
109399ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
109499ebb4caSwyllys 		goto cleanup;
109599ebb4caSwyllys 	}
109699ebb4caSwyllys 
109799ebb4caSwyllys 	if (kmfber_write(asn1, extnvalue->bv_val, extnvalue->bv_len, 0) == -1) {
109899ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
109999ebb4caSwyllys 		goto cleanup;
110099ebb4caSwyllys 	}
110199ebb4caSwyllys 
110299ebb4caSwyllys cleanup:
110399ebb4caSwyllys 	kmfber_free(extn, 1);
110499ebb4caSwyllys 	if (extnvalue != NULL)
110599ebb4caSwyllys 		kmfber_bvfree(extnvalue);
110699ebb4caSwyllys 
110799ebb4caSwyllys 	return (ret);
110899ebb4caSwyllys }
110999ebb4caSwyllys 
111099ebb4caSwyllys static KMF_RETURN
get_one_extension(BerElement * asn1,KMF_X509_EXTENSION ** retex,char * end)111199ebb4caSwyllys get_one_extension(BerElement *asn1, KMF_X509_EXTENSION **retex, char *end)
111299ebb4caSwyllys {
111399ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
111499ebb4caSwyllys 	ber_len_t size;
111599ebb4caSwyllys 	int  critical, tag;
111699ebb4caSwyllys 	KMF_X509_EXTENSION *ex = NULL;
111799ebb4caSwyllys 	BerValue extOID;
111899ebb4caSwyllys 	BerValue extValue;
111999ebb4caSwyllys 	BerElement *extnber = NULL;
112099ebb4caSwyllys 
112199ebb4caSwyllys 	if (kmfber_scanf(asn1, "T", &tag) == -1) {
112299ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
112399ebb4caSwyllys 		goto cleanup;
112499ebb4caSwyllys 	}
112599ebb4caSwyllys 
112699ebb4caSwyllys 	tag = kmfber_next_element(asn1, &size, end);
112799ebb4caSwyllys 	if (tag != BER_OBJECT_IDENTIFIER) {
112899ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
112999ebb4caSwyllys 		goto cleanup;
113099ebb4caSwyllys 	}
113199ebb4caSwyllys 	if (kmfber_scanf(asn1, "D", &extOID) == -1) {
113299ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
113399ebb4caSwyllys 		goto cleanup;
113499ebb4caSwyllys 	}
113599ebb4caSwyllys 
113699ebb4caSwyllys 	tag = kmfber_next_element(asn1, &size, end);
113799ebb4caSwyllys 	if (tag != BER_BOOLEAN) {
113899ebb4caSwyllys 		critical = 0;
113999ebb4caSwyllys 		if (tag != BER_OCTET_STRING)
114099ebb4caSwyllys 			goto cleanup;
114199ebb4caSwyllys 	} else {
114299ebb4caSwyllys 		if (kmfber_scanf(asn1, "b", &critical) == -1)
114399ebb4caSwyllys 			goto cleanup;
114499ebb4caSwyllys 	}
114599ebb4caSwyllys 
114699ebb4caSwyllys 	tag = kmfber_next_element(asn1, &size, end);
114799ebb4caSwyllys 	if (tag != BER_OCTET_STRING)  {
114899ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
114999ebb4caSwyllys 		goto cleanup;
115099ebb4caSwyllys 	}
115199ebb4caSwyllys 	if (kmfber_scanf(asn1, "o", &extValue) == -1)  {
115299ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
115399ebb4caSwyllys 		goto cleanup;
115499ebb4caSwyllys 	}
115599ebb4caSwyllys 
115699ebb4caSwyllys 	/* allocate a new Extension record */
115799ebb4caSwyllys 	ex = malloc(sizeof (KMF_X509_EXTENSION));
115899ebb4caSwyllys 	if (ex == NULL) {
115999ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
116099ebb4caSwyllys 		goto cleanup;
116199ebb4caSwyllys 	}
116299ebb4caSwyllys 	(void) memset(ex, 0, sizeof (ex));
116399ebb4caSwyllys 
116499ebb4caSwyllys 	ex->extnId.Data = (uchar_t *)extOID.bv_val;
116599ebb4caSwyllys 	ex->extnId.Length = extOID.bv_len;
116699ebb4caSwyllys 	ex->critical = critical;
116799ebb4caSwyllys 	ex->format = KMF_X509_DATAFORMAT_ENCODED;
116899ebb4caSwyllys 	ex->BERvalue.Data = (uchar_t *)extValue.bv_val;
116999ebb4caSwyllys 	ex->BERvalue.Length = extValue.bv_len;
117099ebb4caSwyllys 
117199ebb4caSwyllys 	/* Tag and value is a little tricky */
117299ebb4caSwyllys 	ex->value.tagAndValue = malloc(sizeof (KMF_X509EXT_TAGandVALUE));
117399ebb4caSwyllys 	if (ex->value.tagAndValue == NULL) {
117499ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
117599ebb4caSwyllys 		goto cleanup;
117699ebb4caSwyllys 	}
117799ebb4caSwyllys 	(void) memset(ex->value.tagAndValue, 0,
11782cbed729Swyllys 	    sizeof (KMF_X509EXT_TAGandVALUE));
117999ebb4caSwyllys 
118099ebb4caSwyllys 	/* Parse the Extension value field */
118199ebb4caSwyllys 	extnber = kmfder_init(&extValue);
118299ebb4caSwyllys 	if (extnber == NULL) {
118399ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
118499ebb4caSwyllys 		goto cleanup;
118599ebb4caSwyllys 	}
118699ebb4caSwyllys 
118799ebb4caSwyllys 	/* Get the tag and length of the extension field */
118899ebb4caSwyllys 	if (kmfber_scanf(extnber, "tl", &tag, &size) == -1) {
118999ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
119099ebb4caSwyllys 		goto cleanup;
119199ebb4caSwyllys 	}
119299ebb4caSwyllys 
119399ebb4caSwyllys 	if (kmfber_scanf(extnber, "T", &tag) == -1) {
119499ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
119599ebb4caSwyllys 		goto cleanup;
119699ebb4caSwyllys 	}
119799ebb4caSwyllys 
119899ebb4caSwyllys 	ex->value.tagAndValue->value.Data = malloc(size);
119999ebb4caSwyllys 	ex->value.tagAndValue->value.Length = size;
120099ebb4caSwyllys 	size = kmfber_read(extnber,
12012cbed729Swyllys 	    (char *)ex->value.tagAndValue->value.Data, size);
120299ebb4caSwyllys 	if (size != ex->value.tagAndValue->value.Length) {
120399ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
120499ebb4caSwyllys 		goto cleanup;
120599ebb4caSwyllys 	}
120699ebb4caSwyllys 	kmfber_free(extnber, 1);
120799ebb4caSwyllys 	ex->value.tagAndValue->type = tag;
120899ebb4caSwyllys 
120999ebb4caSwyllys 	*retex = ex;
121099ebb4caSwyllys cleanup:
121199ebb4caSwyllys 	if (ret != KMF_OK) {
121299ebb4caSwyllys 		if (ex != NULL)
121399ebb4caSwyllys 			free_one_extension(ex);
121499ebb4caSwyllys 	}
121599ebb4caSwyllys 
121699ebb4caSwyllys 	return (ret);
121799ebb4caSwyllys }
121899ebb4caSwyllys 
121999ebb4caSwyllys static KMF_RETURN
get_extensions(BerElement * asn1,KMF_X509_EXTENSIONS * extns)122099ebb4caSwyllys get_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
122199ebb4caSwyllys {
122299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
122399ebb4caSwyllys 	ber_len_t size;
122499ebb4caSwyllys 	char *end = NULL;
122599ebb4caSwyllys 	KMF_X509_EXTENSION *ex = NULL;
122699ebb4caSwyllys 
122799ebb4caSwyllys 	/*
122899ebb4caSwyllys 	 * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
122999ebb4caSwyllys 	 *
123099ebb4caSwyllys 	 * Extension  ::=  SEQUENCE  {
123199ebb4caSwyllys 	 *	extnID		OBJECT IDENTIFIER,
123299ebb4caSwyllys 	 *	critical	BOOLEAN DEFAULT FALSE,
123399ebb4caSwyllys 	 *	extnValue	OCTET STRING  }
123499ebb4caSwyllys 	 *
123599ebb4caSwyllys 	 * { {{D}Bo}, ... }
123699ebb4caSwyllys 	 */
123799ebb4caSwyllys 	if (kmfber_first_element(asn1, &size, &end) !=
12382cbed729Swyllys 	    BER_CONSTRUCTED_SEQUENCE)
123999ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
124099ebb4caSwyllys 
124199ebb4caSwyllys 	while (kmfber_next_element(asn1, &size, end) ==
12422cbed729Swyllys 	    BER_CONSTRUCTED_SEQUENCE) {
124399ebb4caSwyllys 		ret = get_one_extension(asn1, &ex, end);
124499ebb4caSwyllys 		if (ret != KMF_OK)
124599ebb4caSwyllys 			goto cleanup;
124699ebb4caSwyllys 
124799ebb4caSwyllys 		extns->numberOfExtensions++;
124899ebb4caSwyllys 		extns->extensions = realloc(extns->extensions,
12492cbed729Swyllys 		    extns->numberOfExtensions *
12502cbed729Swyllys 		    sizeof (KMF_X509_EXTENSION));
125199ebb4caSwyllys 		if (extns->extensions == NULL) {
125299ebb4caSwyllys 			ret = KMF_ERR_MEMORY;
125399ebb4caSwyllys 			break;
125499ebb4caSwyllys 		}
125599ebb4caSwyllys 
125699ebb4caSwyllys 		extns->extensions[extns->numberOfExtensions-1] = *ex;
125799ebb4caSwyllys 		free(ex);
125899ebb4caSwyllys 	}
125999ebb4caSwyllys 
126099ebb4caSwyllys cleanup:
126199ebb4caSwyllys 	if (ret != KMF_OK)
126299ebb4caSwyllys 		free_extensions(extns);
126399ebb4caSwyllys 
126499ebb4caSwyllys 	return (ret);
126599ebb4caSwyllys }
126699ebb4caSwyllys 
126799ebb4caSwyllys KMF_RETURN
decode_tbscert_data(BerElement * asn1,KMF_X509_TBS_CERT ** signed_cert_ptr_ptr)126899ebb4caSwyllys decode_tbscert_data(BerElement *asn1,
126999ebb4caSwyllys 	KMF_X509_TBS_CERT **signed_cert_ptr_ptr)
127099ebb4caSwyllys {
127199ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
127299ebb4caSwyllys 	KMF_X509_TBS_CERT	*tbscert = NULL;
127399ebb4caSwyllys 	int tag, version;
127499ebb4caSwyllys 	struct berval *bvserno = NULL;
127599ebb4caSwyllys 	KMF_BIGINT serno;
127699ebb4caSwyllys 
127799ebb4caSwyllys 	if (kmfber_scanf(asn1, "{t", &tag) == -1) {
127899ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
127999ebb4caSwyllys 		goto cleanup;
128099ebb4caSwyllys 	}
128199ebb4caSwyllys 
128299ebb4caSwyllys 	/* Version number is optional */
128399ebb4caSwyllys 	if (tag == 0xA0) {
128499ebb4caSwyllys 		if (kmfber_scanf(asn1, "Ti", &tag, &version) == -1) {
128599ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
128699ebb4caSwyllys 			goto cleanup;
128799ebb4caSwyllys 		}
128899ebb4caSwyllys 	} else {
128999ebb4caSwyllys 		version = 0; /* DEFAULT v1 (0) */
129099ebb4caSwyllys 	}
129199ebb4caSwyllys 
129299ebb4caSwyllys 	/* Now get the serial number, it is not optional */
129399ebb4caSwyllys 	if (kmfber_scanf(asn1, "I", &bvserno) == -1) {
129499ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
129599ebb4caSwyllys 		goto cleanup;
129699ebb4caSwyllys 	} else {
129799ebb4caSwyllys 		serno.val = (uchar_t *)bvserno->bv_val;
129899ebb4caSwyllys 		serno.len = bvserno->bv_len;
129999ebb4caSwyllys 	}
130099ebb4caSwyllys 
130199ebb4caSwyllys 	tbscert = malloc(sizeof (KMF_X509_TBS_CERT));
130299ebb4caSwyllys 	if (!tbscert) {
130399ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
130499ebb4caSwyllys 		goto cleanup;
130599ebb4caSwyllys 	}
130699ebb4caSwyllys 
130799ebb4caSwyllys 	(void) memset(tbscert, 0, sizeof (KMF_X509_TBS_CERT));
130899ebb4caSwyllys 
130999ebb4caSwyllys 	if ((ret = set_der_integer(&tbscert->version, version)) != KMF_OK)
131099ebb4caSwyllys 		goto cleanup;
131199ebb4caSwyllys 
131299ebb4caSwyllys 	if ((ret = set_bigint(&tbscert->serialNumber, &serno)) != KMF_OK)
131399ebb4caSwyllys 		goto cleanup;
131499ebb4caSwyllys 
131599ebb4caSwyllys 	if ((ret = get_algoid(asn1, &tbscert->signature)) != KMF_OK)
131699ebb4caSwyllys 		goto cleanup;
131799ebb4caSwyllys 
131899ebb4caSwyllys 	if ((ret = get_rdn(asn1, &tbscert->issuer)) != KMF_OK)
131999ebb4caSwyllys 		goto cleanup;
132099ebb4caSwyllys 
132199ebb4caSwyllys 	if ((ret = get_validity(asn1, &tbscert->validity)) != KMF_OK)
132299ebb4caSwyllys 		goto cleanup;
132399ebb4caSwyllys 
132499ebb4caSwyllys 	if ((ret = get_rdn(asn1, &tbscert->subject)) != KMF_OK)
132599ebb4caSwyllys 		goto cleanup;
132699ebb4caSwyllys 
132799ebb4caSwyllys 	if ((ret = get_spki(asn1, &tbscert->subjectPublicKeyInfo)) != KMF_OK)
132899ebb4caSwyllys 		goto cleanup;
132999ebb4caSwyllys 
133099ebb4caSwyllys 	/* Check for the optional fields */
133199ebb4caSwyllys 	tbscert->extensions.numberOfExtensions = 0;
133299ebb4caSwyllys 	tbscert->extensions.extensions = NULL;
133399ebb4caSwyllys 
133499ebb4caSwyllys 	while ((kmfber_scanf(asn1, "t", &tag)) != -1 &&
13352cbed729Swyllys 	    (tag == 0xA1 || tag == 0xA2 || tag == 0xA3)) {
133699ebb4caSwyllys 		char *optfield;
133799ebb4caSwyllys 		ber_len_t len;
133899ebb4caSwyllys 
133999ebb4caSwyllys 		/* consume the tag and length */
134099ebb4caSwyllys 		(void) kmfber_scanf(asn1, "T", &tag);
134199ebb4caSwyllys 		switch (tag) {
134299ebb4caSwyllys 			case 0xA1:
134399ebb4caSwyllys 				if (kmfber_scanf(asn1, "B", &optfield, &len) !=
13442cbed729Swyllys 				    BER_BIT_STRING) {
134599ebb4caSwyllys 					ret = KMF_ERR_BAD_CERT_FORMAT;
134699ebb4caSwyllys 					goto cleanup;
134799ebb4caSwyllys 				}
134899ebb4caSwyllys 				tbscert->issuerUniqueIdentifier.Data =
13492cbed729Swyllys 				    (uchar_t *)optfield;
135099ebb4caSwyllys 				tbscert->issuerUniqueIdentifier.Length =
13512cbed729Swyllys 				    len / 8;
135299ebb4caSwyllys 				break;
135399ebb4caSwyllys 			case 0xA2:
135499ebb4caSwyllys 				if (kmfber_scanf(asn1, "B", &optfield, &len) !=
13552cbed729Swyllys 				    BER_BIT_STRING) {
135699ebb4caSwyllys 					ret = KMF_ERR_BAD_CERT_FORMAT;
135799ebb4caSwyllys 					goto cleanup;
135899ebb4caSwyllys 				}
135999ebb4caSwyllys 				tbscert->subjectUniqueIdentifier.Data =
13602cbed729Swyllys 				    (uchar_t *)optfield;
136199ebb4caSwyllys 				tbscert->subjectUniqueIdentifier.Length =
13622cbed729Swyllys 				    len / 8;
136399ebb4caSwyllys 				break;
136499ebb4caSwyllys 			case 0xA3:
136599ebb4caSwyllys 			ret = get_extensions(asn1, &tbscert->extensions);
136699ebb4caSwyllys 			break;
136799ebb4caSwyllys 		}
136899ebb4caSwyllys 	}
136999ebb4caSwyllys 
137099ebb4caSwyllys 	*signed_cert_ptr_ptr = tbscert;
137199ebb4caSwyllys 
137299ebb4caSwyllys cleanup:
137399ebb4caSwyllys 	if (bvserno != NULL) {
137499ebb4caSwyllys 		free(bvserno->bv_val);
137599ebb4caSwyllys 		free(bvserno);
137699ebb4caSwyllys 	}
137799ebb4caSwyllys 	if (ret != KMF_OK) {
137899ebb4caSwyllys 		if (tbscert) {
137999ebb4caSwyllys 			free_tbscert(tbscert);
138099ebb4caSwyllys 			free(tbscert);
138199ebb4caSwyllys 		}
138299ebb4caSwyllys 		*signed_cert_ptr_ptr = NULL;
138399ebb4caSwyllys 	}
138499ebb4caSwyllys 	return (ret);
138599ebb4caSwyllys }
138699ebb4caSwyllys 
138799ebb4caSwyllys KMF_RETURN
DerDecodeTbsCertificate(const KMF_DATA * Value,KMF_X509_TBS_CERT ** tbscert)138899ebb4caSwyllys DerDecodeTbsCertificate(const KMF_DATA *Value,
138999ebb4caSwyllys 	KMF_X509_TBS_CERT **tbscert)
139099ebb4caSwyllys {
139199ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
139299ebb4caSwyllys 	BerElement *asn1 = NULL;
139399ebb4caSwyllys 	BerValue 	rawcert;
139499ebb4caSwyllys 	KMF_X509_TBS_CERT *newcert = NULL;
139599ebb4caSwyllys 
139699ebb4caSwyllys 	if (!tbscert || !Value || !Value->Data || !Value->Length)
139799ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
139899ebb4caSwyllys 
139999ebb4caSwyllys 	rawcert.bv_val = (char *)Value->Data;
140099ebb4caSwyllys 	rawcert.bv_len = Value->Length;
140199ebb4caSwyllys 
140299ebb4caSwyllys 	if ((asn1 = kmfder_init(&rawcert)) == NULL)
140399ebb4caSwyllys 		return (KMF_ERR_MEMORY);
140499ebb4caSwyllys 
140599ebb4caSwyllys 	ret = decode_tbscert_data(asn1, &newcert);
140699ebb4caSwyllys 	if (ret != KMF_OK)
140799ebb4caSwyllys 		goto cleanup;
140899ebb4caSwyllys 
140999ebb4caSwyllys 	*tbscert = newcert;
141099ebb4caSwyllys 
141199ebb4caSwyllys cleanup:
141299ebb4caSwyllys 	if (ret != KMF_OK) {
141399ebb4caSwyllys 		if (newcert)
141499ebb4caSwyllys 			free_tbscert(newcert);
141599ebb4caSwyllys 		*tbscert = NULL;
141699ebb4caSwyllys 	}
141799ebb4caSwyllys 	kmfber_free(asn1, 1);
141899ebb4caSwyllys 
141999ebb4caSwyllys 	return (ret);
142099ebb4caSwyllys }
142199ebb4caSwyllys 
142299ebb4caSwyllys /*
142399ebb4caSwyllys  * Name: DerDecodeSignedCertificate
142499ebb4caSwyllys  *
142599ebb4caSwyllys  * Description:
142699ebb4caSwyllys  * DER decodes the encoded X509 certificate
142799ebb4caSwyllys  *
142899ebb4caSwyllys  * Parameters:
142999ebb4caSwyllys  * Value (input): DER encoded object that shd be decoded
143099ebb4caSwyllys  *
143199ebb4caSwyllys  * signed_cert_ptr_ptr (output) : Decoded KMF_X509_CERTIFICATE object
143299ebb4caSwyllys  */
143399ebb4caSwyllys KMF_RETURN
DerDecodeSignedCertificate(const KMF_DATA * Value,KMF_X509_CERTIFICATE ** signed_cert_ptr_ptr)143499ebb4caSwyllys DerDecodeSignedCertificate(const KMF_DATA *Value,
143599ebb4caSwyllys 	KMF_X509_CERTIFICATE **signed_cert_ptr_ptr)
143699ebb4caSwyllys {
143799ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
143899ebb4caSwyllys 	BerElement *asn1 = NULL;
143999ebb4caSwyllys 	BerValue 	rawcert;
144099ebb4caSwyllys 	ber_tag_t	tag;
144199ebb4caSwyllys 	ber_len_t	size;
144299ebb4caSwyllys 	char		*end = NULL;
144399ebb4caSwyllys 	char		*signature;
144499ebb4caSwyllys 	KMF_X509_TBS_CERT	*tbscert = NULL;
144599ebb4caSwyllys 	KMF_X509_CERTIFICATE *certptr = NULL;
144699ebb4caSwyllys 
144799ebb4caSwyllys 	if (!signed_cert_ptr_ptr || !Value || !Value->Data || !Value->Length)
144899ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
144999ebb4caSwyllys 
145099ebb4caSwyllys 	rawcert.bv_val = (char *)Value->Data;
145199ebb4caSwyllys 	rawcert.bv_len = Value->Length;
145299ebb4caSwyllys 
145399ebb4caSwyllys 	if ((asn1 = kmfder_init(&rawcert)) == NULL)
145499ebb4caSwyllys 		return (KMF_ERR_MEMORY);
145599ebb4caSwyllys 
145699ebb4caSwyllys 	if (kmfber_first_element(asn1, &size, &end) !=
14572cbed729Swyllys 	    BER_CONSTRUCTED_SEQUENCE) {
145899ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
145999ebb4caSwyllys 		goto cleanup;
146099ebb4caSwyllys 	}
146199ebb4caSwyllys 
146299ebb4caSwyllys 	certptr = malloc(sizeof (KMF_X509_CERTIFICATE));
146399ebb4caSwyllys 	if (certptr == NULL) {
146499ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
146599ebb4caSwyllys 		goto cleanup;
146699ebb4caSwyllys 	}
146799ebb4caSwyllys 	(void) memset(certptr, 0, sizeof (KMF_X509_CERTIFICATE));
146899ebb4caSwyllys 
146999ebb4caSwyllys 	ret = decode_tbscert_data(asn1, &tbscert);
147099ebb4caSwyllys 	if (ret != KMF_OK)
147199ebb4caSwyllys 		goto cleanup;
147299ebb4caSwyllys 
147399ebb4caSwyllys 	certptr->certificate = *tbscert;
147499ebb4caSwyllys 	free(tbscert);
147599ebb4caSwyllys 	tbscert = NULL;
147699ebb4caSwyllys 
147799ebb4caSwyllys 	/*
147899ebb4caSwyllys 	 * The signature data my not be present yet.
147999ebb4caSwyllys 	 */
148099ebb4caSwyllys 	if ((ret = get_algoid(asn1,
14812cbed729Swyllys 	    &certptr->signature.algorithmIdentifier)) == KMF_OK) {
148299ebb4caSwyllys 
148399ebb4caSwyllys 		/* Check to see if the cert has a signature yet */
148499ebb4caSwyllys 		if (kmfber_next_element(asn1, &size, end) == BER_BIT_STRING) {
148599ebb4caSwyllys 			/* Finally, get the encrypted signature BITSTRING */
148699ebb4caSwyllys 			if (kmfber_scanf(asn1, "tl", &tag, &size) == -1) {
148799ebb4caSwyllys 				ret = KMF_ERR_BAD_CERT_FORMAT;
148899ebb4caSwyllys 				goto cleanup;
148999ebb4caSwyllys 			}
149099ebb4caSwyllys 			if (tag != BER_BIT_STRING) {
149199ebb4caSwyllys 				ret = KMF_ERR_BAD_CERT_FORMAT;
149299ebb4caSwyllys 				goto cleanup;
149399ebb4caSwyllys 			}
149499ebb4caSwyllys 			if (kmfber_scanf(asn1, "B}", &signature, &size) == -1) {
149599ebb4caSwyllys 				ret = KMF_ERR_BAD_CERT_FORMAT;
149699ebb4caSwyllys 				goto cleanup;
149799ebb4caSwyllys 			}
149899ebb4caSwyllys 			certptr->signature.encrypted.Data =
14992cbed729Swyllys 			    (uchar_t *)signature;
150099ebb4caSwyllys 			certptr->signature.encrypted.Length = size / 8;
150199ebb4caSwyllys 		} else {
150299ebb4caSwyllys 			certptr->signature.encrypted.Data = NULL;
150399ebb4caSwyllys 			certptr->signature.encrypted.Length = 0;
150499ebb4caSwyllys 		}
150599ebb4caSwyllys 	} else {
150699ebb4caSwyllys 		(void) memset(&certptr->signature, 0,
15072cbed729Swyllys 		    sizeof (certptr->signature));
150899ebb4caSwyllys 		ret = KMF_OK;
150999ebb4caSwyllys 	}
151099ebb4caSwyllys 
151199ebb4caSwyllys 	*signed_cert_ptr_ptr = certptr;
151299ebb4caSwyllys cleanup:
151399ebb4caSwyllys 	if (ret != KMF_OK) {
151499ebb4caSwyllys 		if (certptr) {
151599ebb4caSwyllys 			free_decoded_cert(certptr);
151699ebb4caSwyllys 			free(certptr);
151799ebb4caSwyllys 		}
151899ebb4caSwyllys 
151999ebb4caSwyllys 		*signed_cert_ptr_ptr = NULL;
152099ebb4caSwyllys 	}
152199ebb4caSwyllys 	if (asn1)
152299ebb4caSwyllys 		kmfber_free(asn1, 1);
152399ebb4caSwyllys 
152499ebb4caSwyllys 	return (ret);
152599ebb4caSwyllys 
152699ebb4caSwyllys }
152799ebb4caSwyllys 
152899ebb4caSwyllys KMF_RETURN
DerDecodeExtension(KMF_DATA * Data,KMF_X509_EXTENSION ** extn)152999ebb4caSwyllys DerDecodeExtension(KMF_DATA *Data, KMF_X509_EXTENSION **extn)
153099ebb4caSwyllys {
153199ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
153299ebb4caSwyllys 	BerElement *asn1 = NULL;
153399ebb4caSwyllys 	BerValue bv;
153499ebb4caSwyllys 
153599ebb4caSwyllys 	bv.bv_val = (char *)Data->Data;
153699ebb4caSwyllys 	bv.bv_len = Data->Length;
153799ebb4caSwyllys 
153899ebb4caSwyllys 	asn1 = kmfder_init(&bv);
153999ebb4caSwyllys 	if (asn1 == NULL)
154099ebb4caSwyllys 		return (KMF_ERR_MEMORY);
154199ebb4caSwyllys 
154299ebb4caSwyllys 	ret = get_one_extension(asn1, extn, NULL);
154399ebb4caSwyllys 
154499ebb4caSwyllys cleanup:
154599ebb4caSwyllys 	if (ret != KMF_OK) {
154699ebb4caSwyllys 		if (*extn != NULL) {
154799ebb4caSwyllys 			free(*extn);
154899ebb4caSwyllys 		}
154999ebb4caSwyllys 		*extn = NULL;
155099ebb4caSwyllys 	}
155199ebb4caSwyllys 
155299ebb4caSwyllys 	kmfber_free(asn1, 1);
155399ebb4caSwyllys 	return (ret);
155499ebb4caSwyllys }
155599ebb4caSwyllys 
155699ebb4caSwyllys KMF_RETURN
DerDecodeName(KMF_DATA * encodedname,KMF_X509_NAME * name)155799ebb4caSwyllys DerDecodeName(KMF_DATA *encodedname, KMF_X509_NAME *name)
155899ebb4caSwyllys {
155999ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
156099ebb4caSwyllys 	BerElement *asn1 = NULL;
156199ebb4caSwyllys 	BerValue  bv;
156299ebb4caSwyllys 
156399ebb4caSwyllys 	bv.bv_val = (char *)encodedname->Data;
156499ebb4caSwyllys 	bv.bv_len = encodedname->Length;
156599ebb4caSwyllys 
156699ebb4caSwyllys 	asn1 = kmfder_init(&bv);
156799ebb4caSwyllys 	if (asn1 == NULL)
156899ebb4caSwyllys 		return (KMF_ERR_MEMORY);
156999ebb4caSwyllys 
157099ebb4caSwyllys 	(void) memset((void *)name, 0, sizeof (KMF_X509_NAME));
157199ebb4caSwyllys 
157299ebb4caSwyllys 	if ((ret = get_rdn(asn1, name)) != KMF_OK)
157399ebb4caSwyllys 		goto cleanup;
157499ebb4caSwyllys 
157599ebb4caSwyllys cleanup:
157699ebb4caSwyllys 	if (asn1)
157799ebb4caSwyllys 		kmfber_free(asn1, 1);
157899ebb4caSwyllys 	return (ret);
157999ebb4caSwyllys }
158099ebb4caSwyllys 
158199ebb4caSwyllys KMF_RETURN
DerEncodeName(KMF_X509_NAME * name,KMF_DATA * encodedname)158299ebb4caSwyllys DerEncodeName(KMF_X509_NAME *name, KMF_DATA *encodedname)
158399ebb4caSwyllys {
158499ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
158599ebb4caSwyllys 	BerElement *asn1 = NULL;
158699ebb4caSwyllys 	BerValue  *bv = NULL;
158799ebb4caSwyllys 
158899ebb4caSwyllys 	asn1 = kmfder_alloc();
158999ebb4caSwyllys 	if (asn1 == NULL)
159099ebb4caSwyllys 		return (KMF_ERR_MEMORY);
159199ebb4caSwyllys 
159299ebb4caSwyllys 	if ((ret = encode_rdn(asn1, name)) != KMF_OK)
159399ebb4caSwyllys 		goto cleanup;
159499ebb4caSwyllys 
159599ebb4caSwyllys 	if (kmfber_flatten(asn1, &bv) == -1) {
159699ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
159799ebb4caSwyllys 		goto cleanup;
159899ebb4caSwyllys 	}
159999ebb4caSwyllys 
160099ebb4caSwyllys 	encodedname->Data = (uchar_t *)bv->bv_val;
160199ebb4caSwyllys 	encodedname->Length = bv->bv_len;
160299ebb4caSwyllys 
160399ebb4caSwyllys cleanup:
160499ebb4caSwyllys 	if (bv)
160599ebb4caSwyllys 		free(bv);
160699ebb4caSwyllys 
160799ebb4caSwyllys 	if (asn1)
160899ebb4caSwyllys 		kmfber_free(asn1, 1);
160999ebb4caSwyllys 
161099ebb4caSwyllys 	return (ret);
161199ebb4caSwyllys }
161299ebb4caSwyllys 
161399ebb4caSwyllys static KMF_RETURN
encode_tbs_cert(BerElement * asn1,KMF_X509_TBS_CERT * tbscert)161499ebb4caSwyllys encode_tbs_cert(BerElement *asn1, KMF_X509_TBS_CERT *tbscert)
161599ebb4caSwyllys {
161699ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
161799ebb4caSwyllys 	uint32_t version;
161899ebb4caSwyllys 
161999ebb4caSwyllys 	/* version should be 4 bytes or less */
162099ebb4caSwyllys 	if (tbscert->version.Length > sizeof (int))
162199ebb4caSwyllys 		return (KMF_ERR_BAD_CERT_FORMAT);
162299ebb4caSwyllys 
162399ebb4caSwyllys 	(void) memcpy(&version, tbscert->version.Data,
16242cbed729Swyllys 	    tbscert->version.Length);
162599ebb4caSwyllys 
162699ebb4caSwyllys 	/* Start the sequence and add the version */
162799ebb4caSwyllys 	if (kmfber_printf(asn1, "{Tli", 0xA0, 3, version) == -1) {
162899ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
162999ebb4caSwyllys 		goto cleanup;
163099ebb4caSwyllys 	}
163199ebb4caSwyllys 	/* Write the serial number */
163299ebb4caSwyllys 	if (kmfber_printf(asn1, "I",
16332cbed729Swyllys 	    (char *)tbscert->serialNumber.val,
16342cbed729Swyllys 	    (size_t)tbscert->serialNumber.len) == -1) {
163599ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
163699ebb4caSwyllys 		goto cleanup;
163799ebb4caSwyllys 	}
163899ebb4caSwyllys 
1639*e65e5c2dSWyllys Ingersoll 	/* Don't encode alg parameters in signature algid area */
1640*e65e5c2dSWyllys Ingersoll 	if ((ret = encode_algoid(asn1, &tbscert->signature, FALSE)) != KMF_OK)
164199ebb4caSwyllys 		goto cleanup;
164299ebb4caSwyllys 
164399ebb4caSwyllys 	/* Encode the Issuer RDN */
164499ebb4caSwyllys 	if ((ret = encode_rdn(asn1, &tbscert->issuer)) != KMF_OK)
164599ebb4caSwyllys 		goto cleanup;
164699ebb4caSwyllys 
164799ebb4caSwyllys 	/* Encode the Validity fields */
164899ebb4caSwyllys 	if ((ret = encode_validity(asn1, &tbscert->validity)) != KMF_OK)
164999ebb4caSwyllys 		goto cleanup;
165099ebb4caSwyllys 
165199ebb4caSwyllys 	/* Encode the Subject RDN */
165299ebb4caSwyllys 	if ((ret = encode_rdn(asn1, &tbscert->subject)) != KMF_OK)
165399ebb4caSwyllys 		goto cleanup;
165499ebb4caSwyllys 
165599ebb4caSwyllys 	/* Encode the Subject Public Key Info */
165699ebb4caSwyllys 	if ((ret = encode_spki(asn1, &tbscert->subjectPublicKeyInfo)) != KMF_OK)
165799ebb4caSwyllys 		goto cleanup;
165899ebb4caSwyllys 
165999ebb4caSwyllys 	/* Optional field:  issuer Unique ID */
166099ebb4caSwyllys 	if (tbscert->issuerUniqueIdentifier.Length > 0) {
166199ebb4caSwyllys 		if ((ret = encode_uniqueid(asn1, 0xA1,
16622cbed729Swyllys 		    &tbscert->issuerUniqueIdentifier)) != KMF_OK)
166399ebb4caSwyllys 			goto cleanup;
166499ebb4caSwyllys 	}
166599ebb4caSwyllys 
166699ebb4caSwyllys 	/* Optional field:  Subject Unique ID */
166799ebb4caSwyllys 	if (tbscert->subjectUniqueIdentifier.Length > 0) {
166899ebb4caSwyllys 		if ((ret = encode_uniqueid(asn1, 0xA2,
16692cbed729Swyllys 		    &tbscert->subjectUniqueIdentifier)) != KMF_OK)
167099ebb4caSwyllys 			goto cleanup;
167199ebb4caSwyllys 	}
167299ebb4caSwyllys 
167399ebb4caSwyllys 	/* Optional field: Certificate Extensions */
167499ebb4caSwyllys 	if (tbscert->extensions.numberOfExtensions > 0) {
167599ebb4caSwyllys 		if ((ret = encode_extensions(asn1,
16762cbed729Swyllys 		    &tbscert->extensions)) != KMF_OK)
167799ebb4caSwyllys 			goto cleanup;
167899ebb4caSwyllys 	}
167999ebb4caSwyllys 
168099ebb4caSwyllys 	/* Close out the TBSCert sequence */
168199ebb4caSwyllys 	if (kmfber_printf(asn1, "}") == -1) {
168299ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
168399ebb4caSwyllys 		goto cleanup;
168499ebb4caSwyllys 	}
168599ebb4caSwyllys 
168699ebb4caSwyllys cleanup:
168799ebb4caSwyllys 	/*
168899ebb4caSwyllys 	 * Memory cleanup is done in the caller or in the individual
168999ebb4caSwyllys 	 * encoding routines.
169099ebb4caSwyllys 	 */
169199ebb4caSwyllys 
169299ebb4caSwyllys 	return (ret);
169399ebb4caSwyllys }
169499ebb4caSwyllys 
169599ebb4caSwyllys KMF_RETURN
DerEncodeTbsCertificate(KMF_X509_TBS_CERT * tbs_cert_ptr,KMF_DATA * enc_tbs_cert_ptr)169699ebb4caSwyllys DerEncodeTbsCertificate(KMF_X509_TBS_CERT *tbs_cert_ptr,
169799ebb4caSwyllys 	KMF_DATA *enc_tbs_cert_ptr)
169899ebb4caSwyllys {
169999ebb4caSwyllys 	KMF_RETURN ret;
170099ebb4caSwyllys 	BerElement *asn1 = NULL;
170199ebb4caSwyllys 	BerValue  *tbsdata = NULL;
170299ebb4caSwyllys 
170399ebb4caSwyllys 	asn1 = kmfder_alloc();
170499ebb4caSwyllys 	if (asn1 == NULL)
170599ebb4caSwyllys 		return (KMF_ERR_MEMORY);
170699ebb4caSwyllys 
170799ebb4caSwyllys 	enc_tbs_cert_ptr->Data = NULL;
170899ebb4caSwyllys 	enc_tbs_cert_ptr->Length = 0;
170999ebb4caSwyllys 
171099ebb4caSwyllys 	ret = encode_tbs_cert(asn1, tbs_cert_ptr);
171199ebb4caSwyllys 	if (ret != KMF_OK)
171299ebb4caSwyllys 		goto cleanup;
171399ebb4caSwyllys 
171499ebb4caSwyllys 	if (kmfber_flatten(asn1, &tbsdata) == -1) {
171599ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
171699ebb4caSwyllys 		goto cleanup;
171799ebb4caSwyllys 	}
171899ebb4caSwyllys 
171999ebb4caSwyllys 	enc_tbs_cert_ptr->Data = (uchar_t *)tbsdata->bv_val;
172099ebb4caSwyllys 	enc_tbs_cert_ptr->Length = tbsdata->bv_len;
172199ebb4caSwyllys 
172299ebb4caSwyllys cleanup:
172399ebb4caSwyllys 	if (ret != KMF_OK)
172499ebb4caSwyllys 		free_data(enc_tbs_cert_ptr);
172599ebb4caSwyllys 
172699ebb4caSwyllys 	if (asn1 != NULL)
172799ebb4caSwyllys 		kmfber_free(asn1, 1);
172899ebb4caSwyllys 
172999ebb4caSwyllys 	if (tbsdata)
173099ebb4caSwyllys 		free(tbsdata);
173199ebb4caSwyllys 
173299ebb4caSwyllys 	return (ret);
173399ebb4caSwyllys }
173499ebb4caSwyllys 
173599ebb4caSwyllys KMF_RETURN
DerEncodeSignedCertificate(KMF_X509_CERTIFICATE * signed_cert_ptr,KMF_DATA * encodedcert)173699ebb4caSwyllys DerEncodeSignedCertificate(KMF_X509_CERTIFICATE *signed_cert_ptr,
173799ebb4caSwyllys 	KMF_DATA *encodedcert)
173899ebb4caSwyllys {
173999ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
174099ebb4caSwyllys 	KMF_X509_TBS_CERT *tbscert = NULL;
174199ebb4caSwyllys 	KMF_X509_SIGNATURE		*signature = NULL;
174299ebb4caSwyllys 	BerElement	*asn1 = NULL;
174399ebb4caSwyllys 	BerValue 	*tbsdata = NULL;
174499ebb4caSwyllys 
174599ebb4caSwyllys 	if (signed_cert_ptr == NULL || encodedcert == NULL)
174699ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
174799ebb4caSwyllys 
174899ebb4caSwyllys 	encodedcert->Data = NULL;
174999ebb4caSwyllys 	encodedcert->Length = 0;
175099ebb4caSwyllys 
175199ebb4caSwyllys 	tbscert = &signed_cert_ptr->certificate;
175299ebb4caSwyllys 	signature = &signed_cert_ptr->signature;
175399ebb4caSwyllys 
175499ebb4caSwyllys 	asn1 = kmfder_alloc();
175599ebb4caSwyllys 	if (asn1 == NULL)
175699ebb4caSwyllys 		return (KMF_ERR_MEMORY);
175799ebb4caSwyllys 
175899ebb4caSwyllys 	/* Start outer X509 Certificate SEQUENCE */
175999ebb4caSwyllys 	if (kmfber_printf(asn1, "{") == -1) {
176099ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
176199ebb4caSwyllys 		goto cleanup;
176299ebb4caSwyllys 	}
176399ebb4caSwyllys 
176499ebb4caSwyllys 	if ((ret = encode_tbs_cert(asn1, tbscert)) != KMF_OK) {
176599ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
176699ebb4caSwyllys 		goto cleanup;
176799ebb4caSwyllys 	}
176899ebb4caSwyllys 
1769*e65e5c2dSWyllys Ingersoll 	/* Add the Algorithm & Signature Sequence (no parameters) */
177099ebb4caSwyllys 	if ((ret = encode_algoid(asn1,
1771*e65e5c2dSWyllys Ingersoll 	    &signature->algorithmIdentifier, FALSE)) != KMF_OK)
177299ebb4caSwyllys 		goto cleanup;
177399ebb4caSwyllys 
177499ebb4caSwyllys 	if (signature->encrypted.Length > 0) {
177599ebb4caSwyllys 		if (kmfber_printf(asn1, "B", signature->encrypted.Data,
17762cbed729Swyllys 		    signature->encrypted.Length * 8) == -1) {
177799ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
177899ebb4caSwyllys 			goto cleanup;
177999ebb4caSwyllys 		}
178099ebb4caSwyllys 	}
178199ebb4caSwyllys 
178299ebb4caSwyllys 	if (kmfber_printf(asn1, "}") == -1) {
178399ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
178499ebb4caSwyllys 		goto cleanup;
178599ebb4caSwyllys 	}
178699ebb4caSwyllys 
178799ebb4caSwyllys 	if (kmfber_flatten(asn1, &tbsdata) == -1) {
178899ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
178999ebb4caSwyllys 		goto cleanup;
179099ebb4caSwyllys 	}
179199ebb4caSwyllys 
179299ebb4caSwyllys 	encodedcert->Data = (uchar_t *)tbsdata->bv_val;
179399ebb4caSwyllys 	encodedcert->Length = tbsdata->bv_len;
179499ebb4caSwyllys 
179599ebb4caSwyllys cleanup:
179699ebb4caSwyllys 	if (ret != KMF_OK)
179799ebb4caSwyllys 		free_data(encodedcert);
179899ebb4caSwyllys 
179999ebb4caSwyllys 	if (tbsdata)
180099ebb4caSwyllys 		free(tbsdata);
180199ebb4caSwyllys 
180299ebb4caSwyllys 	if (asn1)
180399ebb4caSwyllys 		kmfber_free(asn1, 1);
180499ebb4caSwyllys 
180599ebb4caSwyllys 	return (ret);
180699ebb4caSwyllys }
180799ebb4caSwyllys 
180899ebb4caSwyllys KMF_RETURN
ExtractX509CertParts(KMF_DATA * x509cert,KMF_DATA * tbscert,KMF_DATA * signature)180999ebb4caSwyllys ExtractX509CertParts(KMF_DATA *x509cert, KMF_DATA *tbscert,
181099ebb4caSwyllys 		KMF_DATA *signature)
181199ebb4caSwyllys {
181299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
181399ebb4caSwyllys 	BerElement *der = NULL;
181499ebb4caSwyllys 	BerValue x509;
181599ebb4caSwyllys 	ber_tag_t tag;
181699ebb4caSwyllys 	ber_len_t size;
181799ebb4caSwyllys 
181899ebb4caSwyllys 	if (tbscert == NULL || x509cert == NULL)
181999ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
182099ebb4caSwyllys 
182199ebb4caSwyllys 	x509.bv_val = (char *)x509cert->Data;
182299ebb4caSwyllys 	x509.bv_len = x509cert->Length;
182399ebb4caSwyllys 
182499ebb4caSwyllys 	der = kmfder_init(&x509);
182599ebb4caSwyllys 	if (der == NULL)
182699ebb4caSwyllys 		return (KMF_ERR_MEMORY);
182799ebb4caSwyllys 
182899ebb4caSwyllys 	/* Skip over the overall Sequence tag to get at the TBS Cert data */
182999ebb4caSwyllys 	if (kmfber_scanf(der, "Tl", &tag, &size) == -1) {
183099ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
183199ebb4caSwyllys 		goto cleanup;
183299ebb4caSwyllys 	}
183399ebb4caSwyllys 	if (tag != BER_CONSTRUCTED_SEQUENCE) {
183499ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
183599ebb4caSwyllys 		goto cleanup;
183699ebb4caSwyllys 	}
183799ebb4caSwyllys 
183899ebb4caSwyllys 	/*
183999ebb4caSwyllys 	 * Since we are extracting a copy of the ENCODED bytes, we
184099ebb4caSwyllys 	 * must make sure to also include the bytes for the tag and
184199ebb4caSwyllys 	 * the length fields for the CONSTRUCTED SEQUENCE (TBSCert).
184299ebb4caSwyllys 	 */
184399ebb4caSwyllys 	size += kmfber_calc_taglen(tag) + kmfber_calc_lenlen(size);
184499ebb4caSwyllys 
184599ebb4caSwyllys 	tbscert->Data = malloc(size);
184699ebb4caSwyllys 	if (tbscert->Data == NULL) {
184799ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
184899ebb4caSwyllys 		goto cleanup;
184999ebb4caSwyllys 	}
185099ebb4caSwyllys 	tbscert->Length = size;
185199ebb4caSwyllys 
185299ebb4caSwyllys 	/* The der data ptr is now set to the start of the TBS cert sequence */
185399ebb4caSwyllys 	size = kmfber_read(der, (char *)tbscert->Data, tbscert->Length);
185499ebb4caSwyllys 	if (size != tbscert->Length) {
185599ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
185699ebb4caSwyllys 		goto cleanup;
185799ebb4caSwyllys 	}
185899ebb4caSwyllys 
185999ebb4caSwyllys 	if (signature != NULL) {
186099ebb4caSwyllys 		KMF_X509_ALGORITHM_IDENTIFIER algoid;
186199ebb4caSwyllys 		if ((ret = get_algoid(der, &algoid)) != KMF_OK)
186299ebb4caSwyllys 			goto cleanup;
186399ebb4caSwyllys 		free_algoid(&algoid);
186499ebb4caSwyllys 
186599ebb4caSwyllys 		if (kmfber_scanf(der, "tl", &tag, &size) != BER_BIT_STRING) {
186699ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
186799ebb4caSwyllys 			goto cleanup;
186899ebb4caSwyllys 		}
186999ebb4caSwyllys 		/* Now get the signature data */
187099ebb4caSwyllys 		if (kmfber_scanf(der, "B", (char **)&signature->Data,
18712cbed729Swyllys 		    (ber_len_t *)&signature->Length) == -1) {
187299ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
187399ebb4caSwyllys 			goto cleanup;
187499ebb4caSwyllys 		}
187599ebb4caSwyllys 		/* convert bitstring length to bytes */
187699ebb4caSwyllys 		signature->Length = signature->Length / 8;
187799ebb4caSwyllys 	}
187899ebb4caSwyllys 
187999ebb4caSwyllys cleanup:
188099ebb4caSwyllys 	if (der)
188199ebb4caSwyllys 		kmfber_free(der, 1);
188299ebb4caSwyllys 
188399ebb4caSwyllys 	if (ret != KMF_OK)
188499ebb4caSwyllys 		free_data(tbscert);
188599ebb4caSwyllys 
188699ebb4caSwyllys 	return (ret);
188799ebb4caSwyllys }
188899ebb4caSwyllys 
188999ebb4caSwyllys static KMF_RETURN
decode_csr_extensions(BerElement * asn1,KMF_X509_EXTENSIONS * extns)189099ebb4caSwyllys decode_csr_extensions(BerElement *asn1, KMF_X509_EXTENSIONS *extns)
189199ebb4caSwyllys {
189299ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
189399ebb4caSwyllys 	BerValue oid;
189499ebb4caSwyllys 
189599ebb4caSwyllys 	if (kmfber_scanf(asn1, "{D", &oid) == -1) {
189699ebb4caSwyllys 		return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE);
189799ebb4caSwyllys 	}
189899ebb4caSwyllys 
189999ebb4caSwyllys 	/* We only understand extension requests in a CSR */
190099ebb4caSwyllys 	if (memcmp(oid.bv_val, extension_request_oid.Data,
19012cbed729Swyllys 	    oid.bv_len) != 0) {
190299ebb4caSwyllys 		return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE);
190399ebb4caSwyllys 	}
190499ebb4caSwyllys 
190599ebb4caSwyllys 	if (kmfber_scanf(asn1, "[") == -1) {
190699ebb4caSwyllys 		return (KMF_ERR_ENCODING);
190799ebb4caSwyllys 	}
190899ebb4caSwyllys 	ret = get_extensions(asn1, extns);
190999ebb4caSwyllys 
191099ebb4caSwyllys 
191199ebb4caSwyllys 	return (ret);
191299ebb4caSwyllys }
191399ebb4caSwyllys 
191499ebb4caSwyllys static KMF_RETURN
decode_tbscsr_data(BerElement * asn1,KMF_TBS_CSR ** signed_csr_ptr_ptr)191599ebb4caSwyllys decode_tbscsr_data(BerElement *asn1,
191699ebb4caSwyllys 	KMF_TBS_CSR **signed_csr_ptr_ptr)
191799ebb4caSwyllys {
191899ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
191999ebb4caSwyllys 	KMF_TBS_CSR	*tbscsr = NULL;
192099ebb4caSwyllys 	char *end = NULL;
192199ebb4caSwyllys 	uint32_t version;
192299ebb4caSwyllys 	ber_tag_t tag;
192399ebb4caSwyllys 	ber_len_t size;
192499ebb4caSwyllys 
192599ebb4caSwyllys 	/* Now get the version number, it is not optional */
192699ebb4caSwyllys 	if (kmfber_scanf(asn1, "{i", &version) == -1) {
192799ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
192899ebb4caSwyllys 		goto cleanup;
192999ebb4caSwyllys 	}
193099ebb4caSwyllys 
193199ebb4caSwyllys 	tbscsr = malloc(sizeof (KMF_TBS_CSR));
193299ebb4caSwyllys 	if (!tbscsr) {
193399ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
193499ebb4caSwyllys 		goto cleanup;
193599ebb4caSwyllys 	}
193699ebb4caSwyllys 
193799ebb4caSwyllys 	(void) memset(tbscsr, 0, sizeof (KMF_TBS_CSR));
193899ebb4caSwyllys 
193999ebb4caSwyllys 	if ((ret = set_der_integer(&tbscsr->version, version)) != KMF_OK)
194099ebb4caSwyllys 		goto cleanup;
194199ebb4caSwyllys 
194299ebb4caSwyllys 	if ((ret = get_rdn(asn1, &tbscsr->subject)) != KMF_OK)
194399ebb4caSwyllys 		goto cleanup;
194499ebb4caSwyllys 
194599ebb4caSwyllys 	if ((ret = get_spki(asn1, &tbscsr->subjectPublicKeyInfo)) != KMF_OK)
194699ebb4caSwyllys 		goto cleanup;
194799ebb4caSwyllys 
194899ebb4caSwyllys 	/* Check for the optional fields (attributes) */
194999ebb4caSwyllys 	if (kmfber_next_element(asn1, &size, end) == 0xA0) {
195099ebb4caSwyllys 		if (kmfber_scanf(asn1, "Tl", &tag, &size) == -1) {
195199ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
195299ebb4caSwyllys 			goto cleanup;
195399ebb4caSwyllys 		}
195499ebb4caSwyllys 
195599ebb4caSwyllys 		ret = decode_csr_extensions(asn1, &tbscsr->extensions);
195699ebb4caSwyllys 	}
195799ebb4caSwyllys 	if (ret == KMF_OK)
195899ebb4caSwyllys 		*signed_csr_ptr_ptr = tbscsr;
195999ebb4caSwyllys 
196099ebb4caSwyllys cleanup:
196199ebb4caSwyllys 	if (ret != KMF_OK) {
196299ebb4caSwyllys 		if (tbscsr) {
196399ebb4caSwyllys 			free_tbscsr(tbscsr);
196499ebb4caSwyllys 			free(tbscsr);
196599ebb4caSwyllys 		}
196699ebb4caSwyllys 		*signed_csr_ptr_ptr = NULL;
196799ebb4caSwyllys 	}
196899ebb4caSwyllys 	return (ret);
196999ebb4caSwyllys }
197099ebb4caSwyllys 
197199ebb4caSwyllys KMF_RETURN
DerDecodeTbsCsr(const KMF_DATA * Value,KMF_TBS_CSR ** tbscsr)197299ebb4caSwyllys DerDecodeTbsCsr(const KMF_DATA *Value,
197399ebb4caSwyllys 	KMF_TBS_CSR **tbscsr)
197499ebb4caSwyllys {
197599ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
197699ebb4caSwyllys 	BerElement *asn1 = NULL;
197799ebb4caSwyllys 	BerValue 	rawcsr;
197899ebb4caSwyllys 	KMF_TBS_CSR *newcsr = NULL;
197999ebb4caSwyllys 
198099ebb4caSwyllys 	if (!tbscsr || !Value || !Value->Data || !Value->Length)
198199ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
198299ebb4caSwyllys 
198399ebb4caSwyllys 	rawcsr.bv_val = (char *)Value->Data;
198499ebb4caSwyllys 	rawcsr.bv_len = Value->Length;
198599ebb4caSwyllys 
198699ebb4caSwyllys 	if ((asn1 = kmfder_init(&rawcsr)) == NULL)
198799ebb4caSwyllys 		return (KMF_ERR_MEMORY);
198899ebb4caSwyllys 
198999ebb4caSwyllys 	ret = decode_tbscsr_data(asn1, &newcsr);
199099ebb4caSwyllys 	if (ret != KMF_OK)
199199ebb4caSwyllys 		goto cleanup;
199299ebb4caSwyllys 
199399ebb4caSwyllys 	*tbscsr = newcsr;
199499ebb4caSwyllys 
199599ebb4caSwyllys cleanup:
199699ebb4caSwyllys 	if (ret != KMF_OK) {
199799ebb4caSwyllys 		if (newcsr)
199899ebb4caSwyllys 			free_tbscsr(newcsr);
199999ebb4caSwyllys 		*tbscsr = NULL;
200099ebb4caSwyllys 	}
200199ebb4caSwyllys 	kmfber_free(asn1, 1);
200299ebb4caSwyllys 
200399ebb4caSwyllys 	return (ret);
200499ebb4caSwyllys }
200599ebb4caSwyllys 
200699ebb4caSwyllys KMF_RETURN
DerDecodeSignedCsr(const KMF_DATA * Value,KMF_CSR_DATA ** signed_csr_ptr_ptr)200799ebb4caSwyllys DerDecodeSignedCsr(const KMF_DATA *Value,
200899ebb4caSwyllys 	KMF_CSR_DATA **signed_csr_ptr_ptr)
200999ebb4caSwyllys {
201099ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
201199ebb4caSwyllys 	BerElement *asn1 = NULL;
201299ebb4caSwyllys 	BerValue 	rawcsr;
201399ebb4caSwyllys 	int			tag;
201499ebb4caSwyllys 	ber_len_t	size;
201599ebb4caSwyllys 	char		*end = NULL;
201699ebb4caSwyllys 	char		*signature;
201799ebb4caSwyllys 	KMF_TBS_CSR	*tbscsr = NULL;
201899ebb4caSwyllys 	KMF_CSR_DATA *csrptr = NULL;
201999ebb4caSwyllys 
202099ebb4caSwyllys 	if (!signed_csr_ptr_ptr || !Value || !Value->Data || !Value->Length)
202199ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
202299ebb4caSwyllys 
202399ebb4caSwyllys 	rawcsr.bv_val = (char *)Value->Data;
202499ebb4caSwyllys 	rawcsr.bv_len = Value->Length;
202599ebb4caSwyllys 
202699ebb4caSwyllys 	if ((asn1 = kmfder_init(&rawcsr)) == NULL)
202799ebb4caSwyllys 		return (KMF_ERR_MEMORY);
202899ebb4caSwyllys 
202999ebb4caSwyllys 	if (kmfber_first_element(asn1, &size, &end) !=
20302cbed729Swyllys 	    BER_CONSTRUCTED_SEQUENCE) {
203199ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
203299ebb4caSwyllys 		goto cleanup;
203399ebb4caSwyllys 	}
203499ebb4caSwyllys 
203599ebb4caSwyllys 	csrptr = malloc(sizeof (KMF_CSR_DATA));
203699ebb4caSwyllys 	if (csrptr == NULL) {
203799ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
203899ebb4caSwyllys 		goto cleanup;
203999ebb4caSwyllys 	}
204099ebb4caSwyllys 	(void) memset(csrptr, 0, sizeof (KMF_CSR_DATA));
204199ebb4caSwyllys 
204299ebb4caSwyllys 	ret = decode_tbscsr_data(asn1, &tbscsr);
204399ebb4caSwyllys 	if (ret != KMF_OK)
204499ebb4caSwyllys 		goto cleanup;
204599ebb4caSwyllys 
204699ebb4caSwyllys 	csrptr->csr = *tbscsr;
204799ebb4caSwyllys 	free(tbscsr);
204899ebb4caSwyllys 	tbscsr = NULL;
204999ebb4caSwyllys 
205099ebb4caSwyllys 	if ((ret = get_algoid(asn1,
20512cbed729Swyllys 	    &csrptr->signature.algorithmIdentifier)) != KMF_OK)
205299ebb4caSwyllys 		goto cleanup;
205399ebb4caSwyllys 
205499ebb4caSwyllys 	/* Check to see if the cert has a signature yet */
205599ebb4caSwyllys 	if (kmfber_next_element(asn1, &size, end) == BER_BIT_STRING) {
205699ebb4caSwyllys 		/* Finally, get the encrypted signature BITSTRING */
205799ebb4caSwyllys 		if (kmfber_scanf(asn1, "tl", &tag, &size) == -1) {
205899ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
205999ebb4caSwyllys 			goto cleanup;
206099ebb4caSwyllys 		}
206199ebb4caSwyllys 		if (tag != BER_BIT_STRING) {
206299ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
206399ebb4caSwyllys 			goto cleanup;
206499ebb4caSwyllys 		}
206599ebb4caSwyllys 		if (kmfber_scanf(asn1, "B}", &signature, &size) == -1) {
206699ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
206799ebb4caSwyllys 			goto cleanup;
206899ebb4caSwyllys 		}
206999ebb4caSwyllys 		csrptr->signature.encrypted.Data = (uchar_t *)signature;
207099ebb4caSwyllys 		csrptr->signature.encrypted.Length = size / 8;
207199ebb4caSwyllys 	} else {
207299ebb4caSwyllys 		csrptr->signature.encrypted.Data = NULL;
207399ebb4caSwyllys 		csrptr->signature.encrypted.Length = 0;
207499ebb4caSwyllys 	}
207599ebb4caSwyllys 
207699ebb4caSwyllys 	*signed_csr_ptr_ptr = csrptr;
207799ebb4caSwyllys cleanup:
207899ebb4caSwyllys 	if (ret != KMF_OK) {
207999ebb4caSwyllys 		free_tbscsr(&csrptr->csr);
208099ebb4caSwyllys 		free_algoid(&csrptr->signature.algorithmIdentifier);
208199ebb4caSwyllys 		if (csrptr->signature.encrypted.Data)
208299ebb4caSwyllys 			free(csrptr->signature.encrypted.Data);
208399ebb4caSwyllys 
208499ebb4caSwyllys 		if (csrptr)
208599ebb4caSwyllys 			free(csrptr);
208699ebb4caSwyllys 
208799ebb4caSwyllys 		*signed_csr_ptr_ptr = NULL;
208899ebb4caSwyllys 	}
208999ebb4caSwyllys 	if (asn1)
209099ebb4caSwyllys 		kmfber_free(asn1, 1);
209199ebb4caSwyllys 
209299ebb4caSwyllys 	return (ret);
209399ebb4caSwyllys 
209499ebb4caSwyllys }
209599ebb4caSwyllys 
209699ebb4caSwyllys static KMF_RETURN
encode_csr_extensions(BerElement * asn1,KMF_TBS_CSR * tbscsr)209799ebb4caSwyllys encode_csr_extensions(BerElement *asn1, KMF_TBS_CSR *tbscsr)
209899ebb4caSwyllys {
209999ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
210099ebb4caSwyllys 	int attlen = 0;
210199ebb4caSwyllys 	BerElement *extnasn1 = NULL;
210299ebb4caSwyllys 	BerValue *extnvalue = NULL;
210399ebb4caSwyllys 
210499ebb4caSwyllys 	/* Optional field: CSR attributes and extensions */
210599ebb4caSwyllys 	if (tbscsr->extensions.numberOfExtensions > 0) {
210699ebb4caSwyllys 		if (kmfber_printf(asn1, "T", 0xA0) == -1) {
210799ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
210899ebb4caSwyllys 			goto cleanup;
210999ebb4caSwyllys 		}
211099ebb4caSwyllys 	} else {
211199ebb4caSwyllys 		/* No extensions or attributes to encode */
211299ebb4caSwyllys 		return (KMF_OK);
211399ebb4caSwyllys 	}
211499ebb4caSwyllys 
211599ebb4caSwyllys 	/*
211699ebb4caSwyllys 	 * attributes [0] Attributes
211799ebb4caSwyllys 	 * Attributes := SET OF Attribute
211899ebb4caSwyllys 	 * Attribute  := SEQUENCE {
211999ebb4caSwyllys 	 *   { ATTRIBUTE ID
212099ebb4caSwyllys 	 *	values SET SIZE(1..MAX) of ATTRIBUTE
212199ebb4caSwyllys 	 *   }
212299ebb4caSwyllys 	 *
212399ebb4caSwyllys 	 * Ex: { ExtensionRequest OID [ { {extn1 } , {extn2 } } ] }
212499ebb4caSwyllys 	 */
212599ebb4caSwyllys 
212699ebb4caSwyllys 	/*
212799ebb4caSwyllys 	 * Encode any extensions and add to the attributes section.
212899ebb4caSwyllys 	 */
212999ebb4caSwyllys 	if (tbscsr->extensions.numberOfExtensions > 0) {
213099ebb4caSwyllys 		extnasn1 = kmfder_alloc();
213199ebb4caSwyllys 		if (extnasn1 == NULL) {
213299ebb4caSwyllys 			ret = KMF_ERR_MEMORY;
213399ebb4caSwyllys 			goto cleanup;
213499ebb4caSwyllys 		}
213599ebb4caSwyllys 
213699ebb4caSwyllys 		if (kmfber_printf(extnasn1, "{D[{",
21372cbed729Swyllys 		    &extension_request_oid) == -1) {
213899ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
213999ebb4caSwyllys 			goto cleanup_1;
214099ebb4caSwyllys 		}
214199ebb4caSwyllys 
214299ebb4caSwyllys 		if ((ret = encode_extension_list(extnasn1,
21432cbed729Swyllys 		    &tbscsr->extensions)) != KMF_OK) {
214499ebb4caSwyllys 			goto cleanup_1;
214599ebb4caSwyllys 		}
214699ebb4caSwyllys 
214799ebb4caSwyllys 		if (kmfber_printf(extnasn1, "}]}") == -1) {
214899ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
214999ebb4caSwyllys 			goto cleanup_1;
215099ebb4caSwyllys 		}
215199ebb4caSwyllys 
215299ebb4caSwyllys 		if (kmfber_flatten(extnasn1, &extnvalue) == -1) {
215399ebb4caSwyllys 			ret = KMF_ERR_MEMORY;
215499ebb4caSwyllys 			goto cleanup_1;
215599ebb4caSwyllys 		}
215699ebb4caSwyllys cleanup_1:
215799ebb4caSwyllys 		kmfber_free(extnasn1, 1);
215899ebb4caSwyllys 
215999ebb4caSwyllys 		if (ret == KMF_OK)
216099ebb4caSwyllys 			/* Add 2 bytes to cover the tag and the length */
216199ebb4caSwyllys 			attlen = extnvalue->bv_len;
216299ebb4caSwyllys 	}
216399ebb4caSwyllys 	if (ret != KMF_OK)
216499ebb4caSwyllys 		goto cleanup;
216599ebb4caSwyllys 
216699ebb4caSwyllys 	if (kmfber_printf(asn1, "l", attlen) == -1) {
216799ebb4caSwyllys 		ret = KMF_ERR_ENCODING;
216899ebb4caSwyllys 		goto cleanup;
216999ebb4caSwyllys 	}
217099ebb4caSwyllys 
217199ebb4caSwyllys 	/* Write the actual encoded extensions */
217299ebb4caSwyllys 	if (extnvalue != NULL && extnvalue->bv_val != NULL) {
217399ebb4caSwyllys 		if (kmfber_write(asn1, extnvalue->bv_val,
21742cbed729Swyllys 		    extnvalue->bv_len, 0) == -1) {
217599ebb4caSwyllys 			ret = KMF_ERR_ENCODING;
217699ebb4caSwyllys 			goto cleanup;
217799ebb4caSwyllys 		}
217899ebb4caSwyllys 	}
217999ebb4caSwyllys 
218099ebb4caSwyllys cleanup:
218199ebb4caSwyllys 	/*
218299ebb4caSwyllys 	 * Memory cleanup is done in the caller or in the individual
218399ebb4caSwyllys 	 * encoding routines.
218499ebb4caSwyllys 	 */
218599ebb4caSwyllys 	if (extnvalue) {
218699ebb4caSwyllys 		if (extnvalue->bv_val)
218799ebb4caSwyllys 			free(extnvalue->bv_val);
218899ebb4caSwyllys 		free(extnvalue);
218999ebb4caSwyllys 	}
219099ebb4caSwyllys 
219199ebb4caSwyllys 	return (ret);
219299ebb4caSwyllys }
219399ebb4caSwyllys 
219499ebb4caSwyllys static KMF_RETURN
encode_tbs_csr(BerElement * asn1,KMF_TBS_CSR * tbscsr)219599ebb4caSwyllys encode_tbs_csr(BerElement *asn1, KMF_TBS_CSR *tbscsr)
219699ebb4caSwyllys {
219799ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
219899ebb4caSwyllys 	uint32_t version;
219999ebb4caSwyllys 
220099ebb4caSwyllys 	/* Start the version */
220199ebb4caSwyllys 	(void) memcpy(&version, tbscsr->version.Data,
22022cbed729Swyllys 	    tbscsr->version.Length);
220399ebb4caSwyllys 
220402b8f7bbSwyllys 	if (kmfber_printf(asn1, "{i", version) == -1) {
220599ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
220699ebb4caSwyllys 		goto cleanup;
220799ebb4caSwyllys 	}
220899ebb4caSwyllys 
220999ebb4caSwyllys 	/* Encode the Subject RDN */
221099ebb4caSwyllys 	if ((ret = encode_rdn(asn1, &tbscsr->subject)) != KMF_OK)
221199ebb4caSwyllys 		goto cleanup;
221299ebb4caSwyllys 
221399ebb4caSwyllys 	/* Encode the Subject Public Key Info */
221499ebb4caSwyllys 	if ((ret = encode_spki(asn1, &tbscsr->subjectPublicKeyInfo)) != KMF_OK)
221599ebb4caSwyllys 		goto cleanup;
221699ebb4caSwyllys 
221799ebb4caSwyllys 	if ((ret = encode_csr_extensions(asn1, tbscsr)) != KMF_OK)
221899ebb4caSwyllys 		goto cleanup;
221999ebb4caSwyllys 
222099ebb4caSwyllys 	/* Close out the TBSCert sequence */
222199ebb4caSwyllys 	if (kmfber_printf(asn1, "}") == -1) {
222299ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
222399ebb4caSwyllys 		goto cleanup;
222499ebb4caSwyllys 	}
222599ebb4caSwyllys 
222699ebb4caSwyllys cleanup:
222799ebb4caSwyllys 	return (ret);
222899ebb4caSwyllys }
222999ebb4caSwyllys 
223099ebb4caSwyllys KMF_RETURN
DerEncodeDSAPrivateKey(KMF_DATA * encodedkey,KMF_RAW_DSA_KEY * dsa)223199ebb4caSwyllys DerEncodeDSAPrivateKey(KMF_DATA *encodedkey, KMF_RAW_DSA_KEY *dsa)
223299ebb4caSwyllys {
223399ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
223499ebb4caSwyllys 	BerElement *asn1 = NULL;
223599ebb4caSwyllys 	BerValue  *dsadata = NULL;
223699ebb4caSwyllys 
223799ebb4caSwyllys 	asn1 = kmfder_alloc();
223899ebb4caSwyllys 	if (asn1 == NULL)
223999ebb4caSwyllys 		return (KMF_ERR_MEMORY);
224099ebb4caSwyllys 
224199ebb4caSwyllys 	if (kmfber_printf(asn1, "I",
22422cbed729Swyllys 	    dsa->value.val, dsa->value.len) == -1) {
224399ebb4caSwyllys 		rv = KMF_ERR_MEMORY;
224499ebb4caSwyllys 		goto cleanup;
224599ebb4caSwyllys 	}
224699ebb4caSwyllys 
224799ebb4caSwyllys 	if (kmfber_flatten(asn1, &dsadata) == -1) {
224899ebb4caSwyllys 		rv = KMF_ERR_MEMORY;
224999ebb4caSwyllys 		goto cleanup;
225099ebb4caSwyllys 	}
225199ebb4caSwyllys 
225299ebb4caSwyllys 	encodedkey->Data = (uchar_t *)dsadata->bv_val;
225399ebb4caSwyllys 	encodedkey->Length = dsadata->bv_len;
225499ebb4caSwyllys 
225599ebb4caSwyllys 	free(dsadata);
225699ebb4caSwyllys cleanup:
225799ebb4caSwyllys 	kmfber_free(asn1, 1);
225899ebb4caSwyllys 	return (rv);
225999ebb4caSwyllys }
226099ebb4caSwyllys 
226199ebb4caSwyllys KMF_RETURN
DerEncodeRSAPrivateKey(KMF_DATA * encodedkey,KMF_RAW_RSA_KEY * rsa)226299ebb4caSwyllys DerEncodeRSAPrivateKey(KMF_DATA *encodedkey, KMF_RAW_RSA_KEY *rsa)
226399ebb4caSwyllys {
226499ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
226599ebb4caSwyllys 	BerElement *asn1 = NULL;
226699ebb4caSwyllys 	uchar_t ver = 0;
226799ebb4caSwyllys 	BerValue  *rsadata = NULL;
226899ebb4caSwyllys 
226999ebb4caSwyllys 	asn1 = kmfder_alloc();
227099ebb4caSwyllys 	if (asn1 == NULL)
227199ebb4caSwyllys 		return (KMF_ERR_MEMORY);
227299ebb4caSwyllys 
227399ebb4caSwyllys 	if (kmfber_printf(asn1, "{IIIIIIIII}",
22742cbed729Swyllys 	    &ver, 1,
22752cbed729Swyllys 	    rsa->mod.val, rsa->mod.len,
22762cbed729Swyllys 	    rsa->pubexp.val, rsa->pubexp.len,
22772cbed729Swyllys 	    rsa->priexp.val, rsa->priexp.len,
22782cbed729Swyllys 	    rsa->prime1.val, rsa->prime1.len,
22792cbed729Swyllys 	    rsa->prime2.val, rsa->prime2.len,
22802cbed729Swyllys 	    rsa->exp1.val, rsa->exp1.len,
22812cbed729Swyllys 	    rsa->exp2.val, rsa->exp2.len,
22822cbed729Swyllys 	    rsa->coef.val, rsa->coef.len) == -1)
228399ebb4caSwyllys 		goto cleanup;
228499ebb4caSwyllys 
228599ebb4caSwyllys 	if (kmfber_flatten(asn1, &rsadata) == -1) {
228699ebb4caSwyllys 		rv = KMF_ERR_MEMORY;
228799ebb4caSwyllys 		goto cleanup;
228899ebb4caSwyllys 	}
228999ebb4caSwyllys 
229099ebb4caSwyllys 	encodedkey->Data = (uchar_t *)rsadata->bv_val;
229199ebb4caSwyllys 	encodedkey->Length = rsadata->bv_len;
229299ebb4caSwyllys 
229399ebb4caSwyllys 	free(rsadata);
229499ebb4caSwyllys cleanup:
229599ebb4caSwyllys 	kmfber_free(asn1, 1);
229699ebb4caSwyllys 	return (rv);
229799ebb4caSwyllys }
229899ebb4caSwyllys 
2299*e65e5c2dSWyllys Ingersoll KMF_RETURN
DerEncodeECPrivateKey(KMF_DATA * encodedkey,KMF_RAW_EC_KEY * eckey)2300*e65e5c2dSWyllys Ingersoll DerEncodeECPrivateKey(KMF_DATA *encodedkey, KMF_RAW_EC_KEY *eckey)
2301*e65e5c2dSWyllys Ingersoll {
2302*e65e5c2dSWyllys Ingersoll 	KMF_RETURN rv = KMF_OK;
2303*e65e5c2dSWyllys Ingersoll 	BerElement *asn1 = NULL;
2304*e65e5c2dSWyllys Ingersoll 	uchar_t ver = 1;
2305*e65e5c2dSWyllys Ingersoll 	BerValue  *data = NULL;
2306*e65e5c2dSWyllys Ingersoll 
2307*e65e5c2dSWyllys Ingersoll 	asn1 = kmfder_alloc();
2308*e65e5c2dSWyllys Ingersoll 	if (asn1 == NULL)
2309*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_MEMORY);
2310*e65e5c2dSWyllys Ingersoll 
2311*e65e5c2dSWyllys Ingersoll 	if (kmfber_printf(asn1, "{io",
2312*e65e5c2dSWyllys Ingersoll 	    ver, eckey->value.val, eckey->value.len) == -1) {
2313*e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_ENCODING;
2314*e65e5c2dSWyllys Ingersoll 		goto cleanup;
2315*e65e5c2dSWyllys Ingersoll 	}
2316*e65e5c2dSWyllys Ingersoll 	/*
2317*e65e5c2dSWyllys Ingersoll 	 * Indicate that we are using the named curve option
2318*e65e5c2dSWyllys Ingersoll 	 * for the parameters.
2319*e65e5c2dSWyllys Ingersoll 	 */
2320*e65e5c2dSWyllys Ingersoll 	if (kmfber_printf(asn1, "T", 0xA0) == -1) {
2321*e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_ENCODING;
2322*e65e5c2dSWyllys Ingersoll 		goto cleanup;
2323*e65e5c2dSWyllys Ingersoll 	}
2324*e65e5c2dSWyllys Ingersoll 	if (kmfber_printf(asn1, "l", eckey->params.Length) == -1) {
2325*e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_ENCODING;
2326*e65e5c2dSWyllys Ingersoll 		goto cleanup;
2327*e65e5c2dSWyllys Ingersoll 	}
2328*e65e5c2dSWyllys Ingersoll 	if (kmfber_write(asn1, (char *)eckey->params.Data,
2329*e65e5c2dSWyllys Ingersoll 	    eckey->params.Length, 0) == -1) {
2330*e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_ENCODING;
2331*e65e5c2dSWyllys Ingersoll 		goto cleanup;
2332*e65e5c2dSWyllys Ingersoll 	}
2333*e65e5c2dSWyllys Ingersoll 	if (kmfber_printf(asn1, "}") == -1) {
2334*e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_ENCODING;
2335*e65e5c2dSWyllys Ingersoll 		goto cleanup;
2336*e65e5c2dSWyllys Ingersoll 	}
2337*e65e5c2dSWyllys Ingersoll 	if (kmfber_flatten(asn1, &data) == -1) {
2338*e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_MEMORY;
2339*e65e5c2dSWyllys Ingersoll 		goto cleanup;
2340*e65e5c2dSWyllys Ingersoll 	}
2341*e65e5c2dSWyllys Ingersoll 	encodedkey->Data = (uchar_t *)data->bv_val;
2342*e65e5c2dSWyllys Ingersoll 	encodedkey->Length = data->bv_len;
2343*e65e5c2dSWyllys Ingersoll 
2344*e65e5c2dSWyllys Ingersoll cleanup:
2345*e65e5c2dSWyllys Ingersoll 	kmfber_free(asn1, 1);
2346*e65e5c2dSWyllys Ingersoll 	return (rv);
2347*e65e5c2dSWyllys Ingersoll }
2348*e65e5c2dSWyllys Ingersoll 
234999ebb4caSwyllys 
235099ebb4caSwyllys KMF_RETURN
DerEncodeTbsCsr(KMF_TBS_CSR * tbs_csr_ptr,KMF_DATA * enc_tbs_csr_ptr)235199ebb4caSwyllys DerEncodeTbsCsr(KMF_TBS_CSR *tbs_csr_ptr,
235299ebb4caSwyllys 	KMF_DATA *enc_tbs_csr_ptr)
235399ebb4caSwyllys {
235499ebb4caSwyllys 	KMF_RETURN ret;
235599ebb4caSwyllys 	BerValue  *tbsdata = NULL;
235699ebb4caSwyllys 	BerElement *asn1 = NULL;
235799ebb4caSwyllys 
235899ebb4caSwyllys 	asn1 = kmfder_alloc();
235999ebb4caSwyllys 
236099ebb4caSwyllys 	enc_tbs_csr_ptr->Data = NULL;
236199ebb4caSwyllys 	enc_tbs_csr_ptr->Length = 0;
236299ebb4caSwyllys 
236399ebb4caSwyllys 	if (asn1 == NULL)
236499ebb4caSwyllys 		return (KMF_ERR_MEMORY);
236599ebb4caSwyllys 
236699ebb4caSwyllys 	ret = encode_tbs_csr(asn1, tbs_csr_ptr);
236799ebb4caSwyllys 	if (ret != KMF_OK)
236899ebb4caSwyllys 		goto cleanup;
236999ebb4caSwyllys 
237099ebb4caSwyllys 	if (kmfber_flatten(asn1, &tbsdata) == -1) {
237199ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
237299ebb4caSwyllys 		goto cleanup;
237399ebb4caSwyllys 	}
237499ebb4caSwyllys 
237599ebb4caSwyllys 	enc_tbs_csr_ptr->Data = (uchar_t *)tbsdata->bv_val;
237699ebb4caSwyllys 	enc_tbs_csr_ptr->Length = tbsdata->bv_len;
237799ebb4caSwyllys 
237899ebb4caSwyllys cleanup:
237999ebb4caSwyllys 	if (ret != KMF_OK)
238099ebb4caSwyllys 		free_data(enc_tbs_csr_ptr);
238199ebb4caSwyllys 
238299ebb4caSwyllys 	if (asn1 != NULL)
238399ebb4caSwyllys 		kmfber_free(asn1, 1);
238499ebb4caSwyllys 
238599ebb4caSwyllys 	if (tbsdata)
238699ebb4caSwyllys 		free(tbsdata);
238799ebb4caSwyllys 
238899ebb4caSwyllys 	return (ret);
238999ebb4caSwyllys }
239099ebb4caSwyllys 
239199ebb4caSwyllys KMF_RETURN
DerEncodeSignedCsr(KMF_CSR_DATA * signed_csr_ptr,KMF_DATA * encodedcsr)239299ebb4caSwyllys DerEncodeSignedCsr(KMF_CSR_DATA *signed_csr_ptr,
239399ebb4caSwyllys 	KMF_DATA *encodedcsr)
239499ebb4caSwyllys {
239599ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
239699ebb4caSwyllys 	KMF_TBS_CSR *tbscsr = NULL;
239799ebb4caSwyllys 	KMF_X509_SIGNATURE		*signature = NULL;
239899ebb4caSwyllys 	BerElement	*asn1 = NULL;
239999ebb4caSwyllys 	BerValue 	*tbsdata = NULL;
240099ebb4caSwyllys 
240199ebb4caSwyllys 	if (signed_csr_ptr == NULL)
240299ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
240399ebb4caSwyllys 
240499ebb4caSwyllys 	tbscsr = &signed_csr_ptr->csr;
240599ebb4caSwyllys 	signature = &signed_csr_ptr->signature;
240699ebb4caSwyllys 
240799ebb4caSwyllys 	asn1 = kmfder_alloc();
240899ebb4caSwyllys 	if (asn1 == NULL)
240999ebb4caSwyllys 		return (KMF_ERR_MEMORY);
241099ebb4caSwyllys 
241199ebb4caSwyllys 	/* Start outer CSR SEQUENCE */
241299ebb4caSwyllys 	if (kmfber_printf(asn1, "{") == -1) {
241399ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
241499ebb4caSwyllys 		goto cleanup;
241599ebb4caSwyllys 	}
241699ebb4caSwyllys 
241799ebb4caSwyllys 	ret = encode_tbs_csr(asn1, tbscsr);
241899ebb4caSwyllys 
241999ebb4caSwyllys 	/* Add the Algorithm & Signature Sequence */
242099ebb4caSwyllys 	if ((ret = encode_algoid(asn1,
2421*e65e5c2dSWyllys Ingersoll 	    &signature->algorithmIdentifier, FALSE)) != KMF_OK)
242299ebb4caSwyllys 		goto cleanup;
242399ebb4caSwyllys 
242499ebb4caSwyllys 	if (signature->encrypted.Length > 0) {
242599ebb4caSwyllys 		if (kmfber_printf(asn1, "B", signature->encrypted.Data,
24262cbed729Swyllys 		    signature->encrypted.Length * 8) == -1) {
242799ebb4caSwyllys 			ret = KMF_ERR_BAD_CERT_FORMAT;
242899ebb4caSwyllys 			goto cleanup;
242999ebb4caSwyllys 		}
243099ebb4caSwyllys 	}
243199ebb4caSwyllys 
243299ebb4caSwyllys 	if (kmfber_printf(asn1, "}") == -1) {
243399ebb4caSwyllys 		ret = KMF_ERR_BAD_CERT_FORMAT;
243499ebb4caSwyllys 		goto cleanup;
243599ebb4caSwyllys 	}
243699ebb4caSwyllys 
243799ebb4caSwyllys 	if (kmfber_flatten(asn1, &tbsdata) == -1) {
243899ebb4caSwyllys 		ret = KMF_ERR_MEMORY;
243999ebb4caSwyllys 		goto cleanup;
244099ebb4caSwyllys 	}
244199ebb4caSwyllys 
244299ebb4caSwyllys 	encodedcsr->Data = (uchar_t *)tbsdata->bv_val;
244399ebb4caSwyllys 	encodedcsr->Length = tbsdata->bv_len;
244499ebb4caSwyllys 
244599ebb4caSwyllys cleanup:
244699ebb4caSwyllys 	if (ret != KMF_OK) {
244799ebb4caSwyllys 		free_data(encodedcsr);
244899ebb4caSwyllys 	}
244999ebb4caSwyllys 
245099ebb4caSwyllys 	if (tbsdata)
245199ebb4caSwyllys 		free(tbsdata);
245299ebb4caSwyllys 
245399ebb4caSwyllys 	if (asn1)
245499ebb4caSwyllys 		kmfber_free(asn1, 1);
245599ebb4caSwyllys 	return (ret);
245699ebb4caSwyllys }
245799ebb4caSwyllys 
2458*e65e5c2dSWyllys Ingersoll static KMF_RETURN
ber_copy_data(KMF_DATA * dst,KMF_DATA * src)2459*e65e5c2dSWyllys Ingersoll ber_copy_data(KMF_DATA *dst, KMF_DATA *src)
2460*e65e5c2dSWyllys Ingersoll {
2461*e65e5c2dSWyllys Ingersoll 	KMF_RETURN ret = KMF_OK;
2462*e65e5c2dSWyllys Ingersoll 
2463*e65e5c2dSWyllys Ingersoll 	if (dst == NULL || src == NULL)
2464*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_BAD_PARAMETER);
2465*e65e5c2dSWyllys Ingersoll 
2466*e65e5c2dSWyllys Ingersoll 	dst->Data = malloc(src->Length);
2467*e65e5c2dSWyllys Ingersoll 	if (dst->Data == NULL)
2468*e65e5c2dSWyllys Ingersoll 		return (KMF_ERR_MEMORY);
2469*e65e5c2dSWyllys Ingersoll 
2470*e65e5c2dSWyllys Ingersoll 	dst->Length = src->Length;
2471*e65e5c2dSWyllys Ingersoll 	(void) memcpy(dst->Data, src->Data, src->Length);
2472*e65e5c2dSWyllys Ingersoll 
2473*e65e5c2dSWyllys Ingersoll 	return (ret);
2474*e65e5c2dSWyllys Ingersoll }
2475*e65e5c2dSWyllys Ingersoll 
247699ebb4caSwyllys KMF_RETURN
ExtractSPKIData(const KMF_X509_SPKI * pKey,KMF_ALGORITHM_INDEX AlgorithmId,KMF_DATA * pKeyParts,uint32_t * uNumKeyParts)247799ebb4caSwyllys ExtractSPKIData(
247899ebb4caSwyllys 	const KMF_X509_SPKI *pKey,
247999ebb4caSwyllys 	KMF_ALGORITHM_INDEX AlgorithmId,
248099ebb4caSwyllys 	KMF_DATA *pKeyParts,
248199ebb4caSwyllys 	uint32_t *uNumKeyParts)
248299ebb4caSwyllys {
248399ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
248499ebb4caSwyllys 	BerElement *asn1 = NULL;
248599ebb4caSwyllys 	BerValue 	*P, *Q, *G, *Mod, *Exp, *PubKey;
248699ebb4caSwyllys 	BerValue	PubKeyParams, PubKeyData;
248799ebb4caSwyllys 
248899ebb4caSwyllys 	if (pKeyParts == NULL || uNumKeyParts == NULL || pKey == NULL)
248999ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
249099ebb4caSwyllys 
249199ebb4caSwyllys 	switch (AlgorithmId) {
24922cbed729Swyllys 		case KMF_ALGID_DSA:
24932cbed729Swyllys 		case KMF_ALGID_SHA1WithDSA:
24942cbed729Swyllys 			*uNumKeyParts = 0;
24952cbed729Swyllys 			/* Get the parameters from the algorithm definition */
24962cbed729Swyllys 			PubKeyParams.bv_val =
24972cbed729Swyllys 			    (char *)pKey->algorithm.parameters.Data;
24982cbed729Swyllys 			PubKeyParams.bv_len = pKey->algorithm.parameters.Length;
24992cbed729Swyllys 			if ((asn1 = kmfder_init(&PubKeyParams)) == NULL)
25002cbed729Swyllys 				return (KMF_ERR_MEMORY);
250199ebb4caSwyllys 
25022cbed729Swyllys 			if (kmfber_scanf(asn1, "{III}", &P, &Q, &G) == -1) {
25032cbed729Swyllys 				kmfber_free(asn1, 1);
25042cbed729Swyllys 				return (KMF_ERR_BAD_KEY_FORMAT);
25052cbed729Swyllys 			}
25062cbed729Swyllys 			pKeyParts[KMF_DSA_PRIME].Data = (uchar_t *)P->bv_val;
25072cbed729Swyllys 			pKeyParts[KMF_DSA_PRIME].Length = P->bv_len;
25082cbed729Swyllys 			pKeyParts[KMF_DSA_SUB_PRIME].Data =
25092cbed729Swyllys 			    (uchar_t *)Q->bv_val;
25102cbed729Swyllys 			pKeyParts[KMF_DSA_SUB_PRIME].Length = Q->bv_len;
25112cbed729Swyllys 			pKeyParts[KMF_DSA_BASE].Data = (uchar_t *)G->bv_val;
25122cbed729Swyllys 			pKeyParts[KMF_DSA_BASE].Length = G->bv_len;
25132cbed729Swyllys 
25142cbed729Swyllys 			free(P);
25152cbed729Swyllys 			free(Q);
25162cbed729Swyllys 			free(G);
251799ebb4caSwyllys 			kmfber_free(asn1, 1);
251899ebb4caSwyllys 
25192cbed729Swyllys 			/* Get the PubKey data */
25202cbed729Swyllys 			PubKeyData.bv_val = (char *)pKey->subjectPublicKey.Data;
25212cbed729Swyllys 			PubKeyData.bv_len = pKey->subjectPublicKey.Length;
25222cbed729Swyllys 			if ((asn1 = kmfder_init(&PubKeyData)) == NULL) {
25232cbed729Swyllys 				ret = KMF_ERR_MEMORY;
25242cbed729Swyllys 				goto cleanup;
25252cbed729Swyllys 			}
25262cbed729Swyllys 			PubKey = NULL;
25272cbed729Swyllys 			if (kmfber_scanf(asn1, "I", &PubKey) == -1) {
25282cbed729Swyllys 				ret = KMF_ERR_BAD_KEY_FORMAT;
25292cbed729Swyllys 				goto cleanup;
25302cbed729Swyllys 			}
25312cbed729Swyllys 			pKeyParts[KMF_DSA_PUBLIC_VALUE].Data =
25322cbed729Swyllys 			    (uchar_t *)PubKey->bv_val;
25332cbed729Swyllys 			pKeyParts[KMF_DSA_PUBLIC_VALUE].Length = PubKey->bv_len;
253499ebb4caSwyllys 
25352cbed729Swyllys 			free(PubKey);
253699ebb4caSwyllys 
25372cbed729Swyllys 			*uNumKeyParts = KMF_NUMBER_DSA_PUBLIC_KEY_PARTS;
25382cbed729Swyllys 			break;
2539*e65e5c2dSWyllys Ingersoll 		case KMF_ALGID_SHA1WithECDSA:
2540*e65e5c2dSWyllys Ingersoll 		case KMF_ALGID_ECDSA:
2541*e65e5c2dSWyllys Ingersoll 			(void) ber_copy_data(&pKeyParts[KMF_ECDSA_PARAMS],
2542*e65e5c2dSWyllys Ingersoll 			    (KMF_DATA *)&pKey->algorithm.parameters);
2543*e65e5c2dSWyllys Ingersoll 
2544*e65e5c2dSWyllys Ingersoll 			(void) ber_copy_data(&pKeyParts[KMF_ECDSA_POINT],
2545*e65e5c2dSWyllys Ingersoll 			    (KMF_DATA *)&pKey->subjectPublicKey);
2546*e65e5c2dSWyllys Ingersoll 
2547*e65e5c2dSWyllys Ingersoll 			*uNumKeyParts = 2;
2548*e65e5c2dSWyllys Ingersoll 			break;
254999ebb4caSwyllys 
25502cbed729Swyllys 		case KMF_ALGID_RSA:
25512cbed729Swyllys 		case KMF_ALGID_MD2WithRSA:
25522cbed729Swyllys 		case KMF_ALGID_MD5WithRSA:
25532cbed729Swyllys 		case KMF_ALGID_SHA1WithRSA:
25542cbed729Swyllys 			*uNumKeyParts = 0;
25552cbed729Swyllys 			PubKeyData.bv_val = (char *)pKey->subjectPublicKey.Data;
25562cbed729Swyllys 			PubKeyData.bv_len = pKey->subjectPublicKey.Length;
25572cbed729Swyllys 			if ((asn1 = kmfder_init(&PubKeyData)) == NULL) {
25582cbed729Swyllys 				ret = KMF_ERR_MEMORY;
25592cbed729Swyllys 				goto cleanup;
25602cbed729Swyllys 			}
25612cbed729Swyllys 			if (kmfber_scanf(asn1, "{II}", &Mod, &Exp) == -1) {
25622cbed729Swyllys 				ret = KMF_ERR_BAD_KEY_FORMAT;
25632cbed729Swyllys 				goto cleanup;
25642cbed729Swyllys 			}
25652cbed729Swyllys 			pKeyParts[KMF_RSA_MODULUS].Data =
25662cbed729Swyllys 			    (uchar_t *)Mod->bv_val;
25672cbed729Swyllys 			pKeyParts[KMF_RSA_MODULUS].Length = Mod->bv_len;
25682cbed729Swyllys 			pKeyParts[KMF_RSA_PUBLIC_EXPONENT].Data =
25692cbed729Swyllys 			    (uchar_t *)Exp->bv_val;
25702cbed729Swyllys 			pKeyParts[KMF_RSA_PUBLIC_EXPONENT].Length = Exp->bv_len;
25712cbed729Swyllys 			*uNumKeyParts = KMF_NUMBER_RSA_PUBLIC_KEY_PARTS;
25722cbed729Swyllys 
25732cbed729Swyllys 			free(Mod);
25742cbed729Swyllys 			free(Exp);
25752cbed729Swyllys 			break;
25762cbed729Swyllys 		default:
25772cbed729Swyllys 			return (KMF_ERR_BAD_PARAMETER);
257899ebb4caSwyllys 	}
257999ebb4caSwyllys cleanup:
258099ebb4caSwyllys 	if (ret != KMF_OK) {
258199ebb4caSwyllys 		int i;
258299ebb4caSwyllys 		for (i = 0; i < *uNumKeyParts; i++)
258399ebb4caSwyllys 			free_data(&pKeyParts[i]);
258499ebb4caSwyllys 	}
258599ebb4caSwyllys 	if (asn1 != NULL) {
258699ebb4caSwyllys 		kmfber_free(asn1, 1);
258799ebb4caSwyllys 	}
258899ebb4caSwyllys 
258999ebb4caSwyllys 	return (ret);
259099ebb4caSwyllys }
2591