/* * 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 * */ /* * 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; ilength = 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; itype = 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; istr + 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 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; istr); c = d_ptr[0]; oid_value = 0; while ( istr + 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; } }