You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/util-decode-der.c

1077 lines
30 KiB
C

/*
* Copyright (C) 2011-2015 ANSSI
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* \author Pierre Chifflier <pierre.chifflier@ssi.gouv.fr>
*
*/
/*
* An ASN.1 Parser for DER-encoded structures.
* This parser is not written to be complete or fast, but is rather
* focused on stability and security.
* It does not support all ASN.1 structure, only a meaningful subset
* to decode x509v3 certificates (See RFC 3280).
*
* References (like 8.19.4) are relative to the ISO/IEC 8825-1:2003 document
*
*/
#include "suricata-common.h"
#include "util-decode-der.h"
#include "util-validate.h"
#define MAX_OID_LENGTH 256
static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerGeneralizedTime(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
int seq_index, uint32_t *errcode) __attribute__((nonnull));
static Asn1Generic * Asn1GenericNew(void)
{
Asn1Generic *obj;
obj = SCMalloc(sizeof(Asn1Generic));
if (obj != NULL)
memset(obj, 0, sizeof(Asn1Generic));
return obj;
}
/**
* \retval r 0 ok, -1 error
*/
static int Asn1SequenceAppend(Asn1Generic *seq, Asn1Generic *node)
{
Asn1Generic *it, *new_container;
if (seq->data == NULL) {
seq->data = node;
return 0;
}
new_container = Asn1GenericNew();
if (new_container == NULL)
return -1;
new_container->data = node;
for (it=seq; it->next != NULL; it=it->next)
;
it->next = new_container;
return 0;
}
static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
int seq_index, uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t numbytes, el_max_size;
Asn1ElementType el;
uint8_t c;
uint32_t i;
Asn1Generic *child;
uint8_t el_type;
/* refuse excessive recursion */
if (unlikely(depth == 255)) {
*errcode = ERR_DER_RECURSION_LIMIT;
return NULL;
}
if (max_size < 2) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
el.cls = (d_ptr[0] & 0xc0) >> 6;
el.pc = (d_ptr[0] & 0x20) >> 5;
el.tag = (d_ptr[0] & 0x1f);
el_type = el.tag;
if (el.tag == 0x1f) {
*errcode = ERR_DER_INVALID_TAG;
return NULL;
}
switch (el.cls) {
case ASN1_CLASS_CONTEXTSPEC:
/* get element type from definition, see:
http://www.ietf.org/rfc/rfc3280.txt */
if (depth == 2 && el.tag == 0) {
/* TBSCertificate */
el_type = ASN1_SEQUENCE;
break;
}
if (depth == 2 && el.tag == 1) {
/* issuerUniqueID */
el_type = ASN1_BITSTRING;
break;
}
if (depth == 2 && el.tag == 2) {
/* subjectUniqueID */
el_type = ASN1_BITSTRING;
break;
}
if (depth == 2 && el.tag == 3) {
/* extensions */
el_type = ASN1_SEQUENCE;
break;
}
/* unknown context specific value - do not decode */
break;
};
el_max_size = max_size - (d_ptr-buffer);
switch (el_type) {
case ASN1_INTEGER:
child = DecodeAsn1DerInteger(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_BOOLEAN:
child = DecodeAsn1DerBoolean(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_NULL:
child = DecodeAsn1DerNull(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_BITSTRING:
child = DecodeAsn1DerBitstring(d_ptr, el_max_size, depth+1,
errcode);
break;
case ASN1_OID:
child = DecodeAsn1DerOid(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_IA5STRING:
child = DecodeAsn1DerIA5String(d_ptr, el_max_size, depth+1,
errcode);
break;
case ASN1_OCTETSTRING:
child = DecodeAsn1DerOctetString(d_ptr, el_max_size, depth+1,
errcode);
break;
case ASN1_UTF8STRING:
child = DecodeAsn1DerUTF8String(d_ptr, el_max_size, depth+1,
errcode);
break;
case ASN1_PRINTSTRING:
child = DecodeAsn1DerPrintableString(d_ptr, el_max_size, depth+1,
errcode);
break;
case ASN1_SEQUENCE:
child = DecodeAsn1DerSequence(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_SET:
child = DecodeAsn1DerSet(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_T61STRING:
child = DecodeAsn1DerT61String(d_ptr, el_max_size, depth+1,
errcode);
break;
case ASN1_UTCTIME:
child = DecodeAsn1DerUTCTime(d_ptr, el_max_size, depth+1, errcode);
break;
case ASN1_GENERALIZEDTIME:
child = DecodeAsn1DerGeneralizedTime(d_ptr, el_max_size, depth+1, errcode);
break;
default:
/* unknown ASN.1 type */
child = NULL;
child = Asn1GenericNew();
if (child == NULL)
break;
child->type = el.tag;
/* total sequence length */
const unsigned char * save_d_ptr = d_ptr;
d_ptr++;
el_max_size--;
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
child->length = c;
d_ptr++;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
if (2 + numbytes > el_max_size) {
SCFree(child);
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
return NULL;
}
child->length = 0;
d_ptr++;
for (i=0; i<numbytes; i++) {
child->length = child->length<<8 | d_ptr[0];
d_ptr++;
}
}
/* fix the length for unknown objects, else sequence parsing
will fail */
child->length += (d_ptr - save_d_ptr);
if (child->length > max_size - (d_ptr - buffer)) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
SCFree(child);
return NULL;
}
break;
};
if (child == NULL) {
if (*errcode == 0)
*errcode = ERR_DER_INVALID_OBJECT;
return NULL;
}
/* child length should never be zero */
if (child->length == 0) {
*errcode = ERR_DER_INVALID_OBJECT;
SCFree(child);
return NULL;
}
child->header = el;
return child;
}
static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint8_t numbytes;
uint32_t value;
uint32_t i;
Asn1Generic *a;
numbytes = d_ptr[1];
if ((uint32_t)(numbytes + 2) > size) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
return NULL;
}
d_ptr += 2;
value = 0;
/* Here we need to ensure that numbytes is less than 4
so integer affectation is possible. We set the value
to 0xffffffff which is by convention the unknown value.
In this case, the hexadecimal value must be used. */
if (numbytes > 4) {
value = 0xffffffff;
} else {
for (i=0; i<numbytes; i++) {
value = value<<8 | d_ptr[i];
}
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_INTEGER;
a->length = (d_ptr - buffer) + numbytes;
a->value = value;
a->str = SCMalloc(2*numbytes + 1);
if (a->str == NULL) {
*errcode = ERR_DER_GENERIC;
SCFree(a);
return NULL;
}
for (i=0; i<numbytes; i++) {
snprintf(a->str + 2*i, 2*(numbytes-i)+1, "%02X", d_ptr[i]);
}
a->str[2*numbytes]= '\0';
return a;
}
static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val,
uint8_t numbytes, uint32_t *errcode)
{
int i;
uint32_t value = 0;
if (numbytes > 4) {
*errcode = ERR_DER_INVALID_SIZE;
/* too big won't fit: set it to 0xffffffff by convention */
value = 0xffffffff;
*val = value;
return -1;
} else {
for (i=0; i<numbytes; i++) {
value = value<<8 | (*d_ptr)[0];
(*d_ptr)++;
}
}
*val = value;
return 0;
}
static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint8_t numbytes;
uint32_t value;
Asn1Generic *a;
numbytes = d_ptr[1];
if ((uint32_t)(numbytes + 2) > size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
d_ptr += 2;
if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) {
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_BOOLEAN;
a->length = (d_ptr - buffer);
a->value = value;
return a;
}
static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer,
uint32_t size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint8_t numbytes;
uint32_t value;
Asn1Generic *a;
numbytes = d_ptr[1];
if ((uint32_t)(numbytes + 2) > size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
d_ptr += 2;
if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) {
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_NULL;
a->length = (d_ptr - buffer);
a->value = 0;
return a;
}
static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t length;
uint8_t numbytes, c;
Asn1Generic *a;
d_ptr++;
/* size */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
length = c;
d_ptr++;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
if ((uint32_t)(numbytes + 2) > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
d_ptr++;
if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) {
return NULL;
}
}
if ((d_ptr-buffer) + length > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_BITSTRING;
a->strlen = length;
a->str = SCMalloc(length);
if (a->str == NULL) {
*errcode = ERR_DER_GENERIC;
SCFree(a);
return NULL;
}
memcpy(a->str, (const char*)d_ptr, length);
d_ptr += length;
a->length = (d_ptr - buffer);
return a;
}
static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t oid_length, oid_value;
uint8_t numbytes, c;
Asn1Generic *a;
uint32_t i;
d_ptr++;
/* size */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
oid_length = c;
d_ptr++;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
if ((uint32_t)(numbytes + 2) > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
d_ptr++;
if (DecodeAsn1BuildValue(&d_ptr, &oid_length, numbytes, errcode) == -1) {
return NULL;
}
}
if (oid_length == 0 || (d_ptr-buffer) + oid_length > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_OID;
a->str = SCMalloc(MAX_OID_LENGTH);
if (a->str == NULL) {
*errcode = ERR_DER_GENERIC;
SCFree(a);
return NULL;
}
/* first element = X*40 + Y (See 8.19.4) */
snprintf(a->str, MAX_OID_LENGTH, "%d.%d", (d_ptr[0]/40), (d_ptr[0]%40));
d_ptr++;
if (oid_length + (d_ptr-buffer) > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
SCFree(a->str);
SCFree(a);
return NULL;
}
/* sub-identifiers are multi-valued, coded and 7 bits, first bit of
the 8bits is used to indicate, if a new value is starting */
for (i=1; i<oid_length; ) {
int s = strlen(a->str);
c = d_ptr[0];
oid_value = 0;
while ( i<oid_length && (c & (1<<7)) == 1<<7 ) {
oid_value = oid_value<<7 | (c & ~(1<<7));
d_ptr++;
c = d_ptr[0];
i++;
}
oid_value = oid_value<<7 | c;
d_ptr++;
i++;
snprintf(a->str + s, MAX_OID_LENGTH - s, ".%d", oid_value);
}
a->length = (d_ptr - buffer);
return a;
}
static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t length, numbytes;
Asn1Generic *a;
unsigned char c;
d_ptr++;
max_size--;
/* total sequence length */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
length = c;
d_ptr++;
max_size--;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
if (max_size < 1 + numbytes) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
max_size -= 1 + numbytes;
d_ptr++;
if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) {
return NULL;
}
}
if (length == UINT32_MAX || (d_ptr-buffer) + length > max_size) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_IA5STRING;
a->strlen = length;
a->str = SCMalloc(length+1);
if (a->str == NULL) {
*errcode = ERR_DER_GENERIC;
SCFree(a);
return NULL;
}
memcpy(a->str, (const char*)d_ptr, length);
a->str[length] = 0;
d_ptr += length;
a->length = (d_ptr - buffer);
return a;
}
static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t length, numbytes;
Asn1Generic *a;
unsigned char c;
d_ptr++;
max_size--;
/* total sequence length */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
length = c;
d_ptr++;
max_size--;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
if (max_size < 1 + numbytes) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
max_size -= 1 + numbytes;
d_ptr++;
if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) {
return NULL;
}
}
if (length == UINT32_MAX || (d_ptr-buffer) + length > max_size) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_OCTETSTRING;
a->strlen = length;
/* add one to the octet string for the 0. This will then allow us to
use the string in printf */
a->str = SCMalloc(length + 1);
if (a->str == NULL) {
*errcode = ERR_DER_GENERIC;
SCFree(a);
return NULL;
}
memcpy(a->str, (const char*)d_ptr, length);
a->str[length] = 0;
d_ptr += length;
a->length = (d_ptr - buffer);
return a;
}
static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
Asn1Generic *a = DecodeAsn1DerOctetString(buffer, max_size, depth, errcode);
if (a != NULL)
a->type = ASN1_UTF8STRING;
return a;
}
static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer,
uint32_t max_size,
uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t length, numbytes;
Asn1Generic *a;
unsigned char c;
d_ptr++;
/* total sequence length */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
length = c;
d_ptr++;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
d_ptr++;
if (2 + numbytes > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) {
return NULL;
}
}
if (length == UINT32_MAX || (d_ptr-buffer) + length > max_size) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
return NULL;
}
a = Asn1GenericNew();
if (a == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
a->type = ASN1_PRINTSTRING;
a->strlen = length;
a->str = SCMalloc(length+1);
if (a->str == NULL) {
*errcode = ERR_DER_GENERIC;
SCFree(a);
return NULL;
}
memcpy(a->str, (const char*)d_ptr, length);
a->str[length] = 0;
d_ptr += length;
a->length = (d_ptr - buffer);
return a;
}
static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t d_length, parsed_bytes, numbytes, el_max_size;
uint8_t c;
uint32_t seq_index;
Asn1Generic *node;
d_ptr++;
node = Asn1GenericNew();
if (node == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
node->type = ASN1_SEQUENCE;
/* total sequence length */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
d_length = c;
d_ptr++;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
d_ptr++;
if ( 2 + numbytes > max_size ) {
*errcode = ERR_DER_INVALID_SIZE;
SCFree(node);
return NULL;
}
if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) {
SCFree(node);
return NULL;
}
}
node->length = d_length + (d_ptr - buffer);
if (node->length > max_size || node->length < d_length /* wrap */) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
SCFree(node);
return NULL;
}
parsed_bytes = 0;
seq_index = 0;
/* decode child elements */
while (parsed_bytes < d_length) {
el_max_size = max_size - (d_ptr-buffer);
Asn1Generic *child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth,
seq_index, errcode);
if (child == NULL) {
if (*errcode != 0) {
DerFree(node);
return NULL;
}
break;
}
int ret = Asn1SequenceAppend(node, child);
if (ret == -1) {
DerFree(child);
break;
}
parsed_bytes += child->length;
d_ptr += child->length;
seq_index++;
}
return (Asn1Generic *)node;
}
static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t d_length, numbytes, el_max_size;
uint8_t c;
uint32_t seq_index;
Asn1Generic *node;
Asn1Generic *child;
d_ptr++;
node = Asn1GenericNew();
if (node == NULL) {
*errcode = ERR_DER_GENERIC;
return NULL;
}
node->type = ASN1_SET;
node->data = NULL;
/* total sequence length */
c = d_ptr[0];
/* short form 8.1.3.4 */
if ((c & (1<<7))>>7 == 0) {
d_length = c;
d_ptr++;
/* long form 8.1.3.5 */
} else {
numbytes = c & 0x7f;
if (2 + numbytes > max_size) {
*errcode = ERR_DER_INVALID_SIZE;
SCFree(node);
return NULL;
}
d_ptr++;
if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) {
SCFree(node);
return NULL;
}
}
node->length = d_length + (d_ptr - buffer);
if (node->length > max_size || node->length < d_length /* wrap */) {
*errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG;
SCFree(node);
return NULL;
}
seq_index = 0;
el_max_size = max_size - (d_ptr-buffer);
child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode);
if (child == NULL) {
DerFree(node);
return NULL;
}
node->data = child;
return (Asn1Generic *)node;
}
static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
Asn1Generic *a;
a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode);
if (a != NULL)
a->type = ASN1_T61STRING;
return a;
}
static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer,
uint32_t max_size, uint8_t depth,
uint32_t *errcode)
{
Asn1Generic *a;
a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode);
if (a != NULL)
a->type = ASN1_UTCTIME;
return a;
}
static Asn1Generic * DecodeAsn1DerGeneralizedTime(const unsigned char *buffer,
uint32_t max_size,
uint8_t depth,
uint32_t *errcode)
{
Asn1Generic *a;
a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode);
if (a != NULL)
a->type = ASN1_GENERALIZEDTIME;
return a;
}
/**
* \param errcode pointer to error code variable. May not be NULL.
*/
Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size,
uint32_t *errcode)
{
const unsigned char *d_ptr = buffer;
uint32_t d_length, numbytes;
Asn1Generic *cert;
uint8_t c;
DEBUG_VALIDATE_BUG_ON(errcode == NULL);
*errcode = 0;
if (size < 2) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
/* check that buffer is an ASN.1 structure (basic checks) */
if (d_ptr[0] != 0x30 && d_ptr[1] != 0x82) { /* Sequence */
*errcode = ERR_DER_UNKNOWN_ELEMENT;
return NULL;
}
c = d_ptr[1];
if ((c & (1<<7))>>7 != 1) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
numbytes = c & 0x7f;
d_ptr += 2;
if (size < numbytes + 2) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) {
return NULL;
}
if (d_length+(d_ptr-buffer) != size) {
*errcode = ERR_DER_INVALID_SIZE;
return NULL;
}
cert = DecodeAsn1DerGeneric(buffer, size, 0 /* depth */, 0, errcode);
return cert;
}
#ifdef AFLFUZZ_DER
int DerParseDataFromFile(char *filename)
{
uint8_t buffer[65536];
uint32_t errcode = 0;
#ifdef AFLFUZZ_PERSISTANT_MODE
while (__AFL_LOOP(1000)) {
/* reset state */
memset(buffer, 0, sizeof(buffer));
#endif /* AFLFUZZ_PERSISTANT_MODE */
FILE *fp = fopen(filename, "r");
BUG_ON(fp == NULL);
size_t result = fread(&buffer, 1, sizeof(buffer), fp);
Asn1Generic *a = DecodeDer(buffer, result, &errcode);
DerFree(a);
fclose(fp);
#ifdef AFLFUZZ_PERSISTANT_MODE
}
#endif /* AFLFUZZ_PERSISTANT_MODE */
return 0;
}
#endif /* AFLFUZZ_DER */
void DerFree(Asn1Generic *a)
{
Asn1Generic *it, *n;
if (a == NULL)
return;
it = a;
while (it) {
n = it->next;
if (it->data) {
DerFree(it->data);
}
if (it->str)
SCFree(it->str);
memset(it, 0xff, sizeof(Asn1Generic));
SCFree(it);
it = n;
}
}