Ensure ASN.1 types are appropriately encoded.
authorjsing <jsing@openbsd.org>
Sat, 3 Sep 2022 18:52:18 +0000 (18:52 +0000)
committerjsing <jsing@openbsd.org>
Sat, 3 Sep 2022 18:52:18 +0000 (18:52 +0000)
Per X.690, some ASN.1 types must be primitive encoded, some must be
constructed and some may be either. Add this data to our types table
and check the encoding against this information when decoding.

ok tb@

lib/libcrypto/asn1/asn1_locl.h
lib/libcrypto/asn1/asn1_types.c
lib/libcrypto/asn1/tasn_dec.c

index e2c57fd..1eb7ee4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: asn1_locl.h,v 1.36 2022/09/03 18:45:51 jsing Exp $ */
+/* $OpenBSD: asn1_locl.h,v 1.37 2022/09/03 18:52:18 jsing Exp $ */
 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
  * project 2006.
  */
@@ -204,6 +204,8 @@ int asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
 int asn1_get_primitive(CBS *cbs, int der_mode, uint32_t *out_tag_number,
     CBS *out_content);
 
+int asn1_must_be_constructed(int tag);
+int asn1_must_be_primitive(int tag);
 int asn1_tag2charwidth(int tag);
 
 int asn1_abs_set_unused_bits(ASN1_BIT_STRING *abs, uint8_t unused_bits);
@@ -211,6 +213,8 @@ int c2i_ASN1_BIT_STRING_cbs(ASN1_BIT_STRING **out_abs, CBS *cbs);
 
 int c2i_ASN1_ENUMERATED_cbs(ASN1_ENUMERATED **out_aenum, CBS *cbs);
 
+int c2i_ASN1_ENUMERATED_cbs(ASN1_ENUMERATED **out_aenum, CBS *cbs);
+
 int asn1_aint_get_uint64(CBS *cbs, uint64_t *out_val);
 int asn1_aint_set_uint64(uint64_t val, uint8_t **out_data, int *out_len);
 int asn1_aint_get_int64(CBS *cbs, int negative, int64_t *out_val);
index c8e6b23..d8b7c1e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: asn1_types.c,v 1.1 2021/12/14 17:35:21 jsing Exp $ */
+/* $OpenBSD: asn1_types.c,v 1.2 2022/09/03 18:52:18 jsing Exp $ */
 /*
  * Copyright (c) 2021 Joel Sing <jsing@openbsd.org>
  *
 
 #include <openssl/asn1.h>
 
+#define ASN1_ENCODING_CONSTRUCTED_ONLY 1
+#define ASN1_ENCODING_PRIMITIVE_ONLY   2
+
 struct asn1_type {
        const char *name;
        uint32_t bit_value;
        int char_width;
+       int encoding;
 };
 
 /*
@@ -40,12 +44,14 @@ static const struct asn1_type asn1_types[31] = {
                .name = "BOOLEAN",
                .bit_value = 0,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [2] = {
                /* Tag 2 (0x02) - Integer */
                .name = "INTEGER",
                .bit_value = 0,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [3] = {
                /* Tag 3 (0x03) - BitString */
@@ -64,12 +70,14 @@ static const struct asn1_type asn1_types[31] = {
                .name = "NULL",
                .bit_value = 0,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [6] = {
                /* Tag 6 (0x06) - Object Identifier */
                .name = "OBJECT",
                .bit_value = 0,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [7] = {
                /* Tag 7 (0x07) - Object Descriptor */
@@ -88,12 +96,14 @@ static const struct asn1_type asn1_types[31] = {
                .name = "REAL",
                .bit_value = B_ASN1_UNKNOWN,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [10] = {
                /* Tag 10 (0x0a) - Enumerated */
                .name = "ENUMERATED",
                .bit_value = B_ASN1_UNKNOWN,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [11] = {
                /* Tag 11 (0x0b) - Embedded PDV */
@@ -112,12 +122,14 @@ static const struct asn1_type asn1_types[31] = {
                .name = "<ASN1 13 RELATIVE OID>",
                .bit_value = B_ASN1_UNKNOWN,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [14] = {
                /* Tag 14 (0x0e) - Time */
                .name = "<ASN1 14 TIME>",
                .bit_value = B_ASN1_UNKNOWN,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_PRIMITIVE_ONLY,
        },
        [15] = {
                /* Tag 15 (0x0f) - Reserved */
@@ -130,12 +142,14 @@ static const struct asn1_type asn1_types[31] = {
                .name = "SEQUENCE",
                .bit_value = B_ASN1_SEQUENCE,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_CONSTRUCTED_ONLY,
        },
        [17] = {
                /* Tag 17 (0x11) - Set */
                .name = "SET",
                .bit_value = 0,
                .char_width = -1,
+               .encoding = ASN1_ENCODING_CONSTRUCTED_ONLY,
        },
        [18] = {
                /* Tag 18 (0x12) - NumericString */
@@ -226,6 +240,32 @@ asn1_type_by_tag(int tag)
        return &asn1_types[tag];
 }
 
+int
+asn1_must_be_constructed(int tag)
+{
+       const struct asn1_type *at;
+
+       if (tag == V_ASN1_NEG_INTEGER || tag == V_ASN1_NEG_ENUMERATED)
+               tag &= ~V_ASN1_NEG;
+       if ((at = asn1_type_by_tag(tag)) != NULL)
+               return at->encoding == ASN1_ENCODING_CONSTRUCTED_ONLY;
+
+       return 0;
+}
+
+int
+asn1_must_be_primitive(int tag)
+{
+       const struct asn1_type *at;
+
+       if (tag == V_ASN1_NEG_INTEGER || tag == V_ASN1_NEG_ENUMERATED)
+               tag &= ~V_ASN1_NEG;
+       if ((at = asn1_type_by_tag(tag)) != NULL)
+               return at->encoding == ASN1_ENCODING_PRIMITIVE_ONLY;
+
+       return 0;
+}
+
 int
 asn1_tag2charwidth(int tag)
 {
index 22d8006..457f526 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tasn_dec.c,v 1.79 2022/09/03 18:45:51 jsing Exp $ */
+/* $OpenBSD: tasn_dec.c,v 1.80 2022/09/03 18:52:18 jsing Exp $ */
 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
  * project 2000.
  */
@@ -467,13 +467,14 @@ asn1_d2i_primitive_content(ASN1_VALUE **pval, CBS *cbs, CBS *cbs_object,
        CBS_dup(cbs, &cbs_initial);
        CBS_init(&cbs_content, NULL, 0);
 
-       /* XXX - check primitive vs constructed based on utype. */
-
-       /* SEQUENCE and SET must be constructed. */
-       if ((utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET) && !constructed) {
+       if (asn1_must_be_constructed(utype) && !constructed) {
                ASN1error(ASN1_R_TYPE_NOT_CONSTRUCTED);
                goto err;
        }
+       if (asn1_must_be_primitive(utype) && constructed) {
+               ASN1error(ASN1_R_TYPE_NOT_PRIMITIVE);
+               goto err;
+       }
 
        /* SEQUENCE, SET and "OTHER" are left in encoded form. */
        if (utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET ||