/*
*/
/*
* Copyright (c) 1995-1999 Intel Corporation. All rights reserved.
*/
#include <strings.h>
#include <kmftypes.h>
#include <ber_der.h>
#include <kmfber_int.h>
#include <kmfapi.h>
#include <kmfapiP.h>
#include <stdio.h>
static KMF_RETURN
{
}
if (!encode_params) {
return (KMF_ERR_BAD_CERT_FORMAT);
return (KMF_ERR_BAD_CERT_FORMAT);
} else {
/*
* The algorithm data can be anything, so we just write it
* straight into the buffer. It is already DER encoded.
*/
}
}
return (ret);
}
static void
{
return;
}
static void
{
}
static void
{
}
}
static void
{
}
static void
{
int i;
for (i = 0; i < rdn->numberOfPairs; i++) {
}
rdn->numberOfPairs = 0;
}
static void
{
int i;
if (name->numberOfRDNs != 0) {
for (i = 0; i < name->numberOfRDNs; i++) {
&name->RelativeDistinguishedName[i]);
}
name->numberOfRDNs = 0;
}
}
}
static void
{
}
static void
{
}
}
static void
{
int i;
for (i = 0; i < extns->numberOfExtensions; i++) {
}
extns->numberOfExtensions = 0;
}
}
static void
{
if (tbscsr) {
}
}
static void
{
}
}
static void
{
if (tbscert) {
}
}
static void
{
if (!certptr)
return;
}
static KMF_RETURN
{
if (tag == BER_OBJECT_IDENTIFIER) {
/* The whole block is the OID. */
return (KMF_ERR_MEMORY);
}
/* read the raw data into the Algorithm params area. */
-1) {
return (KMF_ERR_BAD_CERT_FORMAT);
}
return (KMF_OK);
} else if (tag != BER_CONSTRUCTED_SEQUENCE)
return (KMF_ERR_BAD_CERT_FORMAT);
return (KMF_ERR_BAD_CERT_FORMAT);
}
/*
* We need to read the tag and the length bytes too,
* so adjust the size.
*/
return (KMF_ERR_MEMORY);
}
/* read the raw data into the Algorithm params area. */
-1) {
return (KMF_ERR_BAD_CERT_FORMAT);
}
return (KMF_OK);
}
static KMF_RETURN
{
/* Read the entire OID seq into it's own data block */
return (rv);
/* Now parse just this block so we don't overrun */
return (KMF_ERR_MEMORY);
}
if (tag == BER_OBJECT_IDENTIFIER) {
return (KMF_OK);
}
return (KMF_ERR_BAD_CERT_FORMAT);
}
/* close sequence, we are done with Algoid */
} else {
/* The rest of the data is the algorithm parameters */
goto cleanup;
}
/*
* We need to read the tag and the length bytes too,
* so adjust the size.
*/
rv = KMF_ERR_MEMORY;
goto cleanup;
}
/* read the raw data into the Algorithm params area. */
size) == -1) {
goto cleanup;
}
}
}
return (rv);
}
static KMF_RETURN
{
return (KMF_ERR_MEMORY);
}
return (KMF_OK);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_CERT_FORMAT);
/*
* The SPKI is the only place where algorithm parameters
* should be encoded.
*/
return (ret);
return (KMF_ERR_BAD_CERT_FORMAT);
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
return (ret);
}
return (KMF_ERR_ENCODING);
}
return (KMF_OK);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_CERT_FORMAT);
return (ret);
} else {
goto cleanup;
}
}
return (ret);
}
{
int n;
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_BAD_PARAMETER);
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
/*
* The [EC]DSA signature is the concatenation of 2
* bignum values.
*/
return (KMF_ERR_MEMORY);
}
return (KMF_ERR_ENCODING);
}
return (KMF_OK);
}
/*
* ECDSA and DSA encode signatures the same way.
*/
{
}
/*
* Convert a signed DSA sig to a fixed-length unsigned one.
* This is necessary because DER encoding seeks to use the
* minimal amount of bytes but we need a full 20 byte DSA
* value with leading 0x00 bytes.
*/
static KMF_RETURN
{
int cnt;
char *p;
/* prepend with leading 0s */
return (KMF_OK);
}
return (KMF_OK);
}
/*
* src is larger than dest, strip leading 0s.
* This should not be necessary, but do it just in case.
*/
while (cnt-- > 0) {
if (*p++ != 0x00)
return (KMF_ERR_ENCODING);
}
return (KMF_OK);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
goto cleanup;
}
/*
* If either of the values had a leading 0 lopped off
* they will be 1 byte short and need to be adjusted below.
* The stripping is correct as per ASN.1 rules.
*
* We don't know the exact length that the R and S values
* must be, it depends on the signature algorithm and,
* in the case of EC, the curve used. So instead of
* checking for a specific length, we just check to see
* if the value came out to be an odd number. If so,
* then we know it needs a leading 0x00 byte which
* will be added below when we convert it to a fixed
* length.
*/
if ((R->bv_len % 2) != 0)
if ((S->bv_len % 2) != 0)
goto cleanup;
}
/* adjust length if it needs a leading 0x00 byte */
/* adjust length if it needs a leading 0x00 byte */
/*
* This will add back any missing leading 0's
* that were stripped off earlier when the signature
* was parsed. This ensures that the 2 parts of the
* signature are the right length and have the proper
* leading 0's prepended.
*/
if (ret)
goto cleanup;
if (R && R->bv_val)
if (S && S->bv_val)
if (S) free(S);
if (R) free(R);
return (ret);
}
{
/* ECDSA can be decoded using same code as standard DSA */
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
}
return (ret);
}
{
return (KMF_ERR_MEMORY);
goto cleanup;
goto cleanup;
goto cleanup;
if (newspki)
}
return (ret);
}
static KMF_RETURN
{
int ret;
if (ret == -1)
return (KMF_ERR_BAD_CERT_FORMAT);
return (KMF_OK);
}
static KMF_RETURN
{
int tag;
if (tag != BER_CONSTRUCTED_SEQUENCE) {
return (KMF_ERR_BAD_CERT_FORMAT);
}
return (KMF_ERR_BAD_CERT_FORMAT);
}
return (ret);
}
{
/* Add new RDN record to existing list */
goto cleanup;
}
name->numberOfRDNs++;
if (newrdn) {
} else {
rdnslot->numberOfPairs = 0;
}
/* No cleanup needed here */
return (ret);
}
static KMF_RETURN
{
int i, j;
goto cleanup;
}
for (i = 0; i < name->numberOfRDNs; i++) {
goto cleanup;
}
for (j = 0; j < rdn->numberOfPairs; j++) {
&attrtvpair->type,
goto cleanup;
}
}
goto cleanup;
}
}
goto cleanup;
}
/* No cleanup needed here */
return (ret);
}
{
int i, j;
return (KMF_ERR_MEMORY);
sizeof (KMF_X509_RDN));
return (KMF_ERR_MEMORY);
}
/* Copy each RDN in the list */
for (i = 0; i < newname->numberOfRDNs; i++) {
if (dstrdn->numberOfPairs > 0) {
sizeof (KMF_X509_TYPE_VALUE_PAIR));
goto cleanup;
}
sizeof (KMF_X509_TYPE_VALUE_PAIR));
goto cleanup;
}
/* Copy each A/V pair in the list */
for (j = 0; j < dstrdn->numberOfPairs; j++) {
goto cleanup;
goto cleanup;
}
} else {
}
}
if (newname)
}
return (ret);
}
#define VALID_DIRECTORYSTRING_TAG(t) ( \
(t == BER_UTF8_STRING) || \
(t == BER_PRINTABLE_STRING) || \
(t == BER_IA5STRING) || \
(t == BER_T61STRING) || \
(t == BER_BMP_STRING) || \
(t == BER_UNIVERSAL_STRING))
static KMF_RETURN
{
sizeof (KMF_X509_TYPE_VALUE_PAIR));
return (KMF_ERR_MEMORY);
sizeof (KMF_X509_TYPE_VALUE_PAIR));
} else {
sizeof (KMF_X509_TYPE_VALUE_PAIR) *
return (KMF_ERR_MEMORY);
rdn->numberOfPairs++;
sizeof (KMF_X509_TYPE_VALUE_PAIR));
}
return (KMF_OK);
}
static KMF_RETURN
{
char *end;
int tag;
/*
* AttributeType ::= OBJECT IDENTIFIER
* AttributeValue ::= ANY
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* Name ::= CHOICE { -- only one possibility for now --
* rdnSequence RDNSequence }
*
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
*
* DistinguishedName ::= RDNSequence
*
* RelativeDistinguishedName ::=
* SET SIZE (1 .. MAX) OF AttributeTypeAndValue
*
*/
name->numberOfRDNs = 0;
/* Get the beginning of the RDN Set and a ptr to the end */
if (tag != BER_CONSTRUCTED_SET) {
goto cleanup;
}
/* Walk through the individual SET items until the "end" is reached */
/*
* Clear the RDN record before each pass because
* it gets reused.
*/
/* Skip over the SET tag */
break;
}
/* An "empty" set member means we tack on an empty node */
if (size == 0) {
goto cleanup;
continue;
}
/*
* There may be more than one sequence in the set.
*/
/* Skip over the SET tag */
goto cleanup;
}
goto cleanup;
}
if (!(VALID_DIRECTORYSTRING_TAG(tag))) {
goto cleanup;
}
goto cleanup;
}
/* Clear the AV pair record before using it */
goto cleanup;
}
}
/* Close the set processing */
goto cleanup;
}
}
}
return (ret);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
return (KMF_OK);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
return (KMF_OK);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_CERT_FORMAT);
return (ret);
}
static KMF_RETURN
{
int i;
for (i = 0; i < extns->numberOfExtensions; i++) {
BerValue v;
goto cleanup;
}
goto cleanup;
}
}
goto cleanup;
}
}
return (ret);
}
static KMF_RETURN
{
extn = kmfder_alloc();
return (KMF_ERR_MEMORY);
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
return (ret);
}
static KMF_RETURN
{
goto cleanup;
}
if (tag != BER_OBJECT_IDENTIFIER) {
goto cleanup;
}
goto cleanup;
}
if (tag != BER_BOOLEAN) {
critical = 0;
if (tag != BER_OCTET_STRING)
goto cleanup;
} else {
goto cleanup;
}
if (tag != BER_OCTET_STRING) {
goto cleanup;
}
goto cleanup;
}
/* allocate a new Extension record */
goto cleanup;
}
/* Tag and value is a little tricky */
goto cleanup;
}
sizeof (KMF_X509EXT_TAGandVALUE));
/* Parse the Extension value field */
goto cleanup;
}
/* Get the tag and length of the extension field */
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
}
return (ret);
}
static KMF_RETURN
{
/*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
*
* Extension ::= SEQUENCE {
* extnID OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING }
*
* { {{D}Bo}, ... }
*/
return (KMF_ERR_BAD_CERT_FORMAT);
goto cleanup;
sizeof (KMF_X509_EXTENSION));
break;
}
}
return (ret);
}
{
goto cleanup;
}
/* Version number is optional */
if (tag == 0xA0) {
goto cleanup;
}
} else {
version = 0; /* DEFAULT v1 (0) */
}
/* Now get the serial number, it is not optional */
goto cleanup;
} else {
}
if (!tbscert) {
goto cleanup;
}
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
/* Check for the optional fields */
char *optfield;
/* consume the tag and length */
switch (tag) {
case 0xA1:
goto cleanup;
}
len / 8;
break;
case 0xA2:
goto cleanup;
}
len / 8;
break;
case 0xA3:
break;
}
}
}
if (tbscert) {
}
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
goto cleanup;
if (newcert)
}
return (ret);
}
/*
* Name: DerDecodeSignedCertificate
*
* Description:
* DER decodes the encoded X509 certificate
*
* Parameters:
* Value (input): DER encoded object that shd be decoded
*
* signed_cert_ptr_ptr (output) : Decoded KMF_X509_CERTIFICATE object
*/
{
char *signature;
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
goto cleanup;
}
goto cleanup;
}
goto cleanup;
/*
* The signature data my not be present yet.
*/
/* Check to see if the cert has a signature yet */
/* Finally, get the encrypted signature BITSTRING */
goto cleanup;
}
if (tag != BER_BIT_STRING) {
goto cleanup;
}
goto cleanup;
}
} else {
}
} else {
}
if (certptr) {
}
}
if (asn1)
return (ret);
}
{
return (KMF_ERR_MEMORY);
}
}
return (ret);
}
{
return (KMF_ERR_MEMORY);
goto cleanup;
if (asn1)
return (ret);
}
{
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
goto cleanup;
goto cleanup;
}
if (bv)
if (asn1)
return (ret);
}
static KMF_RETURN
{
/* version should be 4 bytes or less */
return (KMF_ERR_BAD_CERT_FORMAT);
/* Start the sequence and add the version */
goto cleanup;
}
/* Write the serial number */
goto cleanup;
}
/* Don't encode alg parameters in signature algid area */
goto cleanup;
/* Encode the Issuer RDN */
goto cleanup;
/* Encode the Validity fields */
goto cleanup;
/* Encode the Subject RDN */
goto cleanup;
/* Encode the Subject Public Key Info */
goto cleanup;
/* Optional field: issuer Unique ID */
goto cleanup;
}
/* Optional field: Subject Unique ID */
goto cleanup;
}
/* Optional field: Certificate Extensions */
goto cleanup;
}
/* Close out the TBSCert sequence */
goto cleanup;
}
/*
* Memory cleanup is done in the caller or in the individual
* encoding routines.
*/
return (ret);
}
{
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
enc_tbs_cert_ptr->Length = 0;
goto cleanup;
goto cleanup;
}
if (tbsdata)
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
encodedcert->Length = 0;
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
/* Start outer X509 Certificate SEQUENCE */
goto cleanup;
}
goto cleanup;
}
/* Add the Algorithm & Signature Sequence (no parameters) */
goto cleanup;
goto cleanup;
}
}
goto cleanup;
}
goto cleanup;
}
if (tbsdata)
if (asn1)
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
/* Skip over the overall Sequence tag to get at the TBS Cert data */
goto cleanup;
}
if (tag != BER_CONSTRUCTED_SEQUENCE) {
goto cleanup;
}
/*
* Since we are extracting a copy of the ENCODED bytes, we
* must make sure to also include the bytes for the tag and
* the length fields for the CONSTRUCTED SEQUENCE (TBSCert).
*/
goto cleanup;
}
/* The der data ptr is now set to the start of the TBS cert sequence */
goto cleanup;
}
goto cleanup;
goto cleanup;
}
/* Now get the signature data */
goto cleanup;
}
/* convert bitstring length to bytes */
}
if (der)
return (ret);
}
static KMF_RETURN
{
return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE);
}
/* We only understand extension requests in a CSR */
return (KMF_ERR_UNKNOWN_CSR_ATTRIBUTE);
}
return (KMF_ERR_ENCODING);
}
return (ret);
}
static KMF_RETURN
{
/* Now get the version number, it is not optional */
goto cleanup;
}
if (!tbscsr) {
goto cleanup;
}
goto cleanup;
goto cleanup;
goto cleanup;
/* Check for the optional fields (attributes) */
goto cleanup;
}
}
if (tbscsr) {
}
}
return (ret);
}
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
goto cleanup;
if (newcsr)
}
return (ret);
}
{
int tag;
char *signature;
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
goto cleanup;
}
goto cleanup;
}
goto cleanup;
goto cleanup;
/* Check to see if the cert has a signature yet */
/* Finally, get the encrypted signature BITSTRING */
goto cleanup;
}
if (tag != BER_BIT_STRING) {
goto cleanup;
}
goto cleanup;
}
} else {
}
if (csrptr)
}
if (asn1)
return (ret);
}
static KMF_RETURN
{
int attlen = 0;
/* Optional field: CSR attributes and extensions */
goto cleanup;
}
} else {
/* No extensions or attributes to encode */
return (KMF_OK);
}
/*
* attributes [0] Attributes
* Attributes := SET OF Attribute
* Attribute := SEQUENCE {
* { ATTRIBUTE ID
* values SET SIZE(1..MAX) of ATTRIBUTE
* }
*
* Ex: { ExtensionRequest OID [ { {extn1 } , {extn2 } } ] }
*/
/*
* Encode any extensions and add to the attributes section.
*/
extnasn1 = kmfder_alloc();
goto cleanup;
}
&extension_request_oid) == -1) {
goto cleanup_1;
}
goto cleanup_1;
}
goto cleanup_1;
}
goto cleanup_1;
}
/* Add 2 bytes to cover the tag and the length */
}
goto cleanup;
goto cleanup;
}
/* Write the actual encoded extensions */
goto cleanup;
}
}
/*
* Memory cleanup is done in the caller or in the individual
* encoding routines.
*/
if (extnvalue) {
}
return (ret);
}
static KMF_RETURN
{
/* Start the version */
goto cleanup;
}
/* Encode the Subject RDN */
goto cleanup;
/* Encode the Subject Public Key Info */
goto cleanup;
goto cleanup;
/* Close out the TBSCert sequence */
goto cleanup;
}
return (ret);
}
{
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
rv = KMF_ERR_MEMORY;
goto cleanup;
}
rv = KMF_ERR_MEMORY;
goto cleanup;
}
return (rv);
}
{
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
&ver, 1,
goto cleanup;
rv = KMF_ERR_MEMORY;
goto cleanup;
}
return (rv);
}
{
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
goto cleanup;
}
/*
* Indicate that we are using the named curve option
* for the parameters.
*/
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
rv = KMF_ERR_MEMORY;
goto cleanup;
}
return (rv);
}
{
asn1 = kmfder_alloc();
enc_tbs_csr_ptr->Length = 0;
return (KMF_ERR_MEMORY);
goto cleanup;
goto cleanup;
}
if (tbsdata)
return (ret);
}
{
if (signed_csr_ptr == NULL)
return (KMF_ERR_BAD_PARAMETER);
asn1 = kmfder_alloc();
return (KMF_ERR_MEMORY);
/* Start outer CSR SEQUENCE */
goto cleanup;
}
/* Add the Algorithm & Signature Sequence */
goto cleanup;
goto cleanup;
}
}
goto cleanup;
}
goto cleanup;
}
}
if (tbsdata)
if (asn1)
return (ret);
}
static KMF_RETURN
{
return (KMF_ERR_BAD_PARAMETER);
return (KMF_ERR_MEMORY);
return (ret);
}
const KMF_X509_SPKI *pKey,
{
return (KMF_ERR_BAD_PARAMETER);
switch (AlgorithmId) {
case KMF_ALGID_DSA:
case KMF_ALGID_SHA1WithDSA:
*uNumKeyParts = 0;
/* Get the parameters from the algorithm definition */
return (KMF_ERR_MEMORY);
return (KMF_ERR_BAD_KEY_FORMAT);
}
free(P);
free(Q);
free(G);
/* Get the PubKey data */
goto cleanup;
}
goto cleanup;
}
break;
case KMF_ALGID_SHA1WithECDSA:
case KMF_ALGID_ECDSA:
*uNumKeyParts = 2;
break;
case KMF_ALGID_RSA:
case KMF_ALGID_MD2WithRSA:
case KMF_ALGID_MD5WithRSA:
case KMF_ALGID_SHA1WithRSA:
*uNumKeyParts = 0;
goto cleanup;
}
goto cleanup;
}
break;
default:
return (KMF_ERR_BAD_PARAMETER);
}
int i;
for (i = 0; i < *uNumKeyParts; i++)
}
}
return (ret);
}