Packages
hackney
3.0.2
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/asn1/tasn_enc.cc
// Copyright 2000-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/asn1.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <openssl/asn1t.h>
#include <openssl/mem.h>
#include "../internal.h"
#include "internal.h"
static int asn1_item_ex_i2d_opt(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass,
int optional);
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass,
int optional);
static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *out_omit,
int *putype, const ASN1_ITEM *it);
static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
int skcontlen, const ASN1_ITEM *item, int do_sort);
static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
const ASN1_TEMPLATE *tt, int tag, int aclass,
int optional);
// Top level i2d equivalents
int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) {
if (out && !*out) {
unsigned char *p, *buf;
int len = ASN1_item_ex_i2d(&val, nullptr, it, /*tag=*/-1, /*aclass=*/0);
if (len <= 0) {
return len;
}
buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(len));
if (!buf) {
return -1;
}
p = buf;
int len2 = ASN1_item_ex_i2d(&val, &p, it, /*tag=*/-1, /*aclass=*/0);
if (len2 <= 0) {
OPENSSL_free(buf);
return len2;
}
assert(len == len2);
*out = buf;
return len;
}
return ASN1_item_ex_i2d(&val, out, it, /*tag=*/-1, /*aclass=*/0);
}
// Encode an item, taking care of IMPLICIT tagging (if any). This function
// performs the normal item handling: it can be used in external types.
int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass) {
int ret = asn1_item_ex_i2d_opt(pval, out, it, tag, aclass, /*optional=*/0);
assert(ret != 0);
return ret;
}
// asn1_item_ex_i2d_opt behaves like |ASN1_item_ex_i2d| but, if |optional| is
// non-zero and |*pval| is omitted, it returns zero and writes no bytes.
int asn1_item_ex_i2d_opt(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass,
int optional) {
const ASN1_TEMPLATE *tt = nullptr;
int i, seqcontlen, seqlen;
// Historically, |aclass| was repurposed to pass additional flags into the
// encoding process.
assert((aclass & ASN1_TFLG_TAG_CLASS) == aclass);
// If not overriding the tag, |aclass| is ignored and should be zero.
assert(tag != -1 || aclass == 0);
// All fields are pointers, except for boolean |ASN1_ITYPE_PRIMITIVE|s.
// Optional primitives are handled later.
if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) {
if (optional) {
return 0;
}
OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
return -1;
}
switch (it->itype) {
case ASN1_ITYPE_PRIMITIVE:
if (it->templates) {
// This is an |ASN1_ITEM_TEMPLATE|.
if (it->templates->flags & ASN1_TFLG_OPTIONAL) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
return asn1_template_ex_i2d(pval, out, it->templates, tag, aclass,
optional);
}
return asn1_i2d_ex_primitive(pval, out, it, tag, aclass, optional);
case ASN1_ITYPE_MSTRING:
// It never makes sense for multi-strings to have implicit tagging, so
// if tag != -1, then this looks like an error in the template.
if (tag != -1) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
return asn1_i2d_ex_primitive(pval, out, it, -1, 0, optional);
case ASN1_ITYPE_CHOICE: {
// It never makes sense for CHOICE types to have implicit tagging, so if
// tag != -1, then this looks like an error in the template.
if (tag != -1) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
i = asn1_get_choice_selector(pval, it);
if (i < 0 || i >= it->tcount) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE);
return -1;
}
const ASN1_TEMPLATE *chtt = it->templates + i;
if (chtt->flags & ASN1_TFLG_OPTIONAL) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
ASN1_VALUE **pchval = asn1_get_field_ptr(pval, chtt);
return asn1_template_ex_i2d(pchval, out, chtt, -1, 0, /*optional=*/0);
}
case ASN1_ITYPE_EXTERN: {
// We don't support implicit tagging with external types.
if (tag != -1) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
const ASN1_EXTERN_FUNCS *ef =
reinterpret_cast<const ASN1_EXTERN_FUNCS *>(it->funcs);
int ret = ef->asn1_ex_i2d(pval, out, it);
if (ret == 0) {
// |asn1_ex_i2d| should never return zero. We have already checked
// for optional values generically, and |ASN1_ITYPE_EXTERN| fields
// must be pointers.
OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
return -1;
}
return ret;
}
case ASN1_ITYPE_SEQUENCE: {
i = asn1_enc_restore(&seqcontlen, out, pval, it);
// An error occurred
if (i < 0) {
return -1;
}
// We have a valid cached encoding...
if (i > 0) {
return seqcontlen;
}
// Otherwise carry on
seqcontlen = 0;
// If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL
if (tag == -1) {
tag = V_ASN1_SEQUENCE;
aclass = V_ASN1_UNIVERSAL;
}
// First work out sequence content length
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
const ASN1_TEMPLATE *seqtt;
ASN1_VALUE **pseqval;
int tmplen;
seqtt = asn1_do_adb(pval, tt, 1);
if (!seqtt) {
return -1;
}
pseqval = asn1_get_field_ptr(pval, seqtt);
tmplen = asn1_template_ex_i2d(pseqval, nullptr, seqtt, -1, 0,
/*optional=*/0);
if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen)) {
return -1;
}
seqcontlen += tmplen;
}
seqlen = ASN1_object_size(/*constructed=*/1, seqcontlen, tag);
if (!out || seqlen == -1) {
return seqlen;
}
// Output SEQUENCE header
ASN1_put_object(out, /*constructed=*/1, seqcontlen, tag, aclass);
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
const ASN1_TEMPLATE *seqtt;
ASN1_VALUE **pseqval;
seqtt = asn1_do_adb(pval, tt, 1);
if (!seqtt) {
return -1;
}
pseqval = asn1_get_field_ptr(pval, seqtt);
if (asn1_template_ex_i2d(pseqval, out, seqtt, -1, 0, /*optional=*/0) <
0) {
return -1;
}
}
return seqlen;
}
default:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
}
// asn1_template_ex_i2d behaves like |asn1_item_ex_i2d_opt| but uses an
// |ASN1_TEMPLATE| instead of an |ASN1_ITEM|. An |ASN1_TEMPLATE| wraps an
// |ASN1_ITEM| with modifiers such as tagging, SEQUENCE or SET, etc.
static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
const ASN1_TEMPLATE *tt, int tag, int iclass,
int optional) {
int i, ret, ttag, tclass;
size_t j;
uint32_t flags = tt->flags;
// Historically, |iclass| was repurposed to pass additional flags into the
// encoding process.
assert((iclass & ASN1_TFLG_TAG_CLASS) == iclass);
// If not overriding the tag, |iclass| is ignored and should be zero.
assert(tag != -1 || iclass == 0);
// Work out tag and class to use: tagging may come either from the
// template or the arguments, not both because this would create
// ambiguity.
if (flags & ASN1_TFLG_TAG_MASK) {
// Error if argument and template tagging
if (tag != -1) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
// Get tagging from template
ttag = tt->tag;
tclass = flags & ASN1_TFLG_TAG_CLASS;
} else if (tag != -1) {
// No template tagging, get from arguments
ttag = tag;
tclass = iclass & ASN1_TFLG_TAG_CLASS;
} else {
ttag = -1;
tclass = 0;
}
// The template may itself by marked as optional, or this may be the template
// of an |ASN1_ITEM_TEMPLATE| type which was contained inside an outer
// optional template. (They cannot both be true because the
// |ASN1_ITEM_TEMPLATE| codepath rejects optional templates.)
assert(!optional || (flags & ASN1_TFLG_OPTIONAL) == 0);
optional = optional || (flags & ASN1_TFLG_OPTIONAL) != 0;
// At this point 'ttag' contains the outer tag to use, and 'tclass' is the
// class.
if (flags & ASN1_TFLG_SK_MASK) {
// SET OF, SEQUENCE OF
STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
int isset, sktag, skaclass;
int skcontlen, sklen;
ASN1_VALUE *skitem;
if (!*pval) {
if (optional) {
return 0;
}
OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
return -1;
}
if (flags & ASN1_TFLG_SET_OF) {
isset = 1;
// Historically, types with both bits set were mutated when
// serialized to apply the sort. We no longer support this.
assert((flags & ASN1_TFLG_SEQUENCE_OF) == 0);
} else {
isset = 0;
}
// Work out inner tag value: if EXPLICIT or no tagging use underlying
// type.
if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) {
sktag = ttag;
skaclass = tclass;
} else {
skaclass = V_ASN1_UNIVERSAL;
if (isset) {
sktag = V_ASN1_SET;
} else {
sktag = V_ASN1_SEQUENCE;
}
}
// Determine total length of items
skcontlen = 0;
for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) {
int tmplen;
skitem = sk_ASN1_VALUE_value(sk, j);
tmplen =
ASN1_item_ex_i2d(&skitem, nullptr, ASN1_ITEM_ptr(tt->item), -1, 0);
if (tmplen == -1 || (skcontlen > INT_MAX - tmplen)) {
return -1;
}
skcontlen += tmplen;
}
sklen = ASN1_object_size(/*constructed=*/1, skcontlen, sktag);
if (sklen == -1) {
return -1;
}
// If EXPLICIT need length of surrounding tag
if (flags & ASN1_TFLG_EXPTAG) {
ret = ASN1_object_size(/*constructed=*/1, sklen, ttag);
} else {
ret = sklen;
}
if (!out || ret == -1) {
return ret;
}
// Now encode this lot...
// EXPLICIT tag
if (flags & ASN1_TFLG_EXPTAG) {
ASN1_put_object(out, /*constructed=*/1, sklen, ttag, tclass);
}
// SET or SEQUENCE and IMPLICIT tag
ASN1_put_object(out, /*constructed=*/1, skcontlen, sktag, skaclass);
// And the stuff itself
if (!asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), isset)) {
return -1;
}
return ret;
}
if (flags & ASN1_TFLG_EXPTAG) {
// EXPLICIT tagging
// Find length of tagged item
i = asn1_item_ex_i2d_opt(pval, nullptr, ASN1_ITEM_ptr(tt->item), -1, 0,
optional);
if (i <= 0) {
return i;
}
// Find length of EXPLICIT tag
ret = ASN1_object_size(/*constructed=*/1, i, ttag);
if (out && ret != -1) {
// Output tag and item
ASN1_put_object(out, /*constructed=*/1, i, ttag, tclass);
if (ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, 0) < 0) {
return -1;
}
}
return ret;
}
// Either normal or IMPLICIT tagging
return asn1_item_ex_i2d_opt(pval, out, ASN1_ITEM_ptr(tt->item), ttag, tclass,
optional);
}
// Temporary structure used to hold DER encoding of items for SET OF
typedef struct {
unsigned char *data;
int length;
} DER_ENC;
static int der_cmp(const void *a, const void *b) {
const DER_ENC *d1 = reinterpret_cast<const DER_ENC *>(a),
*d2 = reinterpret_cast<const DER_ENC *>(b);
int cmplen, i;
cmplen = (d1->length < d2->length) ? d1->length : d2->length;
i = OPENSSL_memcmp(d1->data, d2->data, cmplen);
if (i) {
return i;
}
return d1->length - d2->length;
}
// asn1_set_seq_out writes |sk| to |out| under the i2d output convention,
// excluding the tag and length. It returns one on success and zero on error.
// |skcontlen| must be the total encoded size. If |do_sort| is non-zero, the
// elements are sorted for a SET OF type. Each element of |sk| has type
// |item|.
static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
int skcontlen, const ASN1_ITEM *item, int do_sort) {
// No need to sort if there are fewer than two items.
if (!do_sort || sk_ASN1_VALUE_num(sk) < 2) {
for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
ASN1_VALUE *skitem = sk_ASN1_VALUE_value(sk, i);
if (ASN1_item_ex_i2d(&skitem, out, item, -1, 0) < 0) {
return 0;
}
}
return 1;
}
int ret = 0;
uint8_t *const buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(skcontlen));
DER_ENC *encoded = reinterpret_cast<DER_ENC *>(
OPENSSL_calloc(sk_ASN1_VALUE_num(sk), sizeof(*encoded)));
uint8_t *p = buf;
if (encoded == nullptr || buf == nullptr) {
goto err;
}
// Encode all the elements into |buf| and populate |encoded|.
for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
ASN1_VALUE *skitem = sk_ASN1_VALUE_value(sk, i);
encoded[i].data = p;
encoded[i].length = ASN1_item_ex_i2d(&skitem, &p, item, -1, 0);
if (encoded[i].length < 0) {
goto err;
}
assert(p - buf <= skcontlen);
}
qsort(encoded, sk_ASN1_VALUE_num(sk), sizeof(*encoded), der_cmp);
// Output the elements in sorted order.
p = *out;
for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
OPENSSL_memcpy(p, encoded[i].data, encoded[i].length);
p += encoded[i].length;
}
*out = p;
ret = 1;
err:
OPENSSL_free(encoded);
OPENSSL_free(buf);
return ret;
}
// asn1_i2d_ex_primitive behaves like |ASN1_item_ex_i2d| but |item| must be a
// a PRIMITIVE or MSTRING type that is not an |ASN1_ITEM_TEMPLATE|.
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass,
int optional) {
// Get length of content octets and maybe find out the underlying type.
int omit;
int utype = it->utype;
int len = asn1_ex_i2c(pval, nullptr, &omit, &utype, it);
if (len < 0) {
return -1;
}
if (omit) {
if (optional) {
return 0;
}
OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
return -1;
}
// If SEQUENCE, SET or OTHER then header is included in pseudo content
// octets so don't include tag+length. We need to check here because the
// call to asn1_ex_i2c() could change utype.
int usetag =
utype != V_ASN1_SEQUENCE && utype != V_ASN1_SET && utype != V_ASN1_OTHER;
// If not implicitly tagged get tag from underlying type
if (tag == -1) {
tag = utype;
}
// Output tag+length followed by content octets
if (out) {
if (usetag) {
ASN1_put_object(out, /*constructed=*/0, len, tag, aclass);
}
int len2 = asn1_ex_i2c(pval, *out, &omit, &utype, it);
if (len2 < 0) {
return -1;
}
assert(len == len2);
assert(!omit);
*out += len;
}
if (usetag) {
return ASN1_object_size(/*constructed=*/0, len, tag);
}
return len;
}
// asn1_ex_i2c writes the |*pval| to |cout| under the i2d output convention,
// excluding the tag and length. It returns the number of bytes written,
// possibly zero, on success or -1 on error. If |*pval| should be omitted, it
// returns zero and sets |*out_omit| to true.
//
// If |it| is an MSTRING or ANY type, it gets the underlying type from |*pval|,
// which must be an |ASN1_STRING| or |ASN1_TYPE|, respectively. It then updates
// |*putype| with the tag number of type used, or |V_ASN1_OTHER| if it was not a
// universal type. If |*putype| is set to |V_ASN1_SEQUENCE|, |V_ASN1_SET|, or
// |V_ASN1_OTHER|, it additionally outputs the tag and length, so the caller
// must not do so.
//
// Otherwise, |*putype| must contain |it->utype|.
//
// WARNING: Unlike most functions in this file, |asn1_ex_i2c| can return zero
// without omitting the element. ASN.1 values may have empty contents.
static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *out_omit,
int *putype, const ASN1_ITEM *it) {
ASN1_BOOLEAN *tbool = nullptr;
ASN1_STRING *strtmp;
ASN1_OBJECT *otmp;
int utype;
const unsigned char *cont;
unsigned char c;
int len;
assert(it->itype == ASN1_ITYPE_PRIMITIVE || it->itype == ASN1_ITYPE_MSTRING);
// Historically, |it->funcs| for primitive types contained an
// |ASN1_PRIMITIVE_FUNCS| table of callbacks.
assert(it->funcs == nullptr);
*out_omit = 0;
// Handle omitted optional values for all but BOOLEAN, which uses a
// non-pointer representation.
if (it->itype != ASN1_ITYPE_PRIMITIVE || it->utype != V_ASN1_BOOLEAN) {
if (!*pval) {
*out_omit = 1;
return 0;
}
}
if (it->itype == ASN1_ITYPE_MSTRING) {
// If MSTRING type set the underlying type
strtmp = (ASN1_STRING *)*pval;
utype = strtmp->type;
if (utype < 0 && utype != V_ASN1_OTHER) {
// MSTRINGs can have type -1 when default-constructed.
OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TYPE);
return -1;
}
// Negative INTEGER and ENUMERATED values use |ASN1_STRING| type values that
// do not match their corresponding utype values.
if (utype == V_ASN1_NEG_INTEGER) {
utype = V_ASN1_INTEGER;
} else if (utype == V_ASN1_NEG_ENUMERATED) {
utype = V_ASN1_ENUMERATED;
}
*putype = utype;
} else if (it->utype == V_ASN1_ANY) {
// If ANY set type and pointer to value
ASN1_TYPE *typ;
typ = (ASN1_TYPE *)*pval;
utype = typ->type;
if (utype < 0 && utype != V_ASN1_OTHER) {
// |ASN1_TYPE|s can have type -1 when default-constructed.
OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TYPE);
return -1;
}
*putype = utype;
pval = &typ->value.asn1_value;
} else {
utype = *putype;
}
switch (utype) {
case V_ASN1_OBJECT:
otmp = (ASN1_OBJECT *)*pval;
cont = otmp->data;
len = otmp->length;
if (len == 0) {
// Some |ASN1_OBJECT|s do not have OIDs and cannot be serialized.
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT);
return -1;
}
break;
case V_ASN1_NULL:
cont = nullptr;
len = 0;
break;
case V_ASN1_BOOLEAN:
tbool = (ASN1_BOOLEAN *)pval;
if (*tbool == ASN1_BOOLEAN_NONE) {
*out_omit = 1;
return 0;
}
if (it->utype != V_ASN1_ANY) {
// Default handling if value == size field then omit
if ((*tbool && (it->size > 0)) || (!*tbool && !it->size)) {
*out_omit = 1;
return 0;
}
}
c = *tbool ? 0xff : 0x00;
cont = &c;
len = 1;
break;
case V_ASN1_BIT_STRING: {
int ret =
i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, cout ? &cout : nullptr);
// |i2c_ASN1_BIT_STRING| returns zero on error instead of -1.
return ret <= 0 ? -1 : ret;
}
case V_ASN1_INTEGER:
case V_ASN1_ENUMERATED: {
// |i2c_ASN1_INTEGER| also handles ENUMERATED.
int ret = i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : nullptr);
// |i2c_ASN1_INTEGER| returns zero on error instead of -1.
return ret <= 0 ? -1 : ret;
}
case V_ASN1_OCTET_STRING:
case V_ASN1_NUMERICSTRING:
case V_ASN1_PRINTABLESTRING:
case V_ASN1_T61STRING:
case V_ASN1_VIDEOTEXSTRING:
case V_ASN1_IA5STRING:
case V_ASN1_UTCTIME:
case V_ASN1_GENERALIZEDTIME:
case V_ASN1_GRAPHICSTRING:
case V_ASN1_VISIBLESTRING:
case V_ASN1_GENERALSTRING:
case V_ASN1_UNIVERSALSTRING:
case V_ASN1_BMPSTRING:
case V_ASN1_UTF8STRING:
case V_ASN1_SEQUENCE:
case V_ASN1_SET:
// This is not a valid |ASN1_ITEM| type, but it appears in |ASN1_TYPE|.
case V_ASN1_OTHER:
// All based on ASN1_STRING and handled the same
strtmp = (ASN1_STRING *)*pval;
cont = strtmp->data;
len = strtmp->length;
break;
default:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
return -1;
}
if (cout && len) {
OPENSSL_memcpy(cout, cont, len);
}
return len;
}