in Sources/CNIOBoringSSL/crypto/asn1/tasn_enc.c [564:710]
static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *out_omit,
int *putype, const ASN1_ITEM *it)
{
ASN1_BOOLEAN *tbool = NULL;
ASN1_STRING *strtmp;
ASN1_OBJECT *otmp;
int utype;
const unsigned char *cont;
unsigned char c;
int len;
/* Historically, |it->funcs| for primitive types contained an
* |ASN1_PRIMITIVE_FUNCS| table of callbacks. */
assert(it->funcs == NULL);
*out_omit = 0;
/* Should type be omitted? */
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. INTEGERs cannot
* participate in MSTRING types, but ENUMERATEDs can.
*
* TODO(davidben): Is this a bug? Although arguably one of the MSTRING
* types should contain more values, rather than less. See
* https://crbug.com/boringssl/412. But it is not possible to fit all
* possible ANY values into an |ASN1_STRING|, so matching the spec here
* is somewhat hopeless. */
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 = NULL;
len = 0;
break;
case V_ASN1_BOOLEAN:
tbool = (ASN1_BOOLEAN *)pval;
if (*tbool == -1) {
*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 : NULL);
/* |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 : NULL);
/* |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:
default:
/* All based on ASN1_STRING and handled the same */
strtmp = (ASN1_STRING *)*pval;
cont = strtmp->data;
len = strtmp->length;
break;
}
if (cout && len)
OPENSSL_memcpy(cout, cont, len);
return len;
}