]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix OID check for PRIVATEOID keys and signatures
authorMark Andrews <marka@isc.org>
Thu, 3 Apr 2025 01:49:39 +0000 (12:49 +1100)
committerMark Andrews <marka@isc.org>
Wed, 9 Apr 2025 20:07:31 +0000 (20:07 +0000)
We were failing to account for the length byte before the OID.
See RFC 4034.

   Algorithm number 254 is reserved for private use and will never be
   assigned to a specific algorithm.  The public key area in the DNSKEY
   RR and the signature area in the RRSIG RR begin with an unsigned
   length byte followed by a BER encoded Object Identifier (ISO OID) of
   that length.  The OID indicates the private algorithm in use, and the
   remainder of the area is whatever is required by that algorithm.
   Entities should only use OIDs they control to designate their private
   algorithms.

(cherry picked from commit ca7355b7d064154a348d81002504b1092bf55937)

lib/dns/rdata.c
lib/dns/rdata/generic/key_25.c
tests/dns/rdata_test.c

index e88c289aed91e9af0b9f81ac96ac46773343e02a..dd1e990251489c1c5721c41d5d73615ce31b5ccd 100644 (file)
@@ -609,19 +609,26 @@ check_private(isc_buffer_t *source, dns_secalg_t alg) {
        } else if (alg == DNS_KEYALG_PRIVATEOID) {
                /*
                 * Check that we can extract the OID from the start of the
-                * key data.
+                * key data. We have a length byte followed by the OID BER
+                * encoded.
                 */
                const unsigned char *in = NULL;
                ASN1_OBJECT *obj = NULL;
 
                isc_buffer_activeregion(source, &sr);
-               in = sr.base;
-               obj = d2i_ASN1_OBJECT(NULL, &in, sr.length);
+               if (sr.length < 1 || (unsigned int)*sr.base + 1 > sr.length) {
+                       RETERR(DNS_R_FORMERR);
+               }
+               in = sr.base + 1;
+               obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base);
                if (obj == NULL) {
                        ERR_clear_error();
                        RETERR(DNS_R_FORMERR);
                }
                ASN1_OBJECT_free(obj);
+               if ((in - sr.base) != (*sr.base + 1)) {
+                       RETERR(DNS_R_FORMERR);
+               }
        }
        return ISC_R_SUCCESS;
 }
index 12b509555394052d2862cf48846e2c53ff9d70fc..351c1149d70ad09a70b30a5182d3be7cf612c863 100644 (file)
@@ -164,11 +164,10 @@ generic_totext_key(ARGS_TOTEXT) {
        } else if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 &&
                   algorithm == DNS_KEYALG_PRIVATEOID)
        {
-               const unsigned char *in = sr.base;
-               ASN1_OBJECT *obj = d2i_ASN1_OBJECT(NULL, &in, sr.length);
-               int n;
+               const unsigned char *in = sr.base + 1;
+               ASN1_OBJECT *obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base);
                INSIST(obj != NULL);
-               n = i2t_ASN1_OBJECT(algbuf, sizeof(buf), obj);
+               int n = i2t_ASN1_OBJECT(algbuf, sizeof(buf), obj);
                ASN1_OBJECT_free(obj);
                if (n == -1 || (size_t)n >= sizeof(algbuf)) {
                        dns_secalg_format((dns_secalg_t)algorithm, algbuf,
index 96b3140fc615d512afc636e86a401203f54357e0..83b4711d4766e170e3699e45d7b495e4063c4a74 100644 (file)
@@ -2054,17 +2054,17 @@ ISC_RUN_TEST_IMPL(key) {
                /* PRIVATEOID */
                WIRE_INVALID(0x00, 0x00, 0x00, 254, 0x00),
                /* PRIVATEOID 1.3.6.1.4.1.2495 without key data */
-               WIRE_VALID(0x00, 0x00, 0x00, 254, 0x06, 0x07, 0x2b, 0x06, 0x01,
-                          0x04, 0x01, 0x93, 0x3f),
+               WIRE_VALID(0x00, 0x00, 0x00, 254, 0x09, 0x06, 0x07, 0x2b, 0x06,
+                          0x01, 0x04, 0x01, 0x93, 0x3f),
                /* PRIVATEOID 1.3.6.1.4.1.2495 + keydata */
-               WIRE_VALID(0x00, 0x00, 0x00, 254, 0x06, 0x07, 0x2b, 0x06, 0x01,
-                          0x04, 0x01, 0x93, 0x3f, 0x00),
+               WIRE_VALID(0x00, 0x00, 0x00, 254, 0x09, 0x06, 0x07, 0x2b, 0x06,
+                          0x01, 0x04, 0x01, 0x93, 0x3f, 0x00),
                /* PRIVATEOID malformed OID - high-bit set on last octet */
                WIRE_INVALID(0x00, 0x00, 0x00, 254, 0x06, 0x07, 0x2b, 0x06,
                             0x01, 0x04, 0x01, 0x93, 0xbf, 0x00),
                /* PRIVATEOID malformed OID - wrong tag */
-               WIRE_INVALID(0x00, 0x00, 0x00, 254, 0x07, 0x07, 0x2b, 0x06,
-                            0x01, 0x04, 0x01, 0x93, 0x3f, 0x00),
+               WIRE_INVALID(0x00, 0x00, 0x00, 254, 0x09, 0x07, 0x07, 0x2b,
+                            0x06, 0x01, 0x04, 0x01, 0x93, 0x3f, 0x00),
                WIRE_SENTINEL()
        };
        text_ok_t text_ok[] = { /* PRIVATEDNS example. */
@@ -2076,14 +2076,14 @@ ISC_RUN_TEST_IMPL(key) {
                                /* PRIVATEOID */
                                TEXT_INVALID("0 0 254 AA=="),
                                /* PRIVATEOID 1.3.6.1.4.1.2495 */
-                               TEXT_VALID("0 0 254 BgcrBgEEAZM/"),
+                               TEXT_VALID("0 0 254 CQYHKwYBBAGTPw=="),
                                /* PRIVATEOID 1.3.6.1.4.1.2495 + keydata */
-                               TEXT_VALID("0 0 254 BgcrBgEEAZM/AA=="),
+                               TEXT_VALID("0 0 254 CQYHKwYBBAGTPwA="),
                                /* PRIVATEOID malformed OID - high-bit set on
                                   last octet */
-                               TEXT_INVALID("0 0 254 BgcrBgEEAZO/AA=="),
+                               TEXT_INVALID("0 0 254 CQYHKwYBBAGTvwA="),
                                /* PRIVATEOID malformed OID - wrong tag */
-                               TEXT_INVALID("0 0 254 BwcrBgEEAZM/AA=="),
+                               TEXT_INVALID("0 0 254 CQcHKwYBBAGTPwA="),
                                /*
                                 * Sentinel.
                                 */