Reduce type-punning in ASN1_TYPE

ASN1_TYPE is a union of a bunch of pointer types. Often it takes a
shorthand and accesses a->value.ptr directly. This is allowed in C, but
not C++. Writing the switch/case barely takes more code, so just write
it that way.

Along the way, extract the code for cleaning up an ASN1_TYPE from
tasn_fre.c. This is a small step towards being able to use crypto/asn1's
types without depending on the templates. ASN1_TYPE_free still, for now,
calls into the templates. That will be fixable once tasn_*.c are
rewritten a bit further.

This also removes the weird hack here ASN1_primitive_free (an internal
function) with NULL ASN1_ITEM secretly meant to partially clean up the
ASN1_TYPE. We can just call the function directly now.

Bug: 574
Change-Id: Ie2ba41418801a366ab2f12eccc01e8dadf82c33e
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58126
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
This commit is contained in:
David Benjamin 2023-03-12 12:42:33 -04:00 committed by Boringssl LUCI CQ
parent 6a231e5c6e
commit 860cc73bb2
3 changed files with 62 additions and 43 deletions

View File

@ -65,31 +65,65 @@
int ASN1_TYPE_get(const ASN1_TYPE *a) {
if (a->type == V_ASN1_BOOLEAN || a->type == V_ASN1_NULL ||
a->value.ptr != NULL) {
return a->type;
switch (a->type) {
case V_ASN1_NULL:
case V_ASN1_BOOLEAN:
return a->type;
case V_ASN1_OBJECT:
return a->value.object != NULL ? a->type : 0;
default:
return a->value.asn1_string != NULL ? a->type : 0;
}
return 0;
}
const void *asn1_type_value_as_pointer(const ASN1_TYPE *a) {
if (a->type == V_ASN1_BOOLEAN) {
return a->value.boolean ? (void *)0xff : NULL;
switch (a->type) {
case V_ASN1_NULL:
return NULL;
case V_ASN1_BOOLEAN:
return a->value.boolean ? (void *)0xff : NULL;
case V_ASN1_OBJECT:
return a->value.object;
default:
return a->value.asn1_string;
}
if (a->type == V_ASN1_NULL) {
return NULL;
}
void asn1_type_cleanup(ASN1_TYPE *a) {
switch (a->type) {
case V_ASN1_NULL:
a->value.ptr = NULL;
break;
case V_ASN1_BOOLEAN:
a->value.boolean = ASN1_BOOLEAN_NONE;
break;
case V_ASN1_OBJECT:
ASN1_OBJECT_free(a->value.object);
a->value.object = NULL;
break;
default:
ASN1_STRING_free(a->value.asn1_string);
a->value.asn1_string = NULL;
break;
}
return a->value.ptr;
}
void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) {
ASN1_TYPE **tmp_a = &a;
ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL);
asn1_type_cleanup(a);
a->type = type;
if (type == V_ASN1_BOOLEAN) {
a->value.boolean = value ? 0xff : 0;
} else {
a->value.ptr = value;
switch (type) {
case V_ASN1_NULL:
a->value.ptr = NULL;
break;
case V_ASN1_BOOLEAN:
a->value.boolean = value ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE;
break;
case V_ASN1_OBJECT:
a->value.object = value;
break;
default:
a->value.asn1_string = value;
break;
}
}

View File

@ -210,6 +210,10 @@ void asn1_encoding_clear(ASN1_ENCODING *enc);
// a pointer.
const void *asn1_type_value_as_pointer(const ASN1_TYPE *a);
// asn1_type_cleanup releases memory associated with |a|'s value, without
// freeing |a| itself.
void asn1_type_cleanup(ASN1_TYPE *a);
// asn1_is_printable returns one if |value| is a valid Unicode codepoint for an
// ASN.1 PrintableString, and zero otherwise.
int asn1_is_printable(uint32_t value);

View File

@ -161,12 +161,10 @@ void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
}
void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) {
size_t i;
if (tt->flags & ASN1_TFLG_SK_MASK) {
STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
ASN1_VALUE *vtmp;
vtmp = sk_ASN1_VALUE_value(sk, i);
for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
ASN1_VALUE *vtmp = sk_ASN1_VALUE_value(sk, i);
ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item));
}
sk_ASN1_VALUE_free(sk);
@ -177,30 +175,11 @@ void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) {
}
void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
int utype;
// Historically, |it->funcs| for primitive types contained an
// |ASN1_PRIMITIVE_FUNCS| table of calbacks.
assert(it == NULL || it->funcs == NULL);
// Special case: if 'it' is NULL free contents of ASN1_TYPE
if (!it) {
ASN1_TYPE *typ = (ASN1_TYPE *)*pval;
utype = typ->type;
pval = &typ->value.asn1_value;
if (utype != V_ASN1_BOOLEAN && !*pval) {
return;
}
} else if (it->itype == ASN1_ITYPE_MSTRING) {
utype = -1;
if (!*pval) {
return;
}
} else {
utype = it->utype;
if ((utype != V_ASN1_BOOLEAN) && !*pval) {
return;
}
}
assert(it->funcs == NULL);
int utype = it->itype == ASN1_ITYPE_MSTRING ? -1 : it->utype;
switch (utype) {
case V_ASN1_OBJECT:
ASN1_OBJECT_free((ASN1_OBJECT *)*pval);
@ -210,7 +189,7 @@ void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
if (it) {
*(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size;
} else {
*(ASN1_BOOLEAN *)pval = -1;
*(ASN1_BOOLEAN *)pval = ASN1_BOOLEAN_NONE;
}
return;
@ -218,8 +197,10 @@ void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
break;
case V_ASN1_ANY:
ASN1_primitive_free(pval, NULL);
OPENSSL_free(*pval);
if (*pval != NULL) {
asn1_type_cleanup((ASN1_TYPE *)*pval);
OPENSSL_free(*pval);
}
break;
default: