| // Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     https://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | #include <openssl/x509.h> | 
 |  | 
 | #include <assert.h> | 
 | #include <ctype.h> | 
 | #include <limits.h> | 
 | #include <string.h> | 
 |  | 
 | #include <openssl/asn1.h> | 
 | #include <openssl/bytestring.h> | 
 | #include <openssl/err.h> | 
 | #include <openssl/obj.h> | 
 |  | 
 | #include "../conf/internal.h" | 
 | #include "../internal.h" | 
 | #include "internal.h" | 
 |  | 
 |  | 
 | // Although this file is in crypto/x509 for layering purposes, it emits | 
 | // errors from the ASN.1 module for OpenSSL compatibility. | 
 |  | 
 | // ASN1_GEN_MAX_DEPTH is the maximum number of nested TLVs allowed. | 
 | #define ASN1_GEN_MAX_DEPTH 50 | 
 |  | 
 | // ASN1_GEN_MAX_OUTPUT is the maximum output, in bytes, allowed. This limit is | 
 | // necessary because the SEQUENCE and SET section reference mechanism allows the | 
 | // output length to grow super-linearly with the input length. | 
 | #define ASN1_GEN_MAX_OUTPUT (64 * 1024) | 
 |  | 
 | // ASN1_GEN_FORMAT_* are the values for the format modifiers. | 
 | #define ASN1_GEN_FORMAT_ASCII 1 | 
 | #define ASN1_GEN_FORMAT_UTF8 2 | 
 | #define ASN1_GEN_FORMAT_HEX 3 | 
 | #define ASN1_GEN_FORMAT_BITLIST 4 | 
 |  | 
 | // generate_v3 converts |str| into an ASN.1 structure and writes the result to | 
 | // |cbb|. It returns one on success and zero on error. |depth| bounds recursion, | 
 | // and |format| specifies the current format modifier. | 
 | // | 
 | // If |tag| is non-zero, the structure is implicitly tagged with |tag|. |tag| | 
 | // must not have the constructed bit set. | 
 | static int generate_v3(CBB *cbb, const char *str, const X509V3_CTX *cnf, | 
 |                        CBS_ASN1_TAG tag, int format, int depth); | 
 |  | 
 | static int bitstr_cb(const char *elem, size_t len, void *bitstr); | 
 |  | 
 | ASN1_TYPE *ASN1_generate_v3(const char *str, const X509V3_CTX *cnf) { | 
 |   bssl::ScopedCBB cbb; | 
 |   if (!CBB_init(cbb.get(), 0) ||  // | 
 |       !generate_v3(cbb.get(), str, cnf, /*tag=*/0, ASN1_GEN_FORMAT_ASCII, | 
 |                    /*depth=*/0)) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // While not strictly necessary to avoid a DoS (we rely on any super-linear | 
 |   // checks being performed internally), cap the overall output to | 
 |   // |ASN1_GEN_MAX_OUTPUT| so the externally-visible behavior is consistent. | 
 |   if (CBB_len(cbb.get()) > ASN1_GEN_MAX_OUTPUT) { | 
 |     OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   const uint8_t *der = CBB_data(cbb.get()); | 
 |   return d2i_ASN1_TYPE(nullptr, &der, CBB_len(cbb.get())); | 
 | } | 
 |  | 
 | static int cbs_str_equal(const CBS *cbs, const char *str) { | 
 |   return CBS_len(cbs) == strlen(str) && | 
 |          OPENSSL_memcmp(CBS_data(cbs), str, strlen(str)) == 0; | 
 | } | 
 |  | 
 | // parse_tag decodes a tag specifier in |cbs|. It returns the tag on success or | 
 | // zero on error. | 
 | static CBS_ASN1_TAG parse_tag(const CBS *cbs) { | 
 |   CBS copy = *cbs; | 
 |   uint64_t num; | 
 |   if (!CBS_get_u64_decimal(©, &num) || num > CBS_ASN1_TAG_NUMBER_MASK) { | 
 |     OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); | 
 |     return 0; | 
 |   } | 
 |  | 
 |   CBS_ASN1_TAG tag_class = CBS_ASN1_CONTEXT_SPECIFIC; | 
 |   // The tag may be suffixed by a class. | 
 |   uint8_t c; | 
 |   if (CBS_get_u8(©, &c)) { | 
 |     switch (c) { | 
 |       case 'U': | 
 |         tag_class = CBS_ASN1_UNIVERSAL; | 
 |         break; | 
 |       case 'A': | 
 |         tag_class = CBS_ASN1_APPLICATION; | 
 |         break; | 
 |       case 'P': | 
 |         tag_class = CBS_ASN1_PRIVATE; | 
 |         break; | 
 |       case 'C': | 
 |         tag_class = CBS_ASN1_CONTEXT_SPECIFIC; | 
 |         break; | 
 |       default: { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_MODIFIER); | 
 |         return 0; | 
 |       } | 
 |     } | 
 |     if (CBS_len(©) != 0) { | 
 |       OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_MODIFIER); | 
 |       return 0; | 
 |     } | 
 |   } | 
 |  | 
 |   // Tag [UNIVERSAL 0] is reserved for indefinite-length end-of-contents. We | 
 |   // also use zero in this file to indicator no explicit tagging. | 
 |   if (tag_class == CBS_ASN1_UNIVERSAL && num == 0) { | 
 |     OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); | 
 |     return 0; | 
 |   } | 
 |  | 
 |   return tag_class | (CBS_ASN1_TAG)num; | 
 | } | 
 |  | 
 | static int generate_wrapped(CBB *cbb, const char *str, const X509V3_CTX *cnf, | 
 |                             CBS_ASN1_TAG tag, int padding, int format, | 
 |                             int depth) { | 
 |   CBB child; | 
 |   return CBB_add_asn1(cbb, &child, tag) && | 
 |          (!padding || CBB_add_u8(&child, 0)) && | 
 |          generate_v3(&child, str, cnf, /*tag=*/0, format, depth + 1) && | 
 |          CBB_flush(cbb); | 
 | } | 
 |  | 
 | static int generate_v3(CBB *cbb, const char *str, const X509V3_CTX *cnf, | 
 |                        CBS_ASN1_TAG tag, int format, int depth) { | 
 |   assert((tag & CBS_ASN1_CONSTRUCTED) == 0); | 
 |   if (depth > ASN1_GEN_MAX_DEPTH) { | 
 |     OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING); | 
 |     return 0; | 
 |   } | 
 |  | 
 |   // Process modifiers. This function uses a mix of NUL-terminated strings and | 
 |   // |CBS|. Several functions only work with NUL-terminated strings, so we need | 
 |   // to keep track of when a slice spans the whole buffer. | 
 |   for (;;) { | 
 |     // Skip whitespace. | 
 |     while (*str != '\0' && OPENSSL_isspace((unsigned char)*str)) { | 
 |       str++; | 
 |     } | 
 |  | 
 |     // Modifiers end at commas. | 
 |     const char *comma = strchr(str, ','); | 
 |     if (comma == nullptr) { | 
 |       break; | 
 |     } | 
 |  | 
 |     // Remove trailing whitespace. | 
 |     CBS modifier; | 
 |     CBS_init(&modifier, (const uint8_t *)str, comma - str); | 
 |     for (;;) { | 
 |       uint8_t v; | 
 |       CBS copy = modifier; | 
 |       if (!CBS_get_last_u8(©, &v) || !OPENSSL_isspace(v)) { | 
 |         break; | 
 |       } | 
 |       modifier = copy; | 
 |     } | 
 |  | 
 |     // Advance the string past the modifier, but save the original value. We | 
 |     // will need to rewind if this is not a recognized modifier. | 
 |     const char *str_old = str; | 
 |     str = comma + 1; | 
 |  | 
 |     // Each modifier is either NAME:VALUE or NAME. | 
 |     CBS name; | 
 |     int has_value = CBS_get_until_first(&modifier, &name, ':'); | 
 |     if (has_value) { | 
 |       CBS_skip(&modifier, 1);  // Skip the colon. | 
 |     } else { | 
 |       name = modifier; | 
 |       CBS_init(&modifier, nullptr, 0); | 
 |     } | 
 |  | 
 |     if (cbs_str_equal(&name, "FORMAT") || cbs_str_equal(&name, "FORM")) { | 
 |       if (cbs_str_equal(&modifier, "ASCII")) { | 
 |         format = ASN1_GEN_FORMAT_ASCII; | 
 |       } else if (cbs_str_equal(&modifier, "UTF8")) { | 
 |         format = ASN1_GEN_FORMAT_UTF8; | 
 |       } else if (cbs_str_equal(&modifier, "HEX")) { | 
 |         format = ASN1_GEN_FORMAT_HEX; | 
 |       } else if (cbs_str_equal(&modifier, "BITLIST")) { | 
 |         format = ASN1_GEN_FORMAT_BITLIST; | 
 |       } else { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); | 
 |         return 0; | 
 |       } | 
 |     } else if (cbs_str_equal(&name, "IMP") || | 
 |                cbs_str_equal(&name, "IMPLICIT")) { | 
 |       if (tag != 0) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING); | 
 |         return 0; | 
 |       } | 
 |       tag = parse_tag(&modifier); | 
 |       if (tag == 0) { | 
 |         return 0; | 
 |       } | 
 |     } else if (cbs_str_equal(&name, "EXP") || | 
 |                cbs_str_equal(&name, "EXPLICIT")) { | 
 |       // It would actually be supportable, but OpenSSL does not allow wrapping | 
 |       // an explicit tag in an implicit tag. | 
 |       if (tag != 0) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING); | 
 |         return 0; | 
 |       } | 
 |       tag = parse_tag(&modifier); | 
 |       return tag != 0 && | 
 |              generate_wrapped(cbb, str, cnf, tag | CBS_ASN1_CONSTRUCTED, | 
 |                               /*padding=*/0, format, depth); | 
 |     } else if (cbs_str_equal(&name, "OCTWRAP")) { | 
 |       tag = tag == 0 ? CBS_ASN1_OCTETSTRING : tag; | 
 |       return generate_wrapped(cbb, str, cnf, tag, /*padding=*/0, format, depth); | 
 |     } else if (cbs_str_equal(&name, "BITWRAP")) { | 
 |       tag = tag == 0 ? CBS_ASN1_BITSTRING : tag; | 
 |       return generate_wrapped(cbb, str, cnf, tag, /*padding=*/1, format, depth); | 
 |     } else if (cbs_str_equal(&name, "SEQWRAP")) { | 
 |       tag = tag == 0 ? CBS_ASN1_SEQUENCE : (tag | CBS_ASN1_CONSTRUCTED); | 
 |       tag |= CBS_ASN1_CONSTRUCTED; | 
 |       return generate_wrapped(cbb, str, cnf, tag, /*padding=*/0, format, depth); | 
 |     } else if (cbs_str_equal(&name, "SETWRAP")) { | 
 |       tag = tag == 0 ? CBS_ASN1_SET : (tag | CBS_ASN1_CONSTRUCTED); | 
 |       return generate_wrapped(cbb, str, cnf, tag, /*padding=*/0, format, depth); | 
 |     } else { | 
 |       // If this was not a recognized modifier, rewind |str| to before splitting | 
 |       // on the comma. The type itself consumes all remaining input. | 
 |       str = str_old; | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   // The final element is, like modifiers, NAME:VALUE or NAME, but VALUE spans | 
 |   // the length of the string, including any commas. | 
 |   const char *colon = strchr(str, ':'); | 
 |   CBS name; | 
 |   const char *value; | 
 |   int has_value = colon != nullptr; | 
 |   if (has_value) { | 
 |     CBS_init(&name, (const uint8_t *)str, colon - str); | 
 |     value = colon + 1; | 
 |   } else { | 
 |     CBS_init(&name, (const uint8_t *)str, strlen(str)); | 
 |     value = "";  // Most types treat missing and empty value equivalently. | 
 |   } | 
 |  | 
 |   static const struct { | 
 |     const char *name; | 
 |     CBS_ASN1_TAG type; | 
 |   } kTypes[] = { | 
 |       {"BOOL", CBS_ASN1_BOOLEAN}, | 
 |       {"BOOLEAN", CBS_ASN1_BOOLEAN}, | 
 |       {"NULL", CBS_ASN1_NULL}, | 
 |       {"INT", CBS_ASN1_INTEGER}, | 
 |       {"INTEGER", CBS_ASN1_INTEGER}, | 
 |       {"ENUM", CBS_ASN1_ENUMERATED}, | 
 |       {"ENUMERATED", CBS_ASN1_ENUMERATED}, | 
 |       {"OID", CBS_ASN1_OBJECT}, | 
 |       {"OBJECT", CBS_ASN1_OBJECT}, | 
 |       {"UTCTIME", CBS_ASN1_UTCTIME}, | 
 |       {"UTC", CBS_ASN1_UTCTIME}, | 
 |       {"GENERALIZEDTIME", CBS_ASN1_GENERALIZEDTIME}, | 
 |       {"GENTIME", CBS_ASN1_GENERALIZEDTIME}, | 
 |       {"OCT", CBS_ASN1_OCTETSTRING}, | 
 |       {"OCTETSTRING", CBS_ASN1_OCTETSTRING}, | 
 |       {"BITSTR", CBS_ASN1_BITSTRING}, | 
 |       {"BITSTRING", CBS_ASN1_BITSTRING}, | 
 |       {"UNIVERSALSTRING", CBS_ASN1_UNIVERSALSTRING}, | 
 |       {"UNIV", CBS_ASN1_UNIVERSALSTRING}, | 
 |       {"IA5", CBS_ASN1_IA5STRING}, | 
 |       {"IA5STRING", CBS_ASN1_IA5STRING}, | 
 |       {"UTF8", CBS_ASN1_UTF8STRING}, | 
 |       {"UTF8String", CBS_ASN1_UTF8STRING}, | 
 |       {"BMP", CBS_ASN1_BMPSTRING}, | 
 |       {"BMPSTRING", CBS_ASN1_BMPSTRING}, | 
 |       {"PRINTABLESTRING", CBS_ASN1_PRINTABLESTRING}, | 
 |       {"PRINTABLE", CBS_ASN1_PRINTABLESTRING}, | 
 |       {"T61", CBS_ASN1_T61STRING}, | 
 |       {"T61STRING", CBS_ASN1_T61STRING}, | 
 |       {"TELETEXSTRING", CBS_ASN1_T61STRING}, | 
 |       {"SEQUENCE", CBS_ASN1_SEQUENCE}, | 
 |       {"SEQ", CBS_ASN1_SEQUENCE}, | 
 |       {"SET", CBS_ASN1_SET}, | 
 |   }; | 
 |   CBS_ASN1_TAG type = 0; | 
 |   for (const auto &t : kTypes) { | 
 |     if (cbs_str_equal(&name, t.name)) { | 
 |       type = t.type; | 
 |       break; | 
 |     } | 
 |   } | 
 |   if (type == 0) { | 
 |     OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_TAG); | 
 |     return 0; | 
 |   } | 
 |  | 
 |   // If there is an implicit tag, use the constructed bit from the base type. | 
 |   tag = tag == 0 ? type : (tag | (type & CBS_ASN1_CONSTRUCTED)); | 
 |   CBB child; | 
 |   if (!CBB_add_asn1(cbb, &child, tag)) { | 
 |     return 0; | 
 |   } | 
 |  | 
 |   switch (type) { | 
 |     case CBS_ASN1_NULL: | 
 |       if (*value != '\0') { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL_VALUE); | 
 |         return 0; | 
 |       } | 
 |       return CBB_flush(cbb); | 
 |  | 
 |     case CBS_ASN1_BOOLEAN: { | 
 |       if (format != ASN1_GEN_FORMAT_ASCII) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ASCII_FORMAT); | 
 |         return 0; | 
 |       } | 
 |       ASN1_BOOLEAN boolean; | 
 |       if (!X509V3_bool_from_string(value, &boolean)) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BOOLEAN); | 
 |         return 0; | 
 |       } | 
 |       return CBB_add_u8(&child, boolean ? 0xff : 0x00) && CBB_flush(cbb); | 
 |     } | 
 |  | 
 |     case CBS_ASN1_INTEGER: | 
 |     case CBS_ASN1_ENUMERATED: { | 
 |       if (format != ASN1_GEN_FORMAT_ASCII) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT); | 
 |         return 0; | 
 |       } | 
 |       ASN1_INTEGER *obj = s2i_ASN1_INTEGER(nullptr, value); | 
 |       if (obj == nullptr) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_INTEGER); | 
 |         return 0; | 
 |       } | 
 |       int len = i2c_ASN1_INTEGER(obj, nullptr); | 
 |       uint8_t *out; | 
 |       int ok = len > 0 &&  // | 
 |                CBB_add_space(&child, &out, len) && | 
 |                i2c_ASN1_INTEGER(obj, &out) == len && CBB_flush(cbb); | 
 |       ASN1_INTEGER_free(obj); | 
 |       return ok; | 
 |     } | 
 |  | 
 |     case CBS_ASN1_OBJECT: { | 
 |       if (format != ASN1_GEN_FORMAT_ASCII) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT); | 
 |         return 0; | 
 |       } | 
 |       ASN1_OBJECT *obj = OBJ_txt2obj(value, /*dont_search_names=*/0); | 
 |       if (obj == nullptr || obj->length == 0) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT); | 
 |         return 0; | 
 |       } | 
 |       int ok = CBB_add_bytes(&child, obj->data, obj->length) && CBB_flush(cbb); | 
 |       ASN1_OBJECT_free(obj); | 
 |       return ok; | 
 |     } | 
 |  | 
 |     case CBS_ASN1_UTCTIME: | 
 |     case CBS_ASN1_GENERALIZEDTIME: { | 
 |       if (format != ASN1_GEN_FORMAT_ASCII) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT); | 
 |         return 0; | 
 |       } | 
 |       CBS value_cbs; | 
 |       CBS_init(&value_cbs, (const uint8_t *)value, strlen(value)); | 
 |       int ok = type == CBS_ASN1_UTCTIME | 
 |                    ? CBS_parse_utc_time(&value_cbs, nullptr, | 
 |                                         /*allow_timezone_offset=*/0) | 
 |                    : CBS_parse_generalized_time(&value_cbs, nullptr, | 
 |                                                 /*allow_timezone_offset=*/0); | 
 |       if (!ok) { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TIME_VALUE); | 
 |         return 0; | 
 |       } | 
 |       return CBB_add_bytes(&child, (const uint8_t *)value, strlen(value)) && | 
 |              CBB_flush(cbb); | 
 |     } | 
 |  | 
 |     case CBS_ASN1_UNIVERSALSTRING: | 
 |     case CBS_ASN1_IA5STRING: | 
 |     case CBS_ASN1_UTF8STRING: | 
 |     case CBS_ASN1_BMPSTRING: | 
 |     case CBS_ASN1_PRINTABLESTRING: | 
 |     case CBS_ASN1_T61STRING: { | 
 |       int encoding; | 
 |       if (format == ASN1_GEN_FORMAT_ASCII) { | 
 |         encoding = MBSTRING_ASC; | 
 |       } else if (format == ASN1_GEN_FORMAT_UTF8) { | 
 |         encoding = MBSTRING_UTF8; | 
 |       } else { | 
 |         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_FORMAT); | 
 |         return 0; | 
 |       } | 
 |  | 
 |       // |maxsize| is measured in code points, rather than bytes, but pass it in | 
 |       // as a loose cap so fuzzers can exit from excessively long inputs | 
 |       // earlier. This limit is not load-bearing because |ASN1_mbstring_ncopy|'s | 
 |       // output is already linear in the input. | 
 |       ASN1_STRING *obj = nullptr; | 
 |       if (ASN1_mbstring_ncopy(&obj, (const uint8_t *)value, -1, encoding, | 
 |                               ASN1_tag2bit(type), /*minsize=*/0, | 
 |                               /*maxsize=*/ASN1_GEN_MAX_OUTPUT) <= 0) { | 
 |         return 0; | 
 |       } | 
 |       int ok = CBB_add_bytes(&child, obj->data, obj->length) && CBB_flush(cbb); | 
 |       ASN1_STRING_free(obj); | 
 |       return ok; | 
 |     } | 
 |  | 
 |     case CBS_ASN1_BITSTRING: | 
 |       if (format == ASN1_GEN_FORMAT_BITLIST) { | 
 |         ASN1_BIT_STRING *obj = ASN1_BIT_STRING_new(); | 
 |         if (obj == nullptr) { | 
 |           return 0; | 
 |         } | 
 |         if (!CONF_parse_list(value, ',', 1, bitstr_cb, obj)) { | 
 |           OPENSSL_PUT_ERROR(ASN1, ASN1_R_LIST_ERROR); | 
 |           ASN1_BIT_STRING_free(obj); | 
 |           return 0; | 
 |         } | 
 |         int len = i2c_ASN1_BIT_STRING(obj, nullptr); | 
 |         uint8_t *out; | 
 |         int ok = len > 0 &&  // | 
 |                  CBB_add_space(&child, &out, len) && | 
 |                  i2c_ASN1_BIT_STRING(obj, &out) == len &&  // | 
 |                  CBB_flush(cbb); | 
 |         ASN1_BIT_STRING_free(obj); | 
 |         return ok; | 
 |       } | 
 |  | 
 |       // The other formats are the same as OCTET STRING, but with the leading | 
 |       // zero bytes. | 
 |       if (!CBB_add_u8(&child, 0)) { | 
 |         return 0; | 
 |       } | 
 |       [[fallthrough]]; | 
 |  | 
 |     case CBS_ASN1_OCTETSTRING: | 
 |       if (format == ASN1_GEN_FORMAT_ASCII) { | 
 |         return CBB_add_bytes(&child, (const uint8_t *)value, strlen(value)) && | 
 |                CBB_flush(cbb); | 
 |       } | 
 |       if (format == ASN1_GEN_FORMAT_HEX) { | 
 |         size_t len; | 
 |         uint8_t *data = x509v3_hex_to_bytes(value, &len); | 
 |         if (data == nullptr) { | 
 |           OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_HEX); | 
 |           return 0; | 
 |         } | 
 |         int ok = CBB_add_bytes(&child, data, len) && CBB_flush(cbb); | 
 |         OPENSSL_free(data); | 
 |         return ok; | 
 |       } | 
 |  | 
 |       OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT); | 
 |       return 0; | 
 |  | 
 |     case CBS_ASN1_SEQUENCE: | 
 |     case CBS_ASN1_SET: | 
 |       if (has_value) { | 
 |         if (cnf == nullptr) { | 
 |           OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG); | 
 |           return 0; | 
 |         } | 
 |         const STACK_OF(CONF_VALUE) *section = X509V3_get_section(cnf, value); | 
 |         if (section == nullptr) { | 
 |           OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG); | 
 |           return 0; | 
 |         } | 
 |         for (size_t i = 0; i < sk_CONF_VALUE_num(section); i++) { | 
 |           const CONF_VALUE *conf = sk_CONF_VALUE_value(section, i); | 
 |           if (!generate_v3(&child, conf->value, cnf, /*tag=*/0, | 
 |                            ASN1_GEN_FORMAT_ASCII, depth + 1)) { | 
 |             return 0; | 
 |           } | 
 |           // This recursive call, by referencing |section|, is the one place | 
 |           // where |generate_v3|'s output can be super-linear in the input. | 
 |           // Check bounds here. | 
 |           if (CBB_len(&child) > ASN1_GEN_MAX_OUTPUT) { | 
 |             OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); | 
 |             return 0; | 
 |           } | 
 |         } | 
 |       } | 
 |       if (type == CBS_ASN1_SET) { | 
 |         // The SET type here is a SET OF and must be sorted. | 
 |         return CBB_flush_asn1_set_of(&child) && CBB_flush(cbb); | 
 |       } | 
 |       return CBB_flush(cbb); | 
 |  | 
 |     default: | 
 |       OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR); | 
 |       return 0; | 
 |   } | 
 | } | 
 |  | 
 | static int bitstr_cb(const char *elem, size_t len, void *bitstr) { | 
 |   CBS cbs; | 
 |   CBS_init(&cbs, (const uint8_t *)elem, len); | 
 |   uint64_t bitnum; | 
 |   if (!CBS_get_u64_decimal(&cbs, &bitnum) || CBS_len(&cbs) != 0 || | 
 |       // Cap the highest allowed bit so this mechanism cannot be used to create | 
 |       // extremely large allocations with short inputs. The highest named bit in | 
 |       // RFC 5280 is 8, so 256 should give comfortable margin but still only | 
 |       // allow a 32-byte allocation. | 
 |       // | 
 |       // We do not consider this function to be safe with untrusted inputs (even | 
 |       // without bugs, it is prone to string injection vulnerabilities), so DoS | 
 |       // is not truly a concern, but the limit is necessary to keep fuzzing | 
 |       // effective. | 
 |       bitnum > 256) { | 
 |     OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); | 
 |     return 0; | 
 |   } | 
 |   if (!ASN1_BIT_STRING_set_bit(reinterpret_cast<ASN1_BIT_STRING *>(bitstr), | 
 |                                (int)bitnum, 1)) { | 
 |     return 0; | 
 |   } | 
 |   return 1; | 
 | } |