in crypto/asn1/tasn_dec.c [788:935]
static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len,
int utype, const ASN1_ITEM *it) {
ASN1_VALUE **opval = NULL;
ASN1_STRING *stmp;
ASN1_TYPE *typ = NULL;
int ret = 0;
ASN1_INTEGER **tint;
// Historically, |it->funcs| for primitive types contained an
// |ASN1_PRIMITIVE_FUNCS| table of callbacks.
assert(it->funcs == NULL);
// If ANY type clear type and set pointer to internal value
if (it->utype == V_ASN1_ANY) {
if (!*pval) {
typ = ASN1_TYPE_new();
if (typ == NULL) {
goto err;
}
*pval = (ASN1_VALUE *)typ;
} else {
typ = (ASN1_TYPE *)*pval;
}
if (utype != typ->type) {
ASN1_TYPE_set(typ, utype, NULL);
}
opval = pval;
pval = &typ->value.asn1_value;
}
switch (utype) {
case V_ASN1_OBJECT:
if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) {
goto err;
}
break;
case V_ASN1_NULL:
if (len) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NULL_IS_WRONG_LENGTH);
goto err;
}
*pval = (ASN1_VALUE *)1;
break;
case V_ASN1_BOOLEAN:
if (len != 1) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
goto err;
} else {
ASN1_BOOLEAN *tbool;
tbool = (ASN1_BOOLEAN *)pval;
*tbool = *cont;
}
break;
case V_ASN1_BIT_STRING:
if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) {
goto err;
}
break;
case V_ASN1_INTEGER:
case V_ASN1_ENUMERATED:
tint = (ASN1_INTEGER **)pval;
if (!c2i_ASN1_INTEGER(tint, &cont, len)) {
goto err;
}
// Fixup type to match the expected form
(*tint)->type = utype | ((*tint)->type & V_ASN1_NEG);
break;
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_OTHER:
case V_ASN1_SET:
case V_ASN1_SEQUENCE:
default:
if (utype == V_ASN1_BMPSTRING && (len & 1)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH);
goto err;
}
if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH);
goto err;
}
if (utype == V_ASN1_UTCTIME) {
CBS cbs;
CBS_init(&cbs, cont, (size_t)len);
if (!CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
goto err;
}
}
if (utype == V_ASN1_GENERALIZEDTIME) {
CBS cbs;
CBS_init(&cbs, cont, (size_t)len);
if (!CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
goto err;
}
}
// All based on ASN1_STRING and handled the same
if (!*pval) {
stmp = ASN1_STRING_type_new(utype);
if (!stmp) {
goto err;
}
*pval = (ASN1_VALUE *)stmp;
} else {
stmp = (ASN1_STRING *)*pval;
stmp->type = utype;
}
if (!ASN1_STRING_set(stmp, cont, len)) {
ASN1_STRING_free(stmp);
*pval = NULL;
goto err;
}
break;
}
// If ASN1_ANY and NULL type fix up value
if (typ && (utype == V_ASN1_NULL)) {
typ->value.ptr = NULL;
}
ret = 1;
err:
if (!ret) {
ASN1_TYPE_free(typ);
if (opval) {
*opval = NULL;
}
}
return ret;
}