aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2022-0934.patch188
-rw-r--r--meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb1
-rw-r--r--meta-oe/recipes-crypto/cryptsetup/cryptsetup_2.3.7.bb (renamed from meta-oe/recipes-crypto/cryptsetup/cryptsetup_2.3.2.bb)4
-rw-r--r--meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch947
-rw-r--r--meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb1
-rw-r--r--meta-oe/recipes-devtools/nodejs/nodejs/CVE-2021-44532.patch3090
-rw-r--r--meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb (renamed from meta-oe/recipes-devtools/nodejs/nodejs_12.22.2.bb)5
-rw-r--r--meta-oe/recipes-support/c-ares/c-ares/0001-fix-configure-error-mv-libcares.pc.cmakein-to-libcar.patch27
-rw-r--r--meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-fix-formatting-and-handling-of-root.patch115
-rw-r--r--meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-should-escape-more-characters.patch90
-rw-r--r--meta-oe/recipes-support/c-ares/c-ares/cmake-install-libcares.pc.patch84
-rw-r--r--meta-oe/recipes-support/c-ares/c-ares_1.18.1.bb (renamed from meta-oe/recipes-support/c-ares/c-ares_1.16.1.bb)12
-rw-r--r--meta-python/recipes-devtools/python/python-lxml.inc2
-rw-r--r--meta-python/recipes-devtools/python/python3-lxml/CVE-2022-2309.patch94
14 files changed, 1239 insertions, 3421 deletions
diff --git a/meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2022-0934.patch b/meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2022-0934.patch
new file mode 100644
index 0000000000..b2ef22c06f
--- /dev/null
+++ b/meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2022-0934.patch
@@ -0,0 +1,188 @@
+From 70df9f9104c8f0661966298b58caf794b99e26e1 Mon Sep 17 00:00:00 2001
+From: Hitendra Prajapati <hprajapati@mvista.com>
+Date: Thu, 22 Sep 2022 17:39:21 +0530
+Subject: [PATCH] CVE-2022-0934
+
+Upstream-Status: Backport [https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=03345ecefeb0d82e3c3a4c28f27c3554f0611b39]
+CVE: CVE-2022-0934
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ CHANGELOG | 2 ++
+ src/rfc3315.c | 48 +++++++++++++++++++++++++++---------------------
+ 2 files changed, 29 insertions(+), 21 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 60b08d0..d1d7e41 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -88,6 +88,8 @@ version 2.81
+
+ Add --script-on-renewal option.
+
++ Fix write-after-free error in DHCPv6 server code.
++ CVE-2022-0934 refers.
+
+ version 2.80
+ Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method
+diff --git a/src/rfc3315.c b/src/rfc3315.c
+index b3f0a0a..eef1360 100644
+--- a/src/rfc3315.c
++++ b/src/rfc3315.c
+@@ -33,9 +33,9 @@ struct state {
+ unsigned int mac_len, mac_type;
+ };
+
+-static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
++static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
+ struct in6_addr *client_addr, int is_unicast, time_t now);
+-static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
++static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now);
+ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
+ static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
+ static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
+@@ -104,12 +104,12 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
+ }
+
+ /* This cost me blood to write, it will probably cost you blood to understand - srk. */
+-static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
++static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
+ struct in6_addr *client_addr, int is_unicast, time_t now)
+ {
+ void *end = inbuff + sz;
+ void *opts = inbuff + 34;
+- int msg_type = *((unsigned char *)inbuff);
++ int msg_type = *inbuff;
+ unsigned char *outmsgtypep;
+ void *opt;
+ struct dhcp_vendor *vendor;
+@@ -259,15 +259,15 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
+ return 1;
+ }
+
+-static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)
++static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now)
+ {
+ void *opt;
+- int i, o, o1, start_opts;
++ int i, o, o1, start_opts, start_msg;
+ struct dhcp_opt *opt_cfg;
+ struct dhcp_netid *tagif;
+ struct dhcp_config *config = NULL;
+ struct dhcp_netid known_id, iface_id, v6_id;
+- unsigned char *outmsgtypep;
++ unsigned char outmsgtype;
+ struct dhcp_vendor *vendor;
+ struct dhcp_context *context_tmp;
+ struct dhcp_mac *mac_opt;
+@@ -296,12 +296,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ v6_id.next = state->tags;
+ state->tags = &v6_id;
+
+- /* copy over transaction-id, and save pointer to message type */
+- if (!(outmsgtypep = put_opt6(inbuff, 4)))
++ start_msg = save_counter(-1);
++ /* copy over transaction-id */
++ if (!put_opt6(inbuff, 4))
+ return 0;
+ start_opts = save_counter(-1);
+- state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
+-
++ state->xid = inbuff[3] | inbuff[2] << 8 | inbuff[1] << 16;
++
+ /* We're going to be linking tags from all context we use.
+ mark them as unused so we don't link one twice and break the list */
+ for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
+@@ -347,7 +348,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
+
+ {
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+ o1 = new_opt6(OPTION6_STATUS_CODE);
+ put_opt6_short(DHCP6USEMULTI);
+ put_opt6_string("Use multicast");
+@@ -619,11 +620,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ struct dhcp_netid *solicit_tags;
+ struct dhcp_context *c;
+
+- *outmsgtypep = DHCP6ADVERTISE;
++ outmsgtype = DHCP6ADVERTISE;
+
+ if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
+ {
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+ state->lease_allocate = 1;
+ o = new_opt6(OPTION6_RAPID_COMMIT);
+ end_opt6(o);
+@@ -809,7 +810,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ int start = save_counter(-1);
+
+ /* set reply message type */
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+ state->lease_allocate = 1;
+
+ log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
+@@ -921,7 +922,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ case DHCP6RENEW:
+ {
+ /* set reply message type */
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+
+ log6_quiet(state, "DHCPRENEW", NULL, NULL);
+
+@@ -1033,7 +1034,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ int good_addr = 0;
+
+ /* set reply message type */
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+
+ log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
+
+@@ -1097,7 +1098,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
+ if (ignore)
+ return 0;
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+ tagif = add_options(state, 1);
+ break;
+ }
+@@ -1106,7 +1107,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ case DHCP6RELEASE:
+ {
+ /* set reply message type */
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+
+ log6_quiet(state, "DHCPRELEASE", NULL, NULL);
+
+@@ -1171,7 +1172,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ case DHCP6DECLINE:
+ {
+ /* set reply message type */
+- *outmsgtypep = DHCP6REPLY;
++ outmsgtype = DHCP6REPLY;
+
+ log6_quiet(state, "DHCPDECLINE", NULL, NULL);
+
+@@ -1251,7 +1252,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
+ }
+
+ }
+-
++
++ /* Fill in the message type. Note that we store the offset,
++ not a direct pointer, since the packet memory may have been
++ reallocated. */
++ ((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype;
++
+ log_tags(tagif, state->xid);
+ log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
+
+--
+2.25.1
+
diff --git a/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb b/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb
index 2fb389915b..8db57edb79 100644
--- a/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb
+++ b/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb
@@ -11,4 +11,5 @@ SRC_URI += "\
file://CVE-2020-25686-1.patch \
file://CVE-2020-25686-2.patch \
file://CVE-2021-3448.patch \
+ file://CVE-2022-0934.patch \
"
diff --git a/meta-oe/recipes-crypto/cryptsetup/cryptsetup_2.3.2.bb b/meta-oe/recipes-crypto/cryptsetup/cryptsetup_2.3.7.bb
index 3c1c8b0beb..d303f27ebb 100644
--- a/meta-oe/recipes-crypto/cryptsetup/cryptsetup_2.3.2.bb
+++ b/meta-oe/recipes-crypto/cryptsetup/cryptsetup_2.3.7.bb
@@ -21,8 +21,8 @@ RDEPENDS_${PN} = " \
"
SRC_URI = "${KERNELORG_MIRROR}/linux/utils/${BPN}/v${@d.getVar('PV').split('.')[0]}.${@d.getVar('PV').split('.')[1]}/${BP}.tar.xz"
-SRC_URI[md5sum] = "6e4ffb6d35a73f7539a5d0c1354654cd"
-SRC_URI[sha256sum] = "a89e13dff0798fd0280e801d5f0cc8cfdb2aa5b1929bec1b7322e13d3eca95fb"
+SRC_URI[md5sum] = "9c5952cebb836ee783b0b76c5380a964"
+SRC_URI[sha256sum] = "61835132a5986217af17b8943013aa3fe6d47bdc1a07386343526765e2ce27a9"
inherit autotools gettext pkgconfig
diff --git a/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch b/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch
new file mode 100644
index 0000000000..6f0d5ac06f
--- /dev/null
+++ b/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch
@@ -0,0 +1,947 @@
+From 31eefa1efc8eecb6ab91c8835d2952d44a3b1ae1 Mon Sep 17 00:00:00 2001
+From: Hitendra Prajapati <hprajapati@mvista.com>
+Date: Thu, 22 Sep 2022 11:20:41 +0530
+Subject: [PATCH] CVE-2022-1552
+
+Upstream-Status: Backport [https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=ab49ce7c3414ac19e4afb386d7843ce2d2fb8bda && https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=677a494789062ca88e0142a17bedd5415f6ab0aa]
+
+CVE: CVE-2022-1552
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ contrib/amcheck/expected/check_btree.out | 23 ++++++
+ contrib/amcheck/sql/check_btree.sql | 21 +++++
+ contrib/amcheck/verify_nbtree.c | 27 +++++++
+ src/backend/access/brin/brin.c | 29 ++++++-
+ src/backend/catalog/index.c | 65 ++++++++++++----
+ src/backend/commands/cluster.c | 37 ++++++---
+ src/backend/commands/indexcmds.c | 98 ++++++++++++++++++++----
+ src/backend/commands/matview.c | 30 +++-----
+ src/backend/utils/init/miscinit.c | 24 +++---
+ src/test/regress/expected/privileges.out | 71 +++++++++++++++++
+ src/test/regress/sql/privileges.sql | 64 ++++++++++++++++
+ 11 files changed, 422 insertions(+), 67 deletions(-)
+
+diff --git a/contrib/amcheck/expected/check_btree.out b/contrib/amcheck/expected/check_btree.out
+index 59a805d..0fd6ea0 100644
+--- a/contrib/amcheck/expected/check_btree.out
++++ b/contrib/amcheck/expected/check_btree.out
+@@ -168,11 +168,34 @@ SELECT bt_index_check('toasty', true);
+
+ (1 row)
+
++--
++-- Check that index expressions and predicates are run as the table's owner
++--
++TRUNCATE bttest_a;
++INSERT INTO bttest_a SELECT * FROM generate_series(1, 1000);
++ALTER TABLE bttest_a OWNER TO regress_bttest_role;
++-- A dummy index function checking current_user
++CREATE FUNCTION ifun(int8) RETURNS int8 AS $$
++BEGIN
++ ASSERT current_user = 'regress_bttest_role',
++ format('ifun(%s) called by %s', $1, current_user);
++ RETURN $1;
++END;
++$$ LANGUAGE plpgsql IMMUTABLE;
++CREATE INDEX bttest_a_expr_idx ON bttest_a ((ifun(id) + ifun(0)))
++ WHERE ifun(id + 10) > ifun(10);
++SELECT bt_index_check('bttest_a_expr_idx', true);
++ bt_index_check
++----------------
++
++(1 row)
++
+ -- cleanup
+ DROP TABLE bttest_a;
+ DROP TABLE bttest_b;
+ DROP TABLE bttest_multi;
+ DROP TABLE delete_test_table;
+ DROP TABLE toast_bug;
++DROP FUNCTION ifun(int8);
+ DROP OWNED BY regress_bttest_role; -- permissions
+ DROP ROLE regress_bttest_role;
+diff --git a/contrib/amcheck/sql/check_btree.sql b/contrib/amcheck/sql/check_btree.sql
+index 99acbc8..3248187 100644
+--- a/contrib/amcheck/sql/check_btree.sql
++++ b/contrib/amcheck/sql/check_btree.sql
+@@ -110,11 +110,32 @@ INSERT INTO toast_bug SELECT repeat('a', 2200);
+ -- Should not get false positive report of corruption:
+ SELECT bt_index_check('toasty', true);
+
++--
++-- Check that index expressions and predicates are run as the table's owner
++--
++TRUNCATE bttest_a;
++INSERT INTO bttest_a SELECT * FROM generate_series(1, 1000);
++ALTER TABLE bttest_a OWNER TO regress_bttest_role;
++-- A dummy index function checking current_user
++CREATE FUNCTION ifun(int8) RETURNS int8 AS $$
++BEGIN
++ ASSERT current_user = 'regress_bttest_role',
++ format('ifun(%s) called by %s', $1, current_user);
++ RETURN $1;
++END;
++$$ LANGUAGE plpgsql IMMUTABLE;
++
++CREATE INDEX bttest_a_expr_idx ON bttest_a ((ifun(id) + ifun(0)))
++ WHERE ifun(id + 10) > ifun(10);
++
++SELECT bt_index_check('bttest_a_expr_idx', true);
++
+ -- cleanup
+ DROP TABLE bttest_a;
+ DROP TABLE bttest_b;
+ DROP TABLE bttest_multi;
+ DROP TABLE delete_test_table;
+ DROP TABLE toast_bug;
++DROP FUNCTION ifun(int8);
+ DROP OWNED BY regress_bttest_role; -- permissions
+ DROP ROLE regress_bttest_role;
+diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
+index 700a02f..cb6475d 100644
+--- a/contrib/amcheck/verify_nbtree.c
++++ b/contrib/amcheck/verify_nbtree.c
+@@ -228,6 +228,9 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
+ Relation indrel;
+ Relation heaprel;
+ LOCKMODE lockmode;
++ Oid save_userid;
++ int save_sec_context;
++ int save_nestlevel;
+
+ if (parentcheck)
+ lockmode = ShareLock;
+@@ -244,9 +247,27 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
+ */
+ heapid = IndexGetRelation(indrelid, true);
+ if (OidIsValid(heapid))
++ {
+ heaprel = table_open(heapid, lockmode);
++
++ /*
++ * Switch to the table owner's userid, so that any index functions are
++ * run as that user. Also lock down security-restricted operations
++ * and arrange to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(heaprel->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++ }
+ else
++ {
+ heaprel = NULL;
++ /* for "gcc -Og" https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78394 */
++ save_userid = InvalidOid;
++ save_sec_context = -1;
++ save_nestlevel = -1;
++ }
+
+ /*
+ * Open the target index relations separately (like relation_openrv(), but
+@@ -293,6 +314,12 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
+ heapallindexed, rootdescend);
+ }
+
++ /* Roll back any GUC changes executed by index functions */
++ AtEOXact_GUC(false, save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(save_userid, save_sec_context);
++
+ /*
+ * Release locks early. That's ok here because nothing in the called
+ * routines will trigger shared cache invalidations to be sent, so we can
+diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
+index c7b403b..781cac2 100644
+--- a/src/backend/access/brin/brin.c
++++ b/src/backend/access/brin/brin.c
+@@ -873,6 +873,9 @@ brin_summarize_range(PG_FUNCTION_ARGS)
+ Oid heapoid;
+ Relation indexRel;
+ Relation heapRel;
++ Oid save_userid;
++ int save_sec_context;
++ int save_nestlevel;
+ double numSummarized = 0;
+
+ if (RecoveryInProgress())
+@@ -899,7 +902,22 @@ brin_summarize_range(PG_FUNCTION_ARGS)
+ */
+ heapoid = IndexGetRelation(indexoid, true);
+ if (OidIsValid(heapoid))
++ {
+ heapRel = table_open(heapoid, ShareUpdateExclusiveLock);
++
++ /*
++ * Autovacuum calls us. For its benefit, switch to the table owner's
++ * userid, so that any index functions are run as that user. Also
++ * lock down security-restricted operations and arrange to make GUC
++ * variable changes local to this command. This is harmless, albeit
++ * unnecessary, when called from SQL, because we fail shortly if the
++ * user does not own the index.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(heapRel->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++ }
+ else
+ heapRel = NULL;
+
+@@ -914,7 +932,7 @@ brin_summarize_range(PG_FUNCTION_ARGS)
+ RelationGetRelationName(indexRel))));
+
+ /* User must own the index (comparable to privileges needed for VACUUM) */
+- if (!pg_class_ownercheck(indexoid, GetUserId()))
++ if (heapRel != NULL && !pg_class_ownercheck(indexoid, save_userid))
+ aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_INDEX,
+ RelationGetRelationName(indexRel));
+
+@@ -932,6 +950,12 @@ brin_summarize_range(PG_FUNCTION_ARGS)
+ /* OK, do it */
+ brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
+
++ /* Roll back any GUC changes executed by index functions */
++ AtEOXact_GUC(false, save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(save_userid, save_sec_context);
++
+ relation_close(indexRel, ShareUpdateExclusiveLock);
+ relation_close(heapRel, ShareUpdateExclusiveLock);
+
+@@ -973,6 +997,9 @@ brin_desummarize_range(PG_FUNCTION_ARGS)
+ * passed indexoid isn't an index then IndexGetRelation() will fail.
+ * Rather than emitting a not-very-helpful error message, postpone
+ * complaining, expecting that the is-it-an-index test below will fail.
++ *
++ * Unlike brin_summarize_range(), autovacuum never calls this. Hence, we
++ * don't switch userid.
+ */
+ heapoid = IndexGetRelation(indexoid, true);
+ if (OidIsValid(heapoid))
+diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
+index 3ece136..0333bfd 100644
+--- a/src/backend/catalog/index.c
++++ b/src/backend/catalog/index.c
+@@ -1400,6 +1400,9 @@ index_concurrently_build(Oid heapRelationId,
+ Oid indexRelationId)
+ {
+ Relation heapRel;
++ Oid save_userid;
++ int save_sec_context;
++ int save_nestlevel;
+ Relation indexRelation;
+ IndexInfo *indexInfo;
+
+@@ -1409,7 +1412,16 @@ index_concurrently_build(Oid heapRelationId,
+ /* Open and lock the parent heap relation */
+ heapRel = table_open(heapRelationId, ShareUpdateExclusiveLock);
+
+- /* And the target index relation */
++ /*
++ * Switch to the table owner's userid, so that any index functions are run
++ * as that user. Also lock down security-restricted operations and
++ * arrange to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(heapRel->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++
+ indexRelation = index_open(indexRelationId, RowExclusiveLock);
+
+ /*
+@@ -1425,6 +1437,12 @@ index_concurrently_build(Oid heapRelationId,
+ /* Now build the index */
+ index_build(heapRel, indexRelation, indexInfo, false, true);
+
++ /* Roll back any GUC changes executed by index functions */
++ AtEOXact_GUC(false, save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(save_userid, save_sec_context);
++
+ /* Close both the relations, but keep the locks */
+ table_close(heapRel, NoLock);
+ index_close(indexRelation, NoLock);
+@@ -3271,7 +3289,17 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
+
+ /* Open and lock the parent heap relation */
+ heapRelation = table_open(heapId, ShareUpdateExclusiveLock);
+- /* And the target index relation */
++
++ /*
++ * Switch to the table owner's userid, so that any index functions are run
++ * as that user. Also lock down security-restricted operations and
++ * arrange to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++
+ indexRelation = index_open(indexId, RowExclusiveLock);
+
+ /*
+@@ -3284,16 +3312,6 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
+ /* mark build is concurrent just for consistency */
+ indexInfo->ii_Concurrent = true;
+
+- /*
+- * Switch to the table owner's userid, so that any index functions are run
+- * as that user. Also lock down security-restricted operations and
+- * arrange to make GUC variable changes local to this command.
+- */
+- GetUserIdAndSecContext(&save_userid, &save_sec_context);
+- SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
+- save_sec_context | SECURITY_RESTRICTED_OPERATION);
+- save_nestlevel = NewGUCNestLevel();
+-
+ /*
+ * Scan the index and gather up all the TIDs into a tuplesort object.
+ */
+@@ -3497,6 +3515,9 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
+ Relation iRel,
+ heapRelation;
+ Oid heapId;
++ Oid save_userid;
++ int save_sec_context;
++ int save_nestlevel;
+ IndexInfo *indexInfo;
+ volatile bool skipped_constraint = false;
+ PGRUsage ru0;
+@@ -3527,6 +3548,16 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
+ */
+ iRel = index_open(indexId, AccessExclusiveLock);
+
++ /*
++ * Switch to the table owner's userid, so that any index functions are run
++ * as that user. Also lock down security-restricted operations and
++ * arrange to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(heapRelation->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++
+ if (progress)
+ pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
+ iRel->rd_rel->relam);
+@@ -3684,12 +3715,18 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
+ errdetail_internal("%s",
+ pg_rusage_show(&ru0))));
+
+- if (progress)
+- pgstat_progress_end_command();
++ /* Roll back any GUC changes executed by index functions */
++ AtEOXact_GUC(false, save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(save_userid, save_sec_context);
+
+ /* Close rels, but keep locks */
+ index_close(iRel, NoLock);
+ table_close(heapRelation, NoLock);
++
++ if (progress)
++ pgstat_progress_end_command();
+ }
+
+ /*
+diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
+index bd6f408..74db03e 100644
+--- a/src/backend/commands/cluster.c
++++ b/src/backend/commands/cluster.c
+@@ -266,6 +266,9 @@ void
+ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ {
+ Relation OldHeap;
++ Oid save_userid;
++ int save_sec_context;
++ int save_nestlevel;
+ bool verbose = ((options & CLUOPT_VERBOSE) != 0);
+ bool recheck = ((options & CLUOPT_RECHECK) != 0);
+
+@@ -295,6 +298,16 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ return;
+ }
+
++ /*
++ * Switch to the table owner's userid, so that any index functions are run
++ * as that user. Also lock down security-restricted operations and
++ * arrange to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(OldHeap->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++
+ /*
+ * Since we may open a new transaction for each relation, we have to check
+ * that the relation still is what we think it is.
+@@ -309,11 +322,10 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ Form_pg_index indexForm;
+
+ /* Check that the user still owns the relation */
+- if (!pg_class_ownercheck(tableOid, GetUserId()))
++ if (!pg_class_ownercheck(tableOid, save_userid))
+ {
+ relation_close(OldHeap, AccessExclusiveLock);
+- pgstat_progress_end_command();
+- return;
++ goto out;
+ }
+
+ /*
+@@ -327,8 +339,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ if (RELATION_IS_OTHER_TEMP(OldHeap))
+ {
+ relation_close(OldHeap, AccessExclusiveLock);
+- pgstat_progress_end_command();
+- return;
++ goto out;
+ }
+
+ if (OidIsValid(indexOid))
+@@ -339,8 +350,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid)))
+ {
+ relation_close(OldHeap, AccessExclusiveLock);
+- pgstat_progress_end_command();
+- return;
++ goto out;
+ }
+
+ /*
+@@ -350,8 +360,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ if (!HeapTupleIsValid(tuple)) /* probably can't happen */
+ {
+ relation_close(OldHeap, AccessExclusiveLock);
+- pgstat_progress_end_command();
+- return;
++ goto out;
+ }
+ indexForm = (Form_pg_index) GETSTRUCT(tuple);
+ if (!indexForm->indisclustered)
+@@ -413,8 +422,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+ !RelationIsPopulated(OldHeap))
+ {
+ relation_close(OldHeap, AccessExclusiveLock);
+- pgstat_progress_end_command();
+- return;
++ goto out;
+ }
+
+ /*
+@@ -430,6 +438,13 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
+
+ /* NB: rebuild_relation does table_close() on OldHeap */
+
++out:
++ /* Roll back any GUC changes executed by index functions */
++ AtEOXact_GUC(false, save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(save_userid, save_sec_context);
++
+ pgstat_progress_end_command();
+ }
+
+diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
+index be1cf8c..167b377 100644
+--- a/src/backend/commands/indexcmds.c
++++ b/src/backend/commands/indexcmds.c
+@@ -470,21 +470,22 @@ DefineIndex(Oid relationId,
+ LOCKTAG heaplocktag;
+ LOCKMODE lockmode;
+ Snapshot snapshot;
+- int save_nestlevel = -1;
++ Oid root_save_userid;
++ int root_save_sec_context;
++ int root_save_nestlevel;
+ int i;
+
++ root_save_nestlevel = NewGUCNestLevel();
++
+ /*
+ * Some callers need us to run with an empty default_tablespace; this is a
+ * necessary hack to be able to reproduce catalog state accurately when
+ * recreating indexes after table-rewriting ALTER TABLE.
+ */
+ if (stmt->reset_default_tblspc)
+- {
+- save_nestlevel = NewGUCNestLevel();
+ (void) set_config_option("default_tablespace", "",
+ PGC_USERSET, PGC_S_SESSION,
+ GUC_ACTION_SAVE, true, 0, false);
+- }
+
+ /*
+ * Force non-concurrent build on temporary relations, even if CONCURRENTLY
+@@ -563,6 +564,15 @@ DefineIndex(Oid relationId,
+ lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
+ rel = table_open(relationId, lockmode);
+
++ /*
++ * Switch to the table owner's userid, so that any index functions are run
++ * as that user. Also lock down security-restricted operations. We
++ * already arranged to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&root_save_userid, &root_save_sec_context);
++ SetUserIdAndSecContext(rel->rd_rel->relowner,
++ root_save_sec_context | SECURITY_RESTRICTED_OPERATION);
++
+ namespaceId = RelationGetNamespace(rel);
+
+ /* Ensure that it makes sense to index this kind of relation */
+@@ -648,7 +658,7 @@ DefineIndex(Oid relationId,
+ {
+ AclResult aclresult;
+
+- aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
++ aclresult = pg_namespace_aclcheck(namespaceId, root_save_userid,
+ ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_SCHEMA,
+@@ -680,7 +690,7 @@ DefineIndex(Oid relationId,
+ {
+ AclResult aclresult;
+
+- aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
++ aclresult = pg_tablespace_aclcheck(tablespaceId, root_save_userid,
+ ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_TABLESPACE,
+@@ -1066,15 +1076,17 @@ DefineIndex(Oid relationId,
+
+ ObjectAddressSet(address, RelationRelationId, indexRelationId);
+
+- /*
+- * Revert to original default_tablespace. Must do this before any return
+- * from this function, but after index_create, so this is a good time.
+- */
+- if (save_nestlevel >= 0)
+- AtEOXact_GUC(true, save_nestlevel);
+-
+ if (!OidIsValid(indexRelationId))
+ {
++ /*
++ * Roll back any GUC changes executed by index functions. Also revert
++ * to original default_tablespace if we changed it above.
++ */
++ AtEOXact_GUC(false, root_save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
++
+ table_close(rel, NoLock);
+
+ /* If this is the top-level index, we're done */
+@@ -1084,6 +1096,17 @@ DefineIndex(Oid relationId,
+ return address;
+ }
+
++ /*
++ * Roll back any GUC changes executed by index functions, and keep
++ * subsequent changes local to this command. It's barely possible that
++ * some index function changed a behavior-affecting GUC, e.g. xmloption,
++ * that affects subsequent steps. This improves bug-compatibility with
++ * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
++ * purpose of clearing the above default_tablespace change.
++ */
++ AtEOXact_GUC(false, root_save_nestlevel);
++ root_save_nestlevel = NewGUCNestLevel();
++
+ /* Add any requested comment */
+ if (stmt->idxcomment != NULL)
+ CreateComments(indexRelationId, RelationRelationId, 0,
+@@ -1130,6 +1153,9 @@ DefineIndex(Oid relationId,
+ {
+ Oid childRelid = part_oids[i];
+ Relation childrel;
++ Oid child_save_userid;
++ int child_save_sec_context;
++ int child_save_nestlevel;
+ List *childidxs;
+ ListCell *cell;
+ AttrNumber *attmap;
+@@ -1138,6 +1164,12 @@ DefineIndex(Oid relationId,
+
+ childrel = table_open(childRelid, lockmode);
+
++ GetUserIdAndSecContext(&child_save_userid,
++ &child_save_sec_context);
++ SetUserIdAndSecContext(childrel->rd_rel->relowner,
++ child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ child_save_nestlevel = NewGUCNestLevel();
++
+ /*
+ * Don't try to create indexes on foreign tables, though. Skip
+ * those if a regular index, or fail if trying to create a
+@@ -1153,6 +1185,9 @@ DefineIndex(Oid relationId,
+ errdetail("Table \"%s\" contains partitions that are foreign tables.",
+ RelationGetRelationName(rel))));
+
++ AtEOXact_GUC(false, child_save_nestlevel);
++ SetUserIdAndSecContext(child_save_userid,
++ child_save_sec_context);
+ table_close(childrel, lockmode);
+ continue;
+ }
+@@ -1226,6 +1261,9 @@ DefineIndex(Oid relationId,
+ }
+
+ list_free(childidxs);
++ AtEOXact_GUC(false, child_save_nestlevel);
++ SetUserIdAndSecContext(child_save_userid,
++ child_save_sec_context);
+ table_close(childrel, NoLock);
+
+ /*
+@@ -1280,12 +1318,21 @@ DefineIndex(Oid relationId,
+ if (found_whole_row)
+ elog(ERROR, "cannot convert whole-row table reference");
+
++ /*
++ * Recurse as the starting user ID. Callee will use that
++ * for permission checks, then switch again.
++ */
++ Assert(GetUserId() == child_save_userid);
++ SetUserIdAndSecContext(root_save_userid,
++ root_save_sec_context);
+ DefineIndex(childRelid, childStmt,
+ InvalidOid, /* no predefined OID */
+ indexRelationId, /* this is our child */
+ createdConstraintId,
+ is_alter_table, check_rights, check_not_in_use,
+ skip_build, quiet);
++ SetUserIdAndSecContext(child_save_userid,
++ child_save_sec_context);
+ }
+
+ pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_DONE,
+@@ -1322,12 +1369,17 @@ DefineIndex(Oid relationId,
+ * Indexes on partitioned tables are not themselves built, so we're
+ * done here.
+ */
++ AtEOXact_GUC(false, root_save_nestlevel);
++ SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
+ table_close(rel, NoLock);
+ if (!OidIsValid(parentIndexId))
+ pgstat_progress_end_command();
+ return address;
+ }
+
++ AtEOXact_GUC(false, root_save_nestlevel);
++ SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
++
+ if (!concurrent)
+ {
+ /* Close the heap and we're done, in the non-concurrent case */
+@@ -3040,6 +3092,9 @@ ReindexRelationConcurrently(Oid relationOid, int options)
+ Oid newIndexId;
+ Relation indexRel;
+ Relation heapRel;
++ Oid save_userid;
++ int save_sec_context;
++ int save_nestlevel;
+ Relation newIndexRel;
+ LockRelId *lockrelid;
+
+@@ -3047,6 +3102,16 @@ ReindexRelationConcurrently(Oid relationOid, int options)
+ heapRel = table_open(indexRel->rd_index->indrelid,
+ ShareUpdateExclusiveLock);
+
++ /*
++ * Switch to the table owner's userid, so that any index functions are
++ * run as that user. Also lock down security-restricted operations
++ * and arrange to make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(heapRel->rd_rel->relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
++
+ /* This function shouldn't be called for temporary relations. */
+ if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+ elog(ERROR, "cannot reindex a temporary table concurrently");
+@@ -3101,6 +3166,13 @@ ReindexRelationConcurrently(Oid relationOid, int options)
+
+ index_close(indexRel, NoLock);
+ index_close(newIndexRel, NoLock);
++
++ /* Roll back any GUC changes executed by index functions */
++ AtEOXact_GUC(false, save_nestlevel);
++
++ /* Restore userid and security context */
++ SetUserIdAndSecContext(save_userid, save_sec_context);
++
+ table_close(heapRel, NoLock);
+ }
+
+diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
+index 80e9ec0..e485661 100644
+--- a/src/backend/commands/matview.c
++++ b/src/backend/commands/matview.c
+@@ -167,6 +167,17 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
+ lockmode, 0,
+ RangeVarCallbackOwnsTable, NULL);
+ matviewRel = table_open(matviewOid, NoLock);
++ relowner = matviewRel->rd_rel->relowner;
++
++ /*
++ * Switch to the owner's userid, so that any functions are run as that
++ * user. Also lock down security-restricted operations and arrange to
++ * make GUC variable changes local to this command.
++ */
++ GetUserIdAndSecContext(&save_userid, &save_sec_context);
++ SetUserIdAndSecContext(relowner,
++ save_sec_context | SECURITY_RESTRICTED_OPERATION);
++ save_nestlevel = NewGUCNestLevel();
+
+ /* Make sure it is a materialized view. */
+ if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW)
+@@ -268,19 +279,6 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
+ */
+ SetMatViewPopulatedState(matviewRel, !stmt->skipData);
+
+- relowner = matviewRel->rd_rel->relowner;
+-
+- /*
+- * Switch to the owner's userid, so that any functions are run as that
+- * user. Also arrange to make GUC variable changes local to this command.
+- * Don't lock it down too tight to create a temporary table just yet. We
+- * will switch modes when we are about to execute user code.
+- */
+- GetUserIdAndSecContext(&save_userid, &save_sec_context);
+- SetUserIdAndSecContext(relowner,
+- save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
+- save_nestlevel = NewGUCNestLevel();
+-
+ /* Concurrent refresh builds new data in temp tablespace, and does diff. */
+ if (concurrent)
+ {
+@@ -303,12 +301,6 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
+ LockRelationOid(OIDNewHeap, AccessExclusiveLock);
+ dest = CreateTransientRelDestReceiver(OIDNewHeap);
+
+- /*
+- * Now lock down security-restricted operations.
+- */
+- SetUserIdAndSecContext(relowner,
+- save_sec_context | SECURITY_RESTRICTED_OPERATION);
+-
+ /* Generate the data, if wanted. */
+ if (!stmt->skipData)
+ processed = refresh_matview_datafill(dest, dataQuery, queryString);
+diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
+index de554e2..c9f858e 100644
+--- a/src/backend/utils/init/miscinit.c
++++ b/src/backend/utils/init/miscinit.c
+@@ -455,15 +455,21 @@ GetAuthenticatedUserId(void)
+ * with guc.c's internal state, so SET ROLE has to be disallowed.
+ *
+ * SECURITY_RESTRICTED_OPERATION indicates that we are inside an operation
+- * that does not wish to trust called user-defined functions at all. This
+- * bit prevents not only SET ROLE, but various other changes of session state
+- * that normally is unprotected but might possibly be used to subvert the
+- * calling session later. An example is replacing an existing prepared
+- * statement with new code, which will then be executed with the outer
+- * session's permissions when the prepared statement is next used. Since
+- * these restrictions are fairly draconian, we apply them only in contexts
+- * where the called functions are really supposed to be side-effect-free
+- * anyway, such as VACUUM/ANALYZE/REINDEX.
++ * that does not wish to trust called user-defined functions at all. The
++ * policy is to use this before operations, e.g. autovacuum and REINDEX, that
++ * enumerate relations of a database or schema and run functions associated
++ * with each found relation. The relation owner is the new user ID. Set this
++ * as soon as possible after locking the relation. Restore the old user ID as
++ * late as possible before closing the relation; restoring it shortly after
++ * close is also tolerable. If a command has both relation-enumerating and
++ * non-enumerating modes, e.g. ANALYZE, both modes set this bit. This bit
++ * prevents not only SET ROLE, but various other changes of session state that
++ * normally is unprotected but might possibly be used to subvert the calling
++ * session later. An example is replacing an existing prepared statement with
++ * new code, which will then be executed with the outer session's permissions
++ * when the prepared statement is next used. These restrictions are fairly
++ * draconian, but the functions called in relation-enumerating operations are
++ * really supposed to be side-effect-free anyway.
+ *
+ * SECURITY_NOFORCE_RLS indicates that we are inside an operation which should
+ * ignore the FORCE ROW LEVEL SECURITY per-table indication. This is used to
+diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
+index 186d2fb..0f0c1b3 100644
+--- a/src/test/regress/expected/privileges.out
++++ b/src/test/regress/expected/privileges.out
+@@ -1336,6 +1336,61 @@ SELECT has_table_privilege('regress_priv_user1', 'atest4', 'SELECT WITH GRANT OP
+ -- security-restricted operations
+ \c -
+ CREATE ROLE regress_sro_user;
++-- Check that index expressions and predicates are run as the table's owner
++-- A dummy index function checking current_user
++CREATE FUNCTION sro_ifun(int) RETURNS int AS $$
++BEGIN
++ -- Below we set the table's owner to regress_sro_user
++ ASSERT current_user = 'regress_sro_user',
++ format('sro_ifun(%s) called by %s', $1, current_user);
++ RETURN $1;
++END;
++$$ LANGUAGE plpgsql IMMUTABLE;
++-- Create a table owned by regress_sro_user
++CREATE TABLE sro_tab (a int);
++ALTER TABLE sro_tab OWNER TO regress_sro_user;
++INSERT INTO sro_tab VALUES (1), (2), (3);
++-- Create an expression index with a predicate
++CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
++ WHERE sro_ifun(a + 10) > sro_ifun(10);
++DROP INDEX sro_idx;
++-- Do the same concurrently
++CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
++ WHERE sro_ifun(a + 10) > sro_ifun(10);
++-- REINDEX
++REINDEX TABLE sro_tab;
++REINDEX INDEX sro_idx;
++REINDEX TABLE CONCURRENTLY sro_tab;
++DROP INDEX sro_idx;
++-- CLUSTER
++CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)));
++CLUSTER sro_tab USING sro_cluster_idx;
++DROP INDEX sro_cluster_idx;
++-- BRIN index
++CREATE INDEX sro_brin ON sro_tab USING brin ((sro_ifun(a) + sro_ifun(0)));
++SELECT brin_desummarize_range('sro_brin', 0);
++ brin_desummarize_range
++------------------------
++
++(1 row)
++
++SELECT brin_summarize_range('sro_brin', 0);
++ brin_summarize_range
++----------------------
++ 1
++(1 row)
++
++DROP TABLE sro_tab;
++-- Check with a partitioned table
++CREATE TABLE sro_ptab (a int) PARTITION BY RANGE (a);
++ALTER TABLE sro_ptab OWNER TO regress_sro_user;
++CREATE TABLE sro_part PARTITION OF sro_ptab FOR VALUES FROM (1) TO (10);
++ALTER TABLE sro_part OWNER TO regress_sro_user;
++INSERT INTO sro_ptab VALUES (1), (2), (3);
++CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0)))
++ WHERE sro_ifun(a + 10) > sro_ifun(10);
++REINDEX TABLE sro_ptab;
++REINDEX INDEX CONCURRENTLY sro_pidx;
+ SET SESSION AUTHORIZATION regress_sro_user;
+ CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
+ 'GRANT regress_priv_group2 TO regress_sro_user';
+@@ -1373,6 +1428,22 @@ CONTEXT: SQL function "unwanted_grant" statement 1
+ SQL statement "SELECT unwanted_grant()"
+ PL/pgSQL function sro_trojan() line 1 at PERFORM
+ SQL function "mv_action" statement 1
++-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
++SET SESSION AUTHORIZATION regress_sro_user;
++CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
++ IMMUTABLE LANGUAGE plpgsql AS $$
++BEGIN
++ PERFORM unwanted_grant();
++ RAISE WARNING 'owned';
++ RETURN 1;
++EXCEPTION WHEN OTHERS THEN
++ RETURN 2;
++END$$;
++CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c;
++CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0;
++\c -
++REFRESH MATERIALIZED VIEW CONCURRENTLY sro_index_mv;
++REFRESH MATERIALIZED VIEW sro_index_mv;
+ DROP OWNED BY regress_sro_user;
+ DROP ROLE regress_sro_user;
+ -- Admin options
+diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
+index 34fbf0e..c0b88a6 100644
+--- a/src/test/regress/sql/privileges.sql
++++ b/src/test/regress/sql/privileges.sql
+@@ -826,6 +826,53 @@ SELECT has_table_privilege('regress_priv_user1', 'atest4', 'SELECT WITH GRANT OP
+ \c -
+ CREATE ROLE regress_sro_user;
+
++-- Check that index expressions and predicates are run as the table's owner
++
++-- A dummy index function checking current_user
++CREATE FUNCTION sro_ifun(int) RETURNS int AS $$
++BEGIN
++ -- Below we set the table's owner to regress_sro_user
++ ASSERT current_user = 'regress_sro_user',
++ format('sro_ifun(%s) called by %s', $1, current_user);
++ RETURN $1;
++END;
++$$ LANGUAGE plpgsql IMMUTABLE;
++-- Create a table owned by regress_sro_user
++CREATE TABLE sro_tab (a int);
++ALTER TABLE sro_tab OWNER TO regress_sro_user;
++INSERT INTO sro_tab VALUES (1), (2), (3);
++-- Create an expression index with a predicate
++CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
++ WHERE sro_ifun(a + 10) > sro_ifun(10);
++DROP INDEX sro_idx;
++-- Do the same concurrently
++CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
++ WHERE sro_ifun(a + 10) > sro_ifun(10);
++-- REINDEX
++REINDEX TABLE sro_tab;
++REINDEX INDEX sro_idx;
++REINDEX TABLE CONCURRENTLY sro_tab;
++DROP INDEX sro_idx;
++-- CLUSTER
++CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)));
++CLUSTER sro_tab USING sro_cluster_idx;
++DROP INDEX sro_cluster_idx;
++-- BRIN index
++CREATE INDEX sro_brin ON sro_tab USING brin ((sro_ifun(a) + sro_ifun(0)));
++SELECT brin_desummarize_range('sro_brin', 0);
++SELECT brin_summarize_range('sro_brin', 0);
++DROP TABLE sro_tab;
++-- Check with a partitioned table
++CREATE TABLE sro_ptab (a int) PARTITION BY RANGE (a);
++ALTER TABLE sro_ptab OWNER TO regress_sro_user;
++CREATE TABLE sro_part PARTITION OF sro_ptab FOR VALUES FROM (1) TO (10);
++ALTER TABLE sro_part OWNER TO regress_sro_user;
++INSERT INTO sro_ptab VALUES (1), (2), (3);
++CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0)))
++ WHERE sro_ifun(a + 10) > sro_ifun(10);
++REINDEX TABLE sro_ptab;
++REINDEX INDEX CONCURRENTLY sro_pidx;
++
+ SET SESSION AUTHORIZATION regress_sro_user;
+ CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
+ 'GRANT regress_priv_group2 TO regress_sro_user';
+@@ -852,6 +899,23 @@ REFRESH MATERIALIZED VIEW sro_mv;
+ REFRESH MATERIALIZED VIEW sro_mv;
+ BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
+
++-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
++SET SESSION AUTHORIZATION regress_sro_user;
++CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
++ IMMUTABLE LANGUAGE plpgsql AS $$
++BEGIN
++ PERFORM unwanted_grant();
++ RAISE WARNING 'owned';
++ RETURN 1;
++EXCEPTION WHEN OTHERS THEN
++ RETURN 2;
++END$$;
++CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c;
++CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0;
++\c -
++REFRESH MATERIALIZED VIEW CONCURRENTLY sro_index_mv;
++REFRESH MATERIALIZED VIEW sro_index_mv;
++
+ DROP OWNED BY regress_sro_user;
+ DROP ROLE regress_sro_user;
+
+--
+2.25.1
+
diff --git a/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb b/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb
index 67bf2b9604..1344d4eb00 100644
--- a/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb
+++ b/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb
@@ -7,6 +7,7 @@ SRC_URI += "\
file://0001-Add-support-for-RISC-V.patch \
file://0001-Improve-reproducibility.patch \
file://remove_duplicate.patch \
+ file://CVE-2022-1552.patch \
"
SRC_URI[sha256sum] = "89fda2de33ed04a98548e43f3ee5f15b882be17505d631fe0dd1a540a2b56dce"
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2021-44532.patch b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2021-44532.patch
deleted file mode 100644
index dff7fe23a2..0000000000
--- a/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2021-44532.patch
+++ /dev/null
@@ -1,3090 +0,0 @@
-From 19873abfb24dce75ffff042efe76dc5633052677 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
-Date: Wed, 29 Dec 2021 19:30:57 -0500
-Subject: [PATCH] crypto,tls: implement safe x509 GeneralName format
-
-This change introduces JSON-compatible escaping rules for strings that
-include X.509 GeneralName components (see RFC 5280). This non-standard
-format avoids ambiguities and prevents injection attacks that could
-previously lead to X.509 certificates being accepted even though they
-were not valid for the target hostname.
-
-These changes affect the format of subject alternative names and the
-format of authority information access. The checkServerIdentity function
-has been modified to safely handle the new format, eliminating the
-possibility of injecting subject alternative names into the verification
-logic.
-
-Because each subject alternative name is only encoded as a JSON string
-literal if necessary for security purposes, this change will only be
-visible in rare cases.
-
-This addresses CVE-2021-44532.
-
-Co-authored-by: Akshay K <iit.akshay@gmail.com>
-CVE-ID: CVE-2021-44532
-Backport-PR-URL: https://github.com/nodejs-private/node-private/pull/306
-PR-URL: https://github.com/nodejs-private/node-private/pull/300
-Reviewed-By: Michael Dawson <midawson@redhat.com>
-Reviewed-By: Rich Trott <rtrott@gmail.com>
-
-Upstream-Status: Backport [https://github.com/nodejs/node/commit/19873abfb24dce75ffff042efe76dc5633052677]
-
-CVE: CVE-2021-44532
-
-Signed-off-by: Virendra Thakur <virendra.thakur@kpit.com>
-
----
- doc/api/errors.md | 8 +
- lib/_tls_common.js | 9 +
- lib/internal/errors.js | 2 +
- lib/tls.js | 52 +-
- src/node_crypto_common.cc | 340 ++++++++++--
- test/common/index.js | 7 +
- test/fixtures/keys/Makefile | 14 +
- .../incorrect_san_correct_subject-cert.pem | 11 +
- .../incorrect_san_correct_subject-key.pem | 5 +
- test/fixtures/x509-escaping/.gitignore | 2 +
- test/fixtures/x509-escaping/alt-0-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-1-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-10-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-11-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-12-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-13-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-14-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-15-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-16-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-17-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-18-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-19-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-2-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-20-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-21-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-22-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-23-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-24-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-25-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-26-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-27-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-28-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-29-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-3-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-30-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-4-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-5-cert.pem | 29 +
- test/fixtures/x509-escaping/alt-6-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-7-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-8-cert.pem | 28 +
- test/fixtures/x509-escaping/alt-9-cert.pem | 28 +
- test/fixtures/x509-escaping/create-certs.js | 502 ++++++++++++++++++
- .../x509-escaping/google/intermediate.pem | 11 +
- test/fixtures/x509-escaping/google/key.pem | 5 +
- test/fixtures/x509-escaping/google/leaf0.pem | 10 +
- test/fixtures/x509-escaping/google/leaf1.pem | 10 +
- test/fixtures/x509-escaping/google/leaf2.pem | 10 +
- test/fixtures/x509-escaping/google/leaf3.pem | 10 +
- test/fixtures/x509-escaping/google/leaf4.pem | 10 +
- test/fixtures/x509-escaping/google/root.pem | 9 +
- test/fixtures/x509-escaping/info-0-cert.pem | 30 ++
- test/fixtures/x509-escaping/info-1-cert.pem | 31 ++
- test/fixtures/x509-escaping/info-2-cert.pem | 29 +
- test/fixtures/x509-escaping/info-3-cert.pem | 30 ++
- test/fixtures/x509-escaping/info-4-cert.pem | 29 +
- test/fixtures/x509-escaping/package.json | 12 +
- test/fixtures/x509-escaping/server-key.pem | 52 ++
- test/parallel/test-tls-0-dns-altname.js | 2 +-
- test/parallel/test-x509-escaping.js | 349 ++++++++++++
- 59 files changed, 2429 insertions(+), 42 deletions(-)
- create mode 100644 test/fixtures/keys/incorrect_san_correct_subject-cert.pem
- create mode 100644 test/fixtures/keys/incorrect_san_correct_subject-key.pem
- create mode 100644 test/fixtures/x509-escaping/.gitignore
- create mode 100644 test/fixtures/x509-escaping/alt-0-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-1-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-10-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-11-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-12-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-13-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-14-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-15-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-16-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-17-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-18-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-19-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-2-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-20-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-21-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-22-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-23-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-24-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-25-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-26-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-27-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-28-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-29-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-3-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-30-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-4-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-5-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-6-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-7-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-8-cert.pem
- create mode 100644 test/fixtures/x509-escaping/alt-9-cert.pem
- create mode 100644 test/fixtures/x509-escaping/create-certs.js
- create mode 100644 test/fixtures/x509-escaping/google/intermediate.pem
- create mode 100644 test/fixtures/x509-escaping/google/key.pem
- create mode 100644 test/fixtures/x509-escaping/google/leaf0.pem
- create mode 100644 test/fixtures/x509-escaping/google/leaf1.pem
- create mode 100644 test/fixtures/x509-escaping/google/leaf2.pem
- create mode 100644 test/fixtures/x509-escaping/google/leaf3.pem
- create mode 100644 test/fixtures/x509-escaping/google/leaf4.pem
- create mode 100644 test/fixtures/x509-escaping/google/root.pem
- create mode 100644 test/fixtures/x509-escaping/info-0-cert.pem
- create mode 100644 test/fixtures/x509-escaping/info-1-cert.pem
- create mode 100644 test/fixtures/x509-escaping/info-2-cert.pem
- create mode 100644 test/fixtures/x509-escaping/info-3-cert.pem
- create mode 100644 test/fixtures/x509-escaping/info-4-cert.pem
- create mode 100644 test/fixtures/x509-escaping/package.json
- create mode 100644 test/fixtures/x509-escaping/server-key.pem
- create mode 100644 test/parallel/test-x509-escaping.js
-
-diff --git a/doc/api/errors.md b/doc/api/errors.md
-index d5d8e1efa7..9d176d9048 100644
---- a/doc/api/errors.md
-+++ b/doc/api/errors.md
-@@ -1869,6 +1869,14 @@ An unspecified or non-specific system error has occurred within the Node.js
- process. The error object will have an `err.info` object property with
- additional details.
-
-+<a id="ERR_TLS_CERT_ALTNAME_FORMAT"></a>
-+### `ERR_TLS_CERT_ALTNAME_FORMAT`
-+
-+This error is thrown by `checkServerIdentity` if a user-supplied
-+`subjectaltname` property violates encoding rules. Certificate objects produced
-+by Node.js itself always comply with encoding rules and will never cause
-+this error.
-+
- <a id="ERR_TLS_CERT_ALTNAME_INVALID"></a>
- ### `ERR_TLS_CERT_ALTNAME_INVALID`
-
-diff --git a/lib/_tls_common.js b/lib/_tls_common.js
-index b7a3b70a24..a2a74813f1 100644
---- a/lib/_tls_common.js
-+++ b/lib/_tls_common.js
-@@ -23,6 +23,7 @@
-
- const {
- ArrayIsArray,
-+ JSONParse,
- ObjectCreate,
- } = primordials;
-
-@@ -323,6 +324,14 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) {
-
- // XXX: More key validation?
- info.replace(/([^\n:]*):([^\n]*)(?:\n|$)/g, (all, key, val) => {
-+ if (val.charCodeAt(0) === 0x22) {
-+ // The translatePeerCertificate function is only
-+ // used on internally created legacy certificate
-+ // objects, and any value that contains a quote
-+ // will always be a valid JSON string literal,
-+ // so this should never throw.
-+ val = JSONParse(val);
-+ }
- if (key in c.infoAccess)
- c.infoAccess[key].push(val);
- else
-diff --git a/lib/internal/errors.js b/lib/internal/errors.js
-index 2cf7df436b..cd7153ad1a 100644
---- a/lib/internal/errors.js
-+++ b/lib/internal/errors.js
-@@ -1345,6 +1345,8 @@ E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode', Error);
- E('ERR_STREAM_WRITE_AFTER_END', 'write after end', Error);
- E('ERR_SYNTHETIC', 'JavaScript Callstack', Error);
- E('ERR_SYSTEM_ERROR', 'A system error occurred', SystemError);
-+E('ERR_TLS_CERT_ALTNAME_FORMAT', 'Invalid subject alternative name string',
-+ SyntaxError);
- E('ERR_TLS_CERT_ALTNAME_INVALID', function(reason, host, cert) {
- this.reason = reason;
- this.host = host;
-diff --git a/lib/tls.js b/lib/tls.js
-index 2ccbe409c9..cefb47d10f 100644
---- a/lib/tls.js
-+++ b/lib/tls.js
-@@ -24,11 +24,19 @@
- const {
- Array,
- ArrayIsArray,
-+ ArrayPrototypePush,
-+ JSONParse,
- ObjectDefineProperty,
- ObjectFreeze,
-+ RegExpPrototypeExec,
-+ StringPrototypeIncludes,
-+ StringPrototypeIndexOf,
-+ StringPrototypeSplit,
-+ StringPrototypeSubstring,
- } = primordials;
-
- const {
-+ ERR_TLS_CERT_ALTNAME_FORMAT,
- ERR_TLS_CERT_ALTNAME_INVALID,
- ERR_OUT_OF_RANGE
- } = require('internal/errors').codes;
-@@ -207,6 +215,45 @@ function check(hostParts, pattern, wildcards) {
- return true;
- }
-
-+// This pattern is used to determine the length of escaped sequences within
-+// the subject alt names string. It allows any valid JSON string literal.
-+// This MUST match the JSON specification (ECMA-404 / RFC8259) exactly.
-+const jsonStringPattern =
-+ // eslint-disable-next-line no-control-regex
-+ /^"(?:[^"\\\u0000-\u001f]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4}))*"/;
-+
-+function splitEscapedAltNames(altNames) {
-+ const result = [];
-+ let currentToken = '';
-+ let offset = 0;
-+ while (offset !== altNames.length) {
-+ const nextSep = StringPrototypeIndexOf(altNames, ', ', offset);
-+ const nextQuote = StringPrototypeIndexOf(altNames, '"', offset);
-+ if (nextQuote !== -1 && (nextSep === -1 || nextQuote < nextSep)) {
-+ // There is a quote character and there is no separator before the quote.
-+ currentToken += StringPrototypeSubstring(altNames, offset, nextQuote);
-+ const match = RegExpPrototypeExec(
-+ jsonStringPattern, StringPrototypeSubstring(altNames, nextQuote));
-+ if (!match) {
-+ throw new ERR_TLS_CERT_ALTNAME_FORMAT();
-+ }
-+ currentToken += JSONParse(match[0]);
-+ offset = nextQuote + match[0].length;
-+ } else if (nextSep !== -1) {
-+ // There is a separator and no quote before it.
-+ currentToken += StringPrototypeSubstring(altNames, offset, nextSep);
-+ ArrayPrototypePush(result, currentToken);
-+ currentToken = '';
-+ offset = nextSep + 2;
-+ } else {
-+ currentToken += StringPrototypeSubstring(altNames, offset);
-+ offset = altNames.length;
-+ }
-+ }
-+ ArrayPrototypePush(result, currentToken);
-+ return result;
-+}
-+
- let urlWarningEmitted = false;
- exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
- const subject = cert.subject;
-@@ -218,7 +265,10 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
- hostname = '' + hostname;
-
- if (altNames) {
-- for (const name of altNames.split(', ')) {
-+ const splitAltNames = StringPrototypeIncludes(altNames, '"') ?
-+ splitEscapedAltNames(altNames) :
-+ StringPrototypeSplit(altNames, ', ');
-+ for (const name of splitAltNames) {
- if (name.startsWith('DNS:')) {
- dnsNames.push(name.slice(4));
- } else if (name.startsWith('URI:')) {
-diff --git a/src/node_crypto_common.cc b/src/node_crypto_common.cc
-index 74bc0a9756..53fbc576ef 100644
---- a/src/node_crypto_common.cc
-+++ b/src/node_crypto_common.cc
-@@ -480,39 +480,320 @@ void AddFingerprintDigest(
- }
- }
-
--bool SafeX509ExtPrint(const BIOPointer& out, X509_EXTENSION* ext) {
-- const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
-+static inline bool IsSafeAltName(const char* name, size_t length, bool utf8) {
-+ for (size_t i = 0; i < length; i++) {
-+ char c = name[i];
-+ switch (c) {
-+ case '"':
-+ case '\\':
-+ // These mess with encoding rules.
-+ // Fall through.
-+ case ',':
-+ // Commas make it impossible to split the list of subject alternative
-+ // names unambiguously, which is why we have to escape.
-+ // Fall through.
-+ case '\'':
-+ // Single quotes are unlikely to appear in any legitimate values, but they
-+ // could be used to make a value look like it was escaped (i.e., enclosed
-+ // in single/double quotes).
-+ return false;
-+ default:
-+ if (utf8) {
-+ // In UTF8 strings, we require escaping for any ASCII control character,
-+ // but NOT for non-ASCII characters. Note that all bytes of any code
-+ // point that consists of more than a single byte have their MSB set.
-+ if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
-+ return false;
-+ }
-+ } else {
-+ // Check if the char is a control character or non-ASCII character. Note
-+ // that char may or may not be a signed type. Regardless, non-ASCII
-+ // values will always be outside of this range.
-+ if (c < ' ' || c > '~') {
-+ return false;
-+ }
-+ }
-+ }
-+ }
-+ return true;
-+}
-
-- if (method != X509V3_EXT_get_nid(NID_subject_alt_name))
-- return false;
-+static inline void PrintAltName(const BIOPointer& out, const char* name,
-+ size_t length, bool utf8,
-+ const char* safe_prefix) {
-+ if (IsSafeAltName(name, length, utf8)) {
-+ // For backward-compatibility, append "safe" names without any
-+ // modifications.
-+ if (safe_prefix != nullptr) {
-+ BIO_printf(out.get(), "%s:", safe_prefix);
-+ }
-+ BIO_write(out.get(), name, length);
-+ } else {
-+ // If a name is not "safe", we cannot embed it without special
-+ // encoding. This does not usually happen, but we don't want to hide
-+ // it from the user either. We use JSON compatible escaping here.
-+ BIO_write(out.get(), "\"", 1);
-+ if (safe_prefix != nullptr) {
-+ BIO_printf(out.get(), "%s:", safe_prefix);
-+ }
-+ for (size_t j = 0; j < length; j++) {
-+ char c = static_cast<char>(name[j]);
-+ if (c == '\\') {
-+ BIO_write(out.get(), "\\\\", 2);
-+ } else if (c == '"') {
-+ BIO_write(out.get(), "\\\"", 2);
-+ } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) {
-+ // Note that the above condition explicitly excludes commas, which means
-+ // that those are encoded as Unicode escape sequences in the "else"
-+ // block. That is not strictly necessary, and Node.js itself would parse
-+ // it correctly either way. We only do this to account for third-party
-+ // code that might be splitting the string at commas (as Node.js itself
-+ // used to do).
-+ BIO_write(out.get(), &c, 1);
-+ } else {
-+ // Control character or non-ASCII character. We treat everything as
-+ // Latin-1, which corresponds to the first 255 Unicode code points.
-+ const char hex[] = "0123456789abcdef";
-+ char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] };
-+ BIO_write(out.get(), u, sizeof(u));
-+ }
-+ }
-+ BIO_write(out.get(), "\"", 1);
-+ }
-+}
-+
-+static inline void PrintLatin1AltName(const BIOPointer& out,
-+ const ASN1_IA5STRING* name,
-+ const char* safe_prefix = nullptr) {
-+ PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
-+ false, safe_prefix);
-+}
-+
-+static inline void PrintUtf8AltName(const BIOPointer& out,
-+ const ASN1_UTF8STRING* name,
-+ const char* safe_prefix = nullptr) {
-+ PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
-+ true, safe_prefix);
-+}
-+
-+// This function currently emulates the behavior of i2v_GENERAL_NAME in a safer
-+// and less ambiguous way.
-+// TODO(tniessen): gradually improve the format in the next major version(s)
-+static bool PrintGeneralName(const BIOPointer& out, const GENERAL_NAME* gen) {
-+ if (gen->type == GEN_DNS) {
-+ ASN1_IA5STRING* name = gen->d.dNSName;
-+ BIO_write(out.get(), "DNS:", 4);
-+ // Note that the preferred name syntax (see RFCs 5280 and 1034) with
-+ // wildcards is a subset of what we consider "safe", so spec-compliant DNS
-+ // names will never need to be escaped.
-+ PrintLatin1AltName(out, name);
-+ } else if (gen->type == GEN_EMAIL) {
-+ ASN1_IA5STRING* name = gen->d.rfc822Name;
-+ BIO_write(out.get(), "email:", 6);
-+ PrintLatin1AltName(out, name);
-+ } else if (gen->type == GEN_URI) {
-+ ASN1_IA5STRING* name = gen->d.uniformResourceIdentifier;
-+ BIO_write(out.get(), "URI:", 4);
-+ // The set of "safe" names was designed to include just about any URI,
-+ // with a few exceptions, most notably URIs that contains commas (see
-+ // RFC 2396). In other words, most legitimate URIs will not require
-+ // escaping.
-+ PrintLatin1AltName(out, name);
-+ } else if (gen->type == GEN_DIRNAME) {
-+ // For backward compatibility, use X509_NAME_oneline to print the
-+ // X509_NAME object. The format is non standard and should be avoided
-+ // elsewhere, but conveniently, the function produces ASCII and the output
-+ // is unlikely to contains commas or other characters that would require
-+ // escaping. With that in mind, note that it SHOULD NOT produce ASCII
-+ // output since an RFC5280 AttributeValue may be a UTF8String.
-+ // TODO(tniessen): switch to RFC2253 rules in a major release
-+ BIO_printf(out.get(), "DirName:");
-+ char oline[256];
-+ if (X509_NAME_oneline(gen->d.dirn, oline, sizeof(oline)) != nullptr) {
-+ PrintAltName(out, oline, strlen(oline), false, nullptr);
-+ } else {
-+ return false;
-+ }
-+ } else if (gen->type == GEN_IPADD) {
-+ BIO_printf(out.get(), "IP Address:");
-+ const ASN1_OCTET_STRING* ip = gen->d.ip;
-+ const unsigned char* b = ip->data;
-+ if (ip->length == 4) {
-+ BIO_printf(out.get(), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
-+ } else if (ip->length == 16) {
-+ for (unsigned int j = 0; j < 8; j++) {
-+ uint16_t pair = (b[2 * j] << 8) | b[2 * j + 1];
-+ BIO_printf(out.get(), (j == 0) ? "%X" : ":%X", pair);
-+ }
-+ } else {
-+#if OPENSSL_VERSION_MAJOR >= 3
-+ BIO_printf(out.get(), "<invalid length=%d>", ip->length);
-+#else
-+ BIO_printf(out.get(), "<invalid>");
-+#endif
-+ }
-+ } else if (gen->type == GEN_RID) {
-+ // TODO(tniessen): unlike OpenSSL's default implementation, never print the
-+ // OID as text and instead always print its numeric representation, which is
-+ // backward compatible in practice and more future proof (see OBJ_obj2txt).
-+ char oline[256];
-+ i2t_ASN1_OBJECT(oline, sizeof(oline), gen->d.rid);
-+ BIO_printf(out.get(), "Registered ID:%s", oline);
-+ } else if (gen->type == GEN_OTHERNAME) {
-+ // TODO(tniessen): the format that is used here is based on OpenSSL's
-+ // implementation of i2v_GENERAL_NAME (as of OpenSSL 3.0.1), mostly for
-+ // backward compatibility. It is somewhat awkward, especially when passed to
-+ // translatePeerCertificate, and should be changed in the future, probably
-+ // to the format used by GENERAL_NAME_print (in a major release).
-+ bool unicode = true;
-+ const char* prefix = nullptr;
-+ // OpenSSL 1.1.1 does not support othername in i2v_GENERAL_NAME and may not
-+ // define these NIDs.
-+#if OPENSSL_VERSION_MAJOR >= 3
-+ int nid = OBJ_obj2nid(gen->d.otherName->type_id);
-+ switch (nid) {
-+ case NID_id_on_SmtpUTF8Mailbox:
-+ prefix = " SmtpUTF8Mailbox:";
-+ break;
-+ case NID_XmppAddr:
-+ prefix = " XmppAddr:";
-+ break;
-+ case NID_SRVName:
-+ prefix = " SRVName:";
-+ unicode = false;
-+ break;
-+ case NID_ms_upn:
-+ prefix = " UPN:";
-+ break;
-+ case NID_NAIRealm:
-+ prefix = " NAIRealm:";
-+ break;
-+ }
-+#endif // OPENSSL_VERSION_MAJOR >= 3
-+ int val_type = gen->d.otherName->value->type;
-+ if (prefix == nullptr ||
-+ (unicode && val_type != V_ASN1_UTF8STRING) ||
-+ (!unicode && val_type != V_ASN1_IA5STRING)) {
-+ BIO_printf(out.get(), "othername:<unsupported>");
-+ } else {
-+ BIO_printf(out.get(), "othername:");
-+ if (unicode) {
-+ PrintUtf8AltName(out, gen->d.otherName->value->value.utf8string,
-+ prefix);
-+ } else {
-+ PrintLatin1AltName(out, gen->d.otherName->value->value.ia5string,
-+ prefix);
-+ }
-+ }
-+ } else if (gen->type == GEN_X400) {
-+ // TODO(tniessen): this is what OpenSSL does, implement properly instead
-+ BIO_printf(out.get(), "X400Name:<unsupported>");
-+ } else if (gen->type == GEN_EDIPARTY) {
-+ // TODO(tniessen): this is what OpenSSL does, implement properly instead
-+ BIO_printf(out.get(), "EdiPartyName:<unsupported>");
-+ } else {
-+ // This is safe because X509V3_EXT_d2i would have returned nullptr in this
-+ // case already.
-+ UNREACHABLE();
-+ }
-+
-+ return true;
-+}
-+
-+bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {
-+ const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
-+ CHECK(method == X509V3_EXT_get_nid(NID_subject_alt_name));
-
- GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(ext));
- if (names == nullptr)
- return false;
-
-+ bool ok = true;
-+
- for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) {
- GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i);
-
- if (i != 0)
- BIO_write(out.get(), ", ", 2);
-
-- if (gen->type == GEN_DNS) {
-- ASN1_IA5STRING* name = gen->d.dNSName;
--
-- BIO_write(out.get(), "DNS:", 4);
-- BIO_write(out.get(), name->data, name->length);
-- } else {
-- STACK_OF(CONF_VALUE)* nval = i2v_GENERAL_NAME(
-- const_cast<X509V3_EXT_METHOD*>(method), gen, nullptr);
-- if (nval == nullptr)
-- return false;
-- X509V3_EXT_val_prn(out.get(), nval, 0, 0);
-- sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
-+ if (!(ok = PrintGeneralName(out, gen))) {
-+ break;
- }
- }
- sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
-
-- return true;
-+ return ok;
-+}
-+
-+bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
-+ const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
-+ CHECK(method == X509V3_EXT_get_nid(NID_info_access));
-+
-+ AUTHORITY_INFO_ACCESS* descs =
-+ static_cast<AUTHORITY_INFO_ACCESS*>(X509V3_EXT_d2i(ext));
-+ if (descs == nullptr)
-+ return false;
-+
-+ bool ok = true;
-+
-+ for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) {
-+ ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i);
-+
-+ if (i != 0)
-+ BIO_write(out.get(), "\n", 1);
-+
-+ char objtmp[80];
-+ i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method);
-+ BIO_printf(out.get(), "%s - ", objtmp);
-+ if (!(ok = PrintGeneralName(out, desc->location))) {
-+ break;
-+ }
-+ }
-+ sk_ACCESS_DESCRIPTION_pop_free(descs, ACCESS_DESCRIPTION_free);
-+
-+#if OPENSSL_VERSION_MAJOR < 3
-+ BIO_write(out.get(), "\n", 1);
-+#endif
-+
-+ return ok;
-+}
-+
-+v8::MaybeLocal<v8::Value> GetSubjectAltNameString(
-+ Environment* env,
-+ const BIOPointer& bio,
-+ X509* cert) {
-+ int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
-+ if (index < 0)
-+ return Undefined(env->isolate());
-+
-+ X509_EXTENSION* ext = X509_get_ext(cert, index);
-+ CHECK_NOT_NULL(ext);
-+
-+ if (!SafeX509SubjectAltNamePrint(bio, ext)) {
-+ USE(BIO_reset(bio.get()));
-+ return v8::Null(env->isolate());
-+ }
-+
-+ return ToV8Value(env, bio);
-+}
-+
-+v8::MaybeLocal<v8::Value> GetInfoAccessString(
-+ Environment* env,
-+ const BIOPointer& bio,
-+ X509* cert) {
-+ int index = X509_get_ext_by_NID(cert, NID_info_access, -1);
-+ if (index < 0)
-+ return Undefined(env->isolate());
-+
-+ X509_EXTENSION* ext = X509_get_ext(cert, index);
-+ CHECK_NOT_NULL(ext);
-+
-+ if (!SafeX509InfoAccessPrint(bio, ext)) {
-+ USE(BIO_reset(bio.get()));
-+ return v8::Null(env->isolate());
-+ }
-+
-+ return ToV8Value(env, bio);
- }
-
- MaybeLocal<Value> GetFingerprintDigest(
-@@ -628,27 +909,6 @@ MaybeLocal<Value> GetModulusString(
- return ToV8Value(env, bio);
- }
-
--template <int nid>
--MaybeLocal<Value> GetInfoString(
-- Environment* env,
-- const BIOPointer& bio,
-- X509* cert) {
-- int index = X509_get_ext_by_NID(cert, nid, -1);
-- if (index < 0)
-- return Undefined(env->isolate());
--
-- X509_EXTENSION* ext = X509_get_ext(cert, index);
-- CHECK_NOT_NULL(ext);
--
-- if (!SafeX509ExtPrint(bio, ext) &&
-- X509V3_EXT_print(bio.get(), ext, 0, 0) != 1) {
-- USE(BIO_reset(bio.get()));
-- return Null(env->isolate());
-- }
--
-- return ToV8Value(env, bio);
--}
--
- MaybeLocal<Value> GetIssuerString(
- Environment* env,
- const BIOPointer& bio,
-@@ -917,11 +1177,11 @@ MaybeLocal<Object> X509ToObject(Environment* env, X509* cert) {
- !Set<Value>(context,
- info,
- env->subjectaltname_string(),
-- GetInfoString<NID_subject_alt_name>(env, bio, cert)) ||
-+ GetSubjectAltNameString(env, bio, cert)) ||
- !Set<Value>(context,
- info,
- env->infoaccess_string(),
-- GetInfoString<NID_info_access>(env, bio, cert))) {
-+ GetInfoAccessString(env, bio, cert))) {
- return MaybeLocal<Object>();
- }
-
-diff --git a/test/common/index.js b/test/common/index.js
-index 8cd9841527..98b586cafd 100644
---- a/test/common/index.js
-+++ b/test/common/index.js
-@@ -51,6 +51,11 @@ const noop = () => {};
- const hasCrypto = Boolean(process.versions.openssl) &&
- !process.env.NODE_SKIP_CRYPTO;
-
-+const hasOpenSSL3 = hasCrypto &&
-+ require('crypto').constants.OPENSSL_VERSION_NUMBER >= 805306368;
-+
-+const hasQuic = hasCrypto && !!process.config.variables.openssl_quic;
-+
- // Check for flags. Skip this for workers (both, the `cluster` module and
- // `worker_threads`) and child processes.
- // If the binary was built without-ssl then the crypto flags are
-@@ -714,6 +719,8 @@ const common = {
- getTTYfd,
- hasIntl,
- hasCrypto,
-+ hasOpenSSL3,
-+ hasQuic,
- hasMultiLocalhost,
- invalidArgTypeHelper,
- isAIX,
-diff --git a/test/fixtures/keys/Makefile b/test/fixtures/keys/Makefile
-index 824704c724..49cc29ad1c 100644
---- a/test/fixtures/keys/Makefile
-+++ b/test/fixtures/keys/Makefile
-@@ -75,6 +75,8 @@ all: \
- ed448_public.pem \
- x448_private.pem \
- x448_public.pem \
-+ incorrect_san_correct_subject-cert.pem \
-+ incorrect_san_correct_subject-key.pem \
-
- #
- # Create Certificate Authority: ca1
-@@ -733,6 +735,18 @@ x448_private.pem:
- x448_public.pem: x448_private.pem
- openssl pkey -in x448_private.pem -pubout -out x448_public.pem
-
-+incorrect_san_correct_subject-cert.pem: incorrect_san_correct_subject-key.pem
-+ openssl req -x509 \
-+ -key incorrect_san_correct_subject-key.pem \
-+ -out incorrect_san_correct_subject-cert.pem \
-+ -sha256 \
-+ -days 3650 \
-+ -subj "/CN=good.example.com" \
-+ -addext "subjectAltName = DNS:evil.example.com"
-+
-+incorrect_san_correct_subject-key.pem:
-+ openssl ecparam -name prime256v1 -genkey -noout -out incorrect_san_correct_subject-key.pem
-+
- clean:
- rm -f *.pfx *.pem *.srl ca2-database.txt ca2-serial fake-startcom-root-serial *.print *.old fake-startcom-root-issued-certs/*.pem
- @> fake-startcom-root-database.txt
-diff --git a/test/fixtures/keys/incorrect_san_correct_subject-cert.pem b/test/fixtures/keys/incorrect_san_correct_subject-cert.pem
-new file mode 100644
-index 0000000000..787d9f1135
---- /dev/null
-+++ b/test/fixtures/keys/incorrect_san_correct_subject-cert.pem
-@@ -0,0 +1,11 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBqDCCAU6gAwIBAgIUE3Kx4WUjkwuKy/fBOM+UJkb9aSAwCgYIKoZIzj0EAwIw
-+GzEZMBcGA1UEAwwQZ29vZC5leGFtcGxlLmNvbTAeFw0yMTEyMTExNjUxNDVaFw0z
-+MTEyMDkxNjUxNDVaMBsxGTAXBgNVBAMMEGdvb2QuZXhhbXBsZS5jb20wWTATBgcq
-+hkjOPQIBBggqhkjOPQMBBwNCAASQ/CKa5uMZuLYssnNOm7DPdw3I5Doa0Qpyf3cS
-+7aGatfK3tuY8qG7nJ5OGtl1WOL/gN0vRRN0/KA/iRJyjafzzo3AwbjAdBgNVHQ4E
-+FgQUFkpgPzE1ePjK5UsPcR0gk5uLsTUwHwYDVR0jBBgwFoAUFkpgPzE1ePjK5UsP
-+cR0gk5uLsTUwDwYDVR0TAQH/BAUwAwEB/zAbBgNVHREEFDASghBldmlsLmV4YW1w
-+bGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIQCMZAinQXkOEhfp+moxVnLbcUPAAqsl
-+1KCq3NRG91TGCgIgC4grmOhCRqJMF1RPNWobGogX/yNrYNjiGzNVyJzMR0s=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/keys/incorrect_san_correct_subject-key.pem b/test/fixtures/keys/incorrect_san_correct_subject-key.pem
-new file mode 100644
-index 0000000000..f7f51253a8
---- /dev/null
-+++ b/test/fixtures/keys/incorrect_san_correct_subject-key.pem
-@@ -0,0 +1,5 @@
-+-----BEGIN EC PRIVATE KEY-----
-+MHcCAQEEIOOVRgLS3H2T2fUhj4ASCFq60ySwO6yvSK6rvZHldAHuoAoGCCqGSM49
-+AwEHoUQDQgAEkPwimubjGbi2LLJzTpuwz3cNyOQ6GtEKcn93Eu2hmrXyt7bmPKhu
-+5yeThrZdVji/4DdL0UTdPygP4kSco2n88w==
-+-----END EC PRIVATE KEY-----
-diff --git a/test/fixtures/x509-escaping/.gitignore b/test/fixtures/x509-escaping/.gitignore
-new file mode 100644
-index 0000000000..504afef81f
---- /dev/null
-+++ b/test/fixtures/x509-escaping/.gitignore
-@@ -0,0 +1,2 @@
-+node_modules/
-+package-lock.json
-diff --git a/test/fixtures/x509-escaping/alt-0-cert.pem b/test/fixtures/x509-escaping/alt-0-cert.pem
-new file mode 100644
-index 0000000000..30e6fa6c3f
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-0-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+NTAzMDEGA1UdEQQqMCiCJmdvb2QuZXhhbXBsZS5jb20sIEROUzpldmlsLmV4YW1w
-+bGUuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQAcsy+PIduM8NRrdqcTqufiajsAajQz
-+eB5+5+lZLi9MliXqoS4HsdrDMDevMa2cC+wB+XZW9SJXjtqrwXAxTAHtEyhsCi25
-+XV0sJPWmZM+OQkGTtp7Ain12htr/t/DJ13YJpT03W6kYogA1kKJ5OMYMTcGT+7UB
-+zM4G2LUSrrSisxhfz9bF8Q9s1piG2gb5ACEQUiMLRrZXl8WLlaY59lloKyMa/9g6
-+i3TgLxhp7XNS/bh/f2tDx+7ZgdtHUlkNhl1MycIVQRGK3BaZBEd+sDxS52kwym5I
-+CWLXGLutU3OeaNgqyvZuMvy//2oER3PysizyjwNoFlUbIz3zMnXvBeEjeGtEHsCJ
-+EBtX+xBWwMhUKE2QcMLxQaZNJCZFVFw8fDeEgFjTdEBcLsZ1PngT3jgXSHEWA+YL
-+C3rQhFMjyjy2h8u1sjySFrTlbZPm8gC3q/+LaXxhf5i5xiZOOcVfeYiWFUa5gQal
-+FaWj2SlQFaN2nidPaQO62vRIYn0Y/qbtUQAPkq4VVeycgxiuZaVVWCdct8UCYb9F
-+b9QSMpK4r99MKy+s41RiJodDJy0XraOxy7hUDjyObL2fuuPUK6mQAFGwWtajv3qq
-+vrRMvBEXdOPVmbETyzIosUHvOXT+v8WoCbC14mqMZTWVywRg7bD/NTHJDRIBrqvi
-+O6Zqbod3EImVnQ==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-1-cert.pem b/test/fixtures/x509-escaping/alt-1-cert.pem
-new file mode 100644
-index 0000000000..63883c2bbf
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-1-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE0zCCArugAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+IjAgMB4GA1UdEQQXMBWGE2h0dHA6Ly9leGFtcGxlLmNvbS8wDQYJKoZIhvcNAQEL
-+BQADggIBACFwNHWQ5w3UBbyq17emn7Z0BT0Zm5iFr8Qeik75WzbyzXd5QIeFWewB
-+qmiuaoKGGZ674sGcuomnIwoZBCoqvzbBBqBHp+O3/6pq59THQxeE6vhjKAe8oaih
-+emdigRmkX+Qi8UwUh76B51wHtkp6zAZnLDn8M67qmP7bjNrrMQeE81wRWYz9ssfd
-+N63dzu2BdD3EGl4CepdszpfUYLkz6iiDwFkc1NaBcQbBDoGqn2ubNXTHAyGGeL5a
-+ulDCND0FQtg+jhHHE3zXBqh1nPg/cXXRUG2zjxzUnaU2eMs5b4yqoLN/2n7fb7mV
-+HRh0T6X1HZcYpf5BSsgmr3Ngd/9b3sYRvNXBkVmKAu8dH7zguksczsvbL9r/u2YX
-+hgGjNT3xSphJbZTzqsACcoDo67EFkJ5p25f0N1i/rxk7O6uLMtrUqnzOXs6NXgEQ
-+8lyfVEgLFrXzdKXuk2l/6bwym80Eqdpjv5yCckCl24cFVpc15MRP3MPwIHrtoOLw
-+bdNZA5NUAnppLmG6zTdPPgBWEmf5+4ei9WjmpG1hq72/nJ1qM2dLIgV5nLggr1UH
-+i+vih+ujceBLVumAu/naP440xO5HRvpPfDWI+eU/wuXjUyAqe6YlYS+Txu/5YnFh
-+aMHO+PIgudWwGPhkABtrc/1jC+Yfy+GCtih10zBagoN9/DSugh0H
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-10-cert.pem b/test/fixtures/x509-escaping/alt-10-cert.pem
-new file mode 100644
-index 0000000000..14bec45d28
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-10-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIExTCCAq2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+FDASMBAGA1UdEQQJMAeHBQAICAQEMA0GCSqGSIb3DQEBCwUAA4ICAQA+jnyjJ/9X
-+ENWXApq2g+GlWBM07KpsrxzwDXc6wsOnZCIiMoDqpcH96X8Q2Lahc4mZuz4yOZtv
-+z8Q9YUDTnJY+RtKYNDbxlz7wI1ASxKdP0X1qdzkYtHH752tG/zwVU2FSvqJLw+nl
-+rPJvQQ82/30BspejbW0JIfO7JnfN5BHPzzJp/V5tI1KQe+Wh0gEq6UvXjFrkCoeU
-+gaedPaG2RYDi1LWawRque7pnYzrcJCtc+wb8wiL1dRv7fDDmI7fFm3Bj6Rnid4/6
-+/CxK3WqLBQrXoGnPGwI4iR17Rx08hPCL2V8NvDuJlagJe/Vc6LzOEixofoHGx4rG
-+Cm0AKubKbak/ML/rjyP2TiUmOhhm3Xdml3xexedErkgTLtlvmC0jesYuc4MeypNx
-+Q0eKRnChRGZYT9kaNgXZG1Scq63vpxKhayVvwU4ahGQS+nmuZdbRMEMIH6YkGxo/
-+i5qmNxQPLMLE6HclSdDtUxN4ywQAQ49CaTCxVYq7dLTzpII3ldQ+KuefenaXrYGE
-+7TyqJBVdsTq0Bg2Ftf7GaoidJ/ZjjkB3Sj5uVQFMfU8uSATOolBOzh6fSiQJ60Zn
-+CtAAkb9uOwTl67Qijo4qAe9JRNqR9H5d65D0Vx+gdhcZVEriqIVhXVcgsvYQ55Ju
-+VGhc/foVd+vBuM3jXEdGR+DN/dEu+HZrhQ==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-11-cert.pem b/test/fixtures/x509-escaping/alt-11-cert.pem
-new file mode 100644
-index 0000000000..694cb7e9d8
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-11-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIExjCCAq6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+FTATMBEGA1UdEQQKMAiHBgABAgMEBTANBgkqhkiG9w0BAQsFAAOCAgEAp2nxfYla
-+giNJ9S2owtp/5DxB3jIhQJzmdSxuUKVwWBffmzxrTkOoK/IcGkq3hu27GIy+ICFc
-+YkSsAE3DfboSTStxhkVZKMVv+e5tXPQ0i+Z+CSgHZbrnaA7nH0UPEgFFddhqogGw
-+LGE54iZ3D7ZYebTw/ELCIHNu9KeOStF7j04WXG7qRrqza5NmKqlxTC5tGoWAljzN
-+cdC2BdK7H2+6de3c4dBsYqcL2IgwNhA1uKIsDjJwwkOPmCEPl+7DjleI3IAKpROh
-+vX66DLaAsLEkoHsN7XTienHF8o/avIMGUfb0rtNLbwW8tzfjeAaJ7iTSm7ibhBLP
-+fK+n7Osh9QH+lG0K7M2zez7Kd3u+eNgTEG63gVR+zDZQwkA2Hy1o4zmZ+a3iCtdi
-+w6JGq3TT8nfPNO4kSoq7EYs6daPnGi3sqNRC20t4FZw0jOpvI4Uw7rPcTTqmAeAw
-+9H37WU3URD2EP8BpkoZiOShMHzNGqlC9qbqr5dd83Lkdz9gN4w3ipdbiiGFGPXhT
-+YubUecjwXoBUUI+be/edVbg7RtSSuplDv5l4bBSy+BG8JEUL6CKAUEtt2Tpt2SVD
-+AIaj0B19/DSYq1e4x8IBVBsI2RnEEpP70bdLiSYLhVhMdzp0PRqDVDE+zt4mm0lx
-+NRDSdNS1/rJEH1gLQEh4SGMs9iY5Vv+kx28=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-12-cert.pem b/test/fixtures/x509-escaping/alt-12-cert.pem
-new file mode 100644
-index 0000000000..7e48ebdf05
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-12-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE0DCCArigAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+HzAdMBsGA1UdEQQUMBKHEAoLDA0ODwAAAAAAAHp7fH0wDQYJKoZIhvcNAQELBQAD
-+ggIBAEMU6XcjSdQ+EG22BsyAYin2d3g9Fd0gljsuyEyw2qwFE1zeNqz2sFX7GdmP
-+hEmUVdzQ0EQsHtKiO2BIhU5fkLoGIkJQT0MY/Tkc3xCLjVBG9ryHNjhv4aYfcvZ2
-+K8LwWu5na5YtpmEHppFTmhQFHK9Yf2Jeh5Ms1VH2jwKR8iFM9dk0wcB74Y1WqyX0
-+bhNUzv0ISvz/DK6rN0CM0OiZ7D1toMFJIslEcZD/MCZ0icFwRgGLzooDbm1xtixo
-+NjgdswdiL0cS/wgSdzu9eIugUQZU2KvUWYXGqYMDpn7iukiZSKQuFhZGcuK17zyR
-+y6TkDFe9rTxVtw9SAxjlo94rEqWN9Cns0n7tqAI/Wg6ILHUjUFwqSdrZQTEgH4O3
-+tfhRkV4HCgP1Tzfz/20uMBqjCLbdt7xcSfLIiHgaxgwM0LGhH2Uk3oYinL2WIUDi
-+bZPI+1bzeyZ/tHw4sDxkGn3W3Nr44Td/5DAFz1lRMxAliVwHNzFTiY7IjCqmB0DL
-+z91agdgPMdh/huFvGJZHS/v7EXMSXyNLyIw+5JO12iwf4+pu8NLnOtMoHDB4yY0w
-+MEerc4e8SmygBQGF0MrcmirdT+7yiKRktZZFuyQoj4fBSKeBaBKUrnnk4UYw9H8f
-+j/EQwM87PmYjTwYPrJ0Kz5r4dmAUvq4z2ReLgM08Ve4SPa79
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-13-cert.pem b/test/fixtures/x509-escaping/alt-13-cert.pem
-new file mode 100644
-index 0000000000..574ad1ca8f
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-13-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIEzzCCAregAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+HjAcMBoGA1UdEQQTMBGBD2Zvb0BleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOC
-+AgEAkx9jG86PMjL+/UxlhX0B/gIKHyTVrEt8j+/fn74uMnd7CV7toK6f5DANIxYp
-+3OJWAFYZ2lNS3MQMxpbjpd7D0BeNwhiJyBnRPhJ9KdsvdXnupF5ANNzr3oMioWwL
-+3WxvmQDEz35sorae5nzuZu8EpuwgodR0NCEmoPdW9JOUiB7k3Ku5goZHqlrdzM8f
-+YPbRDNOxSIpRqr5eqhEM9tEf+TF6qOM/NZJlXxtGDVdaDTbaULuCJGEW8TdVajnY
-+FfWWtIHwF64G5qJTgENqJjR1kkJy5vg2lFoDXE8MG+LvTHfyY0rMilncD2YOBLcj
-+gb3mBTxZGI2w2KZbchgEvA9+0heumAVJQPfdGs+pCUdvlhwWh8FCvu3aQb5X57OU
-+3D97vwvEs8Mxm0KHf0o0ZnTvaBWN5htX2bbpvYxGGB0SsWM8r1LIXj8bwGNdViV8
-+UWNrg37XyGCppL1jXJ1q+DDKOvi0JR384ocRmS8mWUf9qiAMOqveix38rHezWlEm
-+4TCscq4tv135nM194D6uilzv4mUxLAMTX8Lvag1R3aKuOHio9lCGep4v776kALE6
-+9/rekRGoMwNApoaC96x+V/dkbfnjWcxRXL5TvjDwVInl+RCcn6ijYZM0HYc+U1Dw
-+MwqBCbP2Y9Ee7xcnAgPbqH2svWG7XadQHAcOEDc/DFsPRG8=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-14-cert.pem b/test/fixtures/x509-escaping/alt-14-cert.pem
-new file mode 100644
-index 0000000000..0265b5992c
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-14-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE5TCCAs2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+NDAyMDAGA1UdEQQpMCeBJWZvb0BleGFtcGxlLmNvbSwgRE5TOmdvb2QuZXhhbXBs
-+ZS5jb20wDQYJKoZIhvcNAQELBQADggIBABf7bojDeoFEFyk/Xzo50sAL+5irJYzV
-+n//5aEvUotYxQt5coi7UnkKUgdiUhIXD8WaxD9KP3nUH+C3cxAQ+I7iVjFhjqFQB
-+X4c/ZjJA2QIX7VMWA3kpOFvR5N0HHest097Fi/HUEEXNkcUtCkRNtI2Msse9uz09
-+DIv9P0IQ2TFgBRCTJwq2ZfVebHk/xoQ5fV9b0b39ts6ToiuMvGJVng2zz8fVNMah
-+hycCn0WSb6dPi9k0ItSvRTYL6vp9X842+Q0Xkq0FxQPUcvzN7D1tSmHXDM7nYXp3
-+FB6DKASp0+nn+J88RXVSpO0JedEyRDEluxHJcan+hqhWJ4DgamlVTEPN3q5yE4lt
-+Jr/R5tnx0Lv0CxDTAfZLaFiKb2jz9nVhzbCh7t21mxyb2mOM+GAxRaIgxodeNJoY
-+QA6Ezz4cbjjA72Rgi+tBxy2abXpbbJ/vX7FUhs0ICFKZJHvFoxazgtSGgHHYNxhc
-+/+9o6Y9jhunwGn/MaoxWJsdSjZ8VX7HY0iOSU3z4d4PWvIz05n4sGoJET6s1JuKe
-+dZAAeQy0V5/EzxIu4GPGrzVtk2SQhNHVJZKponZeCRruruGT5Z1T+gF5YSqVM6BA
-+XA0ZVXwOEbZ5XRIzBBbaiX3Eeful50ILOiP/uxLlcZtTtOyT4wNBgijfJehRHbED
-+ppJk42EFZKb2
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-15-cert.pem b/test/fixtures/x509-escaping/alt-15-cert.pem
-new file mode 100644
-index 0000000000..70a98fb90b
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-15-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE4jCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+MTAvMC0GA1UdEQQmMCSkIjAgMQswCQYDVQQGEwJERTERMA8GA1UEBwwISGFubm92
-+ZXIwDQYJKoZIhvcNAQELBQADggIBABIv7Wlg5F1gh0+0v/+LnushmLeypcXQGqkg
-+E2IxXC2VnZxq8xTFCHy/m1qTBLPJK5VIg5qmtstL9zIk9rOUshQvusvNLplC0j3o
-+GuQdQJNKV7rrzYYpUZO1en11q27AgDsO6lwSNg4U+mqzJxxIHc8IMeJpfaGTkUz/
-+ZXXNz04JJalUff+W2436vSvu8Y82fD72/qNu6EMiOl0EHJFQ/7eCAlz6hSNleLT/
-+N2GztApNzujbPgH7+PHOeVpwppDuXY1rkmPJMxCqkY8yOwyM5dMov0bjIN1f+QXv
-+7voxVGMTefUajKADaNGMShH5rhgjIWBgujvdCyLPr6W2R4S1QPzjx4X26eTX1G8V
-+/eTsJ6mMc+3cd6CEmEahUnc6LdEdwm+1SMRG2nejea4o8c+crwYX5KQVrqx92FqB
-+SdkdCtS6qlnxJVvSz+HW6lEM0EShvjKEz/udsnttALQjhxfB7AHNWA073o/OiH25
-+Y9QpUudmWJjOoqRokN0SV4rDQnfNcLKIoVFPu+rG2CpBDjUsoxG3/aC8Owcd8Ceh
-+w+O/DqQXudXFS3RsePbz4rPfID9YtBHrihCE10B70DUutWPsbe5lKie3wJpQbqvl
-+zp5kkI5RffVU7OFD6os3+wPomdIG21Cf/fru56nV3FmkINCabLQddes7OarQcZ5y
-+xsumEzq+
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-16-cert.pem b/test/fixtures/x509-escaping/alt-16-cert.pem
-new file mode 100644
-index 0000000000..64f852ceeb
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-16-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE4jCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+MTAvMC0GA1UdEQQmMCSkIjAgMQswCQYDVQQGEwJERTERMA8GA1UEBwwITcO8bmNo
-+ZW4wDQYJKoZIhvcNAQELBQADggIBAEID22h5WK1YJrKUmmO0owley+tL519YwJbs
-+FwbwPz7+SJKA+UQNqVXYOGLwDJ6A6OzsV1TnJuwGotTmvNwr7eOVyLf03qggIYEj
-+5Twgk57gJmqE+Q8UXUq2ocALUcgReZhluhNoL1XYQMbDaHYwh9HSOP7udEszVQoE
-+m1D74cSiW803XnqPJGj0i1s9mD6AEewPl2k0mQ0hTMM3rlE1jOCj4Jx81tWH5KNY
-+LXn/LhFomeo/LAU4PCFTt65tAomKTNXq0GwuunU62fy8pwh9QUpD3Vfrkm4+08uz
-+WXSk9PeaF8tOs5pRwVMRr0GIdnQHa9GKuBBSZEvkGTxLM+cxO7jp5qSs2IRVpI5s
-+ztlJQcJpeTRNCEF7gM98nMqDqve/IySGle9s1RjpnBuSD9UKzbMGeBuZK8d0JfBt
-+7XF3i6Tu74EbBL/mP/0xoHausW9Yo8HZhXjm5k9P7m9xxlq2JSSXeQCLbKFT/SN+
-+Q3bS6rh0HaqLP8Gd3OyU+aOOy13Tr167LEFNK6DlfSadITuHwRMNvCk8UIDRDzAZ
-+kXVXdT5UfUe4IJU6OPVsFfntTX6G8s2/K4WropnjD5NjBJ0ppvPgCBqEA03mCGVt
-+IunRhQypiA0+SilM7BX6jD97IcmnbSyQ6fUkIdDBTMlX3MoYXkT00gDT3y8D/aKw
-+KTd5SKbD
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-17-cert.pem b/test/fixtures/x509-escaping/alt-17-cert.pem
-new file mode 100644
-index 0000000000..f09f41b918
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-17-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE9jCCAt6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+RTBDMEEGA1UdEQQ6MDikNjA0MQswCQYDVQQGEwJERTElMCMGA1UEBwwcQmVybGlu
-+LCBETlM6Z29vZC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAchR9+hds
-+zMK0NKgiX32XxJJ79tlo2sRMCZqij8Lqfyz7JDlTMSvIVqcrmimlAMX5u8BxKRXG
-+99KzXhbJb6Hnj2i6fQobxpD6nKnPSUcoiiWccmp8jmcKQW7M6TuqOfEdEnKpf0BF
-+vNFBjXGxs0KqOArX/1d0DqYS1LTnxaC6NimgvjAqKVRm9mqj62pc9//ixCgHkqLJ
-+stuoSerbo/mO0ieY1wq9r9TZT1epacVrQpJFWeJWhow94WutMNesJSWLcxX63mH4
-+j0LHEEkHLa1UkMzM2RkHTVhKrthCiuyrtqrglLsdPInU7ZYVONyUrR2D1tMy52mB
-+b1HzzP43pomBJtp3OeEZtBDwmmGgD8RBdVK/T9hcK02cvB1w1yr4LHUeYLMqrZaP
-+SJHQ7kv9AV5Os64SYW9+7cqjt1q4VmaEqcuCqvB6mORHWHnsa6PQ19myA7OdqNpT
-+WAK3D94tpbGPTzfhUCHk0w0fPzJ4A1+S6g4eHX4iQQxxDg9sXV4ZRvAEKnJhs2S7
-+OhtXdfyu/1+lfaunN13SyxMwyyxHzylEU707Sisxse2usX1Zy2zxqD+LO/9iIu1S
-+76/rquhiOFRWxSpjb7ewpH97OGFmtzfH70vBBukn0alT4xjkje10NlBfzcFwHWQH
-+59nxPd5sUEqq+DxTjoAgwO91woU7UTs98lw=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-18-cert.pem b/test/fixtures/x509-escaping/alt-18-cert.pem
-new file mode 100644
-index 0000000000..341ac0b7ce
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-18-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIFBzCCAu+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+VjBUMFIGA1UdEQRLMEmkRzBFMQswCQYDVQQGEwJERTE2MDQGA1UEBwwtQmVybGlu
-+LCBETlM6Z29vZC5leGFtcGxlLmNvbQBldmlsLmV4YW1wbGUuY29tMA0GCSqGSIb3
-+DQEBCwUAA4ICAQBFUk2Z1E5Q4mW7S8dLz5h78AmfNbwx9eNtECc8iLQq2Q0MuIzQ
-+noURyNSHhH2hkohU4afXjolCr54DkJNYogrBwHaNDt3Y3wqGQXc+BKRnqblfr1+A
-+1EoIaqRFjv/Mu2gB0H4U3vBRYriZu7BhQFXiQHAr6hWLG91B1eN1i+my9zOSoSZF
-+7BuemB/9F4wjvwmDJieSwOgGk3FhNV64Ce9M95RwDKNSJBTBqOTLoyvOw2jgs22m
-+MntqW9oRywGeHdJ5EucPBrZQKDNysNFj3We8H7PedGNlnG/QknE6pzpRgqbRCAax
-+hcvGQIaMcUJ3oWhJuPNscjsJ/nfaitz58nH5raj4O8JhlS1h49NpbJO/pAWMHh0d
-+ZruXspxdEwW17aMJJ365q0XyVysRHiwQuIQYCo8L7oVUsH5FUJ9xxPH22b+PG05r
-+EABdID+aDV7X/MNwBxgeBOFVOgE5bfrH8NBjkx/F7ID/hjcQDLVWWoFnpIjekebC
-+EeqTRl5TcnoN9Dc7zkfwmuYGoaYJrGhj7WRvfFgcw1Cr1xujiJtoKbEbMoeD45+H
-+SQ8MwBb37Gm3aBNakpVmJlp/QZSJY403hA8QrZdjnqoS4THrC0+gN2q71aZ9ZCZY
-+3+OPNg659ZcYvo1onBSA0p1WGKEAWdHKqZCVRdsl5LnRg4H5gEVW4gmhjA==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-19-cert.pem b/test/fixtures/x509-escaping/alt-19-cert.pem
-new file mode 100644
-index 0000000000..f163184204
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-19-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIFCDCCAvCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+VzBVMFMGA1UdEQRMMEqkSDBGMQswCQYDVQQGEwJERTE3MDUGA1UEBwwuQmVybGlu
-+LCBETlM6Z29vZC5leGFtcGxlLmNvbVwAZXZpbC5leGFtcGxlLmNvbTANBgkqhkiG
-+9w0BAQsFAAOCAgEAWtSJOhwRpYdB/aq/AixRTIpwf5VR3MWaDNh7clpnpYhYoLDY
-+7dJ8cv3AR5dOScFXLrCZ2UYVD+tTPyt18opnYDT4h6If/U9TTHVu5tRSX0wGIdPc
-+j3zVVegty/HWMA5LfwygNTvZjgXhocckNND7hC42+BuXE2bqoqnkqMRer/R+9PmU
-+FXpyLk0aDl2QmspDAz86FYpEuxpMfmDNmM1nWDz+n+uBbeuriTttsFqFWkfOGoNN
-+/3tAmUjAt5IqkL+7rnDt6Lc9inY0z3uYGJEdqa0GJJFJ7U+8wcw8rUwvKETqAtW1
-+mBOswkoCImPeNDpiqiotwl4cfrsb1+j9gNpYTP2oSurh/bF0mxGLoJa1iDeibwqg
-++f6oWcCdYQ94ItvS3d+lNXT0MWM6HU6sHXf3+5SqvsvsKjUBRyy1Nvnug1bha6Qv
-+bdeErN0ZSGy12Vc90Y5fpl8kebmYiJc79OqvuTNDeRfgBm+U4ASAj/AEhtbN+wDd
-+HrUHbk/9U9h0UFRZ5s7Pqoy5PEoLRoFeA/jQQa/fLC8nl7YTSwidVgj8cyAy36sV
-+uaBNXrcgelqlR26SBynXM3APaFlv5IdSlF199swMCusQrGbiNajl21TUm+Iv+84g
-+x7rnUPnQ1grkLpMOBtGaraKc93e2VfH5bAZvyaIq99qdA10ERCtE2grvjik=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-2-cert.pem b/test/fixtures/x509-escaping/alt-2-cert.pem
-new file mode 100644
-index 0000000000..6ae58f5636
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-2-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE2zCCAsOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+KjAoMCYGA1UdEQQfMB2GG2h0dHA6Ly9leGFtcGxlLmNvbS8/YT1iJmM9ZDANBgkq
-+hkiG9w0BAQsFAAOCAgEANTZFCjNmspLkZaVYkcAXfT2poPPWAu7wS/wG4VEmKwPV
-+A4dnFV2McXNW/iyABeoofeIjsjiYLpxTvz3teD2JJh+hidNED77PV7f4hj7vs4Dn
-+DGB3HKJvTD63AVOiPJ4bbfUyiuvLO5TwdxAGm+q9lsf/fWFraTF2qlnFwyWf6Qul
-++NQo3bM8mErvntZMscq7wo0cOdAXA0bNqxKS+IDnc+HLxoEr2egbRJmEagMgV4/U
-++AGVQ1sY+HrEszOPUA6NZ/OzLuXUT3swm+4rqJZEQ3AVr2BdqSzoiGHqqzmfKO33
-+sODcYXuED0sUkIhRZE1vW+wXR94WQsT5C4MtHabNjpPLSH7cVjGvEfTX8DJH/F7p
-+OdMmXxvPey0wLGJwoZMMhG/XC8Nb1g+qCLLou9WuA7KHMibfiYdBnPcMDg3fwWwg
-+pYzrvK/S6f5h6TS8y9zKxCJwTdfC7f4KT6EjxQFhgHCm8oFupOLSEZKF0UmLMeOA
-+J504ZnGdhEG5p9AqQNBlyBsGGmSyQkSJg1BPB6U7wFBSwrXS+3b2ph4J5RivH68O
-+CKjR7yWl7M75LOa1dt133GmhPUUGHLsjHTnuCDVB0eHcgboonKTjCSAmckNKm/uw
-+tAUMkO3puty5JM38b8AwFRDXLnlWdSsNr9j243SHOfKyFWidjwglRpVGBhoECtA=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-20-cert.pem b/test/fixtures/x509-escaping/alt-20-cert.pem
-new file mode 100644
-index 0000000000..eca176f2df
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-20-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE4jCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+MTAvMC0GA1UdEQQmMCSkIjAgMQswCQYDVQQGEwJERTERMA8GA1UEBwwIQmVybGlu
-+DQowDQYJKoZIhvcNAQELBQADggIBAKvkEHjR6lk0AlKiC7oltE+gp7SpVHdKs7I4
-+zswnbZ1EcddA9D6hjemU+nIUriLkt8BxY+KxNtkwDm5mvXZn5E4XDXzRDsCdNZXE
-+qx9og9LhkhfGbPJ1LPutQ0VmqPwY17mRUeaLhNIwOmD7g++oVHYmZWqA8tHVB9f+
-+gP5Ni2x/PX772Vt/hIpI14VoYIsMFs4Ewjc0Gc02DvOdsDT9eUmAo6GNOAbxeRS/
-+D2D0w6CQhwJ+cemcAo0lGw8KemCYfqzL+MQd8wUGPsiZgm5wQACOp+ImL4guy2gX
-+h60W9Gtxu77jsjF7n0n4LlInylrZAgw09CkehUfF4+cP2kZDTcsuqOoCVYATAGxa
-+49ZvuRHoo5Ine5PcfuARS09LmxgI0fdsjaRvRELYIRWHTvE+zCLlNkxkpwXULgZZ
-+bpJ08L52P+jz+HJPeiHZnYKXgtXyGLpwG1danS600tqiMmDh0G9Ss+UzwhS+jhN5
-+viIvpmns0zvI1Z1IWPw3y27pw7rmLVcFMbEZFK5mwHiT10iRrT4sxihWIT+sn6n5
-+5baup/od4kSJABQy9LAuhhuZHyCfxC2yPYz70sP8qGVtY+rA3LNe0ns6pY1L77DR
-+QIRD/Mm2hql91+U222mxikdT4WQEheh2cLwdg/T1uo/SQDruliNZncdNbTGDmnhc
-+cg1mw5tk
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-21-cert.pem b/test/fixtures/x509-escaping/alt-21-cert.pem
-new file mode 100644
-index 0000000000..16d5e7265b
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-21-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE9DCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+QzBBMD8GA1UdEQQ4MDakNDAyMQswCQYDVQQGEwJERTEjMCEGA1UEBwwaQmVybGlu
-+L0NOPWdvb2QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggIBAHdccJEkqezS
-+GSNNVIWv9XffNTrZnejms90h66UDC4O9shHMy0aNWgmGuu7uFi1BK4sTciXT+ZR5
-+3+1ni3WKMhJ5Iu1aNlNeXULOlmuHKVJKrAj8BR7lflSFqj/MHnw22HU+BTmddZPj
-+F/OCl2W+O+eUNBTTmYI2+pZgmyyU9v8qEwLZn57qlpAJa4gpnSRYQS1xfSaUgAcM
-+xtZM/AE4F9mDFOdO86/RxXsYRyT0+sOGmaoJrlTWoKduoI7fhzQAIGHnhn9yBT60
-+0K6LmCR2dXRyLxxVTy0Laiz487IXpQTJ8jo6c0wT6SeiQBlE0W3FTH3IM8Shzd7b
-+5tbix0bCR1pUT2Q46oaB4xkEweKNGKS46kIps6mpTav3TMhNDVyalUfF4fOu4FQu
-+RLB6B/I1TI1KHiTeD9xfNInBAdO9ewjWQ9spFei3EExZmvnnWKZIA82mjG/9Wcdh
-+HFK/uEylzo1Nsxujv2V6ueMYc0pF4XH2U1Azjxb0+pWUZhoy537Nlf8b+PO/GSG8
-+del0yPwf6JP5AZdXfiV8vNqwEGCC/BEIPrbZ6Zz1q6lT+7GZAGkzbMYlfkzA1lXh
-+JteRIracA38WfQOHf3FOPYvTBOPlVHWB+tJbwlalYQqCPupMaaxxizCLPIsNvqdy
-+TAtC5Jbx6N1DdeyHpRuKRUe1M926oKTp
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-22-cert.pem b/test/fixtures/x509-escaping/alt-22-cert.pem
-new file mode 100644
-index 0000000000..5f89b00dfd
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-22-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIEyTCCArGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+GDAWMBQGA1UdEQQNMAuICSqGSIb3DQEBCzANBgkqhkiG9w0BAQsFAAOCAgEAE8vG
-+nLYo/G+3Cuzir4toX726vLOkCEqZrkRE18dc3px/CgmEI/6+4lWjp3u/9MxER+kT
-+t5o5Xin+vmg5F+hocR16mMeX6pjD6tXJ+uzDacTxDgRBFdbqX4x8Fjiig0FXsr3H
-+jFBY2c4UcKszFlCTqjH1/RfwLYJPU6Q1WZM+1iJotSKnhK7y4A/3jho7sL0PPuMG
-+WEoxbTBmpAf+jPT+LRe2MY++VnVJHjlPba+S4Y9PHOzizQuIJs7YnhNIqA9So7Iv
-+eA7Lp8GID+w/eY4DEq4z6CIuCplKZTrrWH0kQbG1sV4J5+W+JL0DOXDk91JwkOPH
-+rWf6aOb3akFRk5Z/PrrcTAlqtApPQF4uGycQBo8KgcatZyP/3HZZHyyxhEjF9sw/
-+STHm93GlCIwocJ+SkwjBmdupv6Yk8fRmA7LinjVvi7EnQQ7qcRE3oUCPPReDD96G
-+TuDsGkQbv5WQSh+0mBAiTFze3C6FSNcldQBrlWReqOj6pVWtUN49lpYOJ2XfLCQe
-+RjS7IUYNn7Ku3xXi2etgNzmJXcSnNXZkh+3henpFqkwEFJ5b5RgOHXULTwoqo9KS
-+YMs3eKHp62J6l0pQD+wTGUyVU8cJghJ0hR1WnNR7o32Bos2dfBmIQgET4ZH/P2+H
-+A2gtbJO5mRsTvuD+kZut1jxJvUzuO0yZoNpuUVQ=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-23-cert.pem b/test/fixtures/x509-escaping/alt-23-cert.pem
-new file mode 100644
-index 0000000000..5cd6795cde
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-23-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIExTCCAq2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+FDASMBAGA1UdEQQJMAeIBSvODwwiMA0GCSqGSIb3DQEBCwUAA4ICAQBps3VQshvW
-+9HDR2oDXSldWNW2SWksa+9npI4IEMDusiDbLdR0VBphw2R3iUuJ4IAPDc1s/SMi0
-+1t1o92lC5zVeTq9LvOOC1KxwbZXDubFDmdsuJ/DYPDkaRoDqoH7eFsJuIyD/TKqm
-+HXPYmWmjUNv51SSLTTqPRz2TmLQVA1Iw7J7H3fz2LExsAtczx6gRZJPIZGdMx6do
-+E67SUp/2RPYtkEmmCELOxCAh/Pzm6pBPncI86AMTNwppl+FpqaH0LPrqMre40tTt
-+cQq/0XrMWRoWsS3VU8uor+aGTnNp5VT3ZLVmXZNyG7nISW7ERaGCeTZJRcqwjeH/
-+yPxhQc7IpYCm5x+HN2sDuvVC7l/q1A7+CbO3jNR5Gb7aEEyGiKb5ZkElbsulfwom
-+JOg1K8+SBDGrErEf0MDCenKY2g0lhpKGBwu6O+RVmKbhlHEjt2/31/NCSBMLopdU
-+AmCNoBo3+KaRljo1lVf7tWbffNRCqsbPZPHtq9uXs0DliJTUroaJ584h92VrSLJB
-+SdAUVLAwzmwu2Pa4bp0STv5tJy1hFNJdVFQ4rgAfaFudXy41K9zqrDCB7RbzX7Yi
-+97TCDu/phzkoFpOZabqTrvcP13N0wfDeOx4Y9nx77aeqTAaQ0ooTG9IWrHmjuUKF
-+wpEXQBfkuXug5+xq/hlCllkPj67cIaldDQ==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-24-cert.pem b/test/fixtures/x509-escaping/alt-24-cert.pem
-new file mode 100644
-index 0000000000..2a858dd39a
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-24-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE1DCCArygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+IzAhMB8GA1UdEQQYMBagFAYIKwYBBQUHCAWgCAwGYWJjMTIzMA0GCSqGSIb3DQEB
-+CwUAA4ICAQCKRaPaQO4+oztra70h3g1qwmJurQ1vGBdcXh27nf9epFAwhU1zL5v7
-+7wN7iclY15BX3w3WrZ+ag74AvQLG6WQkDY1JCmidEjjt2bmVTxIus0H9Bb2AlUEw
-+BtVYMJrr+fiWbfSwRxhMQa9BQ6ZcUA7EluYQFApo2m7GIcMc4x51L/bwzmsXYj4t
-+2tjnkU7clL+7GR/w/+ZB7nIe80j7wYvIbOfMS3Yxh+uu0aQCNdoh9Tsdtu1jtmJv
-+4lJ5aZIDABE/XIFVkWRyHv2ou14J/LXUKE3HPEhSKWu7GShrdTeS+gZpOixM+uPG
-+ieHah1GfJMS69P82Z72Cr7XWpQY0NKwMB+ePhTzz1LMBHQ5ySXQCViQRClRMc5K+
-+cXZm8cs6oe4IEhMcf3kc/9xblgRWqxX7vsb6Gcrn1eXsfxco17S1yNBzTt75ybt9
-+kvPmrWqpg+sQ0r4473DjEASoSCPwlzCpd7AHOw+XxSwsOUNXkEnXMa2v2VHBjx06
-+QnrLenB/n7EQ5Vo9JLDMLM6ie4gfehHxfdyoBg21jN9eUPpKGnjARVvyfDWV+7rI
-+ZHU7wc2iMnqroAqm9FZ0YBqZ/eI8M4ZAYSvDKnGZQlUWfhdNDhI4FsHBPymMFtjW
-+ln5eFUNLMoitMGs12Ib+omr9WSTxRj97GvRkRTNK5Gxmo9Mi/Pkxng==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-25-cert.pem b/test/fixtures/x509-escaping/alt-25-cert.pem
-new file mode 100644
-index 0000000000..695b8ebba8
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-25-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE6jCCAtKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+OTA3MDUGA1UdEQQuMCygKgYIKwYBBQUHCAWgHgwcYWJjMTIzLCBETlM6Z29vZC5l
-+eGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAIgp7IrYYdLCoUqg7E4igLD3u
-+C68B896uoeenMmTKDfCzvB5svYKZlfIi3njJUZ2G6kgBNcSd/mwQ2ggex9AEUiGp
-+uaT7Dpev3RpwtCz5zpOZxN+B0LJk4hPzzE4sjJFrmHRgJVzADL5RdcEF7+GV81nP
-+X/cXviffkxSihAFALArAaOA6/hBoT6unvlDsY3cxgZWFl3ao76vTQFLs7ZNHYbHe
-+WDkkNpheWmNlOrVTEz0vjNCQz5wYOM6HJ0O3cxzR/6+OnhPQagZRCWApPopYGuxc
-+kXHAPbEkXpVzJTrNgHIvZ3l3JdJSHsh+DdGVz1NY4bogQNKCVa3xt+zLpUrr34XM
-+61Z91MekMijfjOsy7LGLSBdCPCZ00enXPkflDEhv1kRlbo/ZdYGHynzl6Xzu1A5B
-+nuwDbpsCzR6ij8fZDXGUS7F8Iemdfag4XTtrXnVXLgPpD/FMzJUx4kCIAjgh2MaP
-+0nUvZDVYt+GKGohCNDrSt2ByFtbYGaX5GeMIp8zW+GT8KUW/K7pp9PjsmzG6vvQd
-+kqxB45ddf87E8NoDWh/ptdj3pjfbDc5A1SeXKGXrt1TwgWHtUNW0zF8qOuG+PZ1P
-+u10lUx4gayyF3unaSLZwYu8nYq5C7mC9DjjnbjLhsh0VOIEEh+Q8vJH8OvZFkyti
-+l2ADXC+6evQTvqLwXi8=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-26-cert.pem b/test/fixtures/x509-escaping/alt-26-cert.pem
-new file mode 100644
-index 0000000000..1204d95a8a
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-26-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE5TCCAs2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+NDAyMDAGA1UdEQQpMCegJQYIKwYBBQUHCAWgGQwXZ29vZC5leGFtcGxlLmNvbQBh
-+YmMxMjMwDQYJKoZIhvcNAQELBQADggIBAKmgEHc9b/bscpyO5mTKrITyoYtbhz/P
-+0Uz2Uc4tKokUI9EBuuD/XX4EjtVzne9mssAAs9EhBSFmNhDjpAUYh9n2cFvAJQit
-+4d9EbaNbB3SuzG5onu8ZBtfLsABr5L5tQspO3tinamSM2ZuRo4dvcQ2a38C38LAQ
-+HBnvZ744Th3LckPMLTWNChe3E2jAt8Av0XA2yVJ/B+EeEaqSYDALKhI49CLeq96L
-+m/Vq/mqADborW51pMNFn7CAF1jxizQNHy6K0E95ziq8q/OL7j4+j8Erh4x7bcjrQ
-+X04Z+hrA9q5AjG++ieztKqGuGxHeSclqBhOdnU0UI528Vn0OXRxeMmbqMF+qhx17
-+nHuxxs4z5CIdTwHA6LgMUpDxcOhdUctIj32gwZM3UHI8lmdRTWn13y/Ht6CpIXCL
-+1ohSXne5y34z4AKeJQpdUfwQD552Ui8B+bhH1JBm5phjLn1fboXCYiCgnPQ+SJzx
-+3hsIv7Fji7lfk1UPkr0s7Ze8b/seYS8nVB5rg4qXEwFDMo9zsjCEIyg0tKwj5Ani
-+HlYzqjjsIK50TPjXYOA9J+NHcBDCDa3r8TBtRGtQqOXQGzvWTqAyT8Uwn7jimmh+
-+EGDr4PJSTJxv43EYL+of0sRHkOhnfFfJYF9vQLT+wD6l+6T1xNPE/gjX8DyQS9a3
-+zOgdOiTp0AKH
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-27-cert.pem b/test/fixtures/x509-escaping/alt-27-cert.pem
-new file mode 100644
-index 0000000000..268abdd300
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-27-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE0TCCArmgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+IDAeMBwGA1UdEQQVMBOgEQYFK84PDCKgCAwGYWJjMTIzMA0GCSqGSIb3DQEBCwUA
-+A4ICAQBtXT+t0fuBRClJdY6y01k1jqcsXEkmKOr4czznuiloGVEjpbjmxzxsgvzw
-+nz3od6Sx56SHG1xYbKDCapX9Ld2IDsPvpF2wdH2wpIS5DI7tQdBpLm7vr3vTYKwm
-+Wns+WKO5VBHDLCyuYvHNo37MJCAfBlr1ni7BCLOg3eycPiANJHPD2T9BnXlJm49K
-+166VMviuiLBEyO9tadhvQHGqCX3D4pW31zwsKHvS4wau15N4yt053Iac6eaysdTp
-+mspw5jX85tlQ9XxKNTftUVJU9Uzk2ll4A0Gvnq2FEjiqf6m3tye2nsqDI3C81Dwb
-+Y/+AeO7ZsVyLpIstfUBFmpLGPUoZ5MNmgrboGf8K8dPPgVbmbS0msrsI4LWSQb8P
-+R2hzj0F7bFvgbZad7rFXJW9FQOqTwvJrZBkkDpZpeNbhah14avV2Ftrc5+PtVfP0
-+jB1L3nhc5KGpGL4xqE19K+GVR/KBREgiFD7B7NYUOPt9NjFTrbbC3XA8L0MC7PNh
-+ySDN/NCiIF9K9MtpC8BYuNBlRt5C82L37qPY4Tw3z9sCyXK5oOQ4xdbdDEWdwzc5
-+F2S4zfQiB7y+C9RigOyGPChxBqDK/bCExrG1S2b95oP4QMuaL55iXnaG9ME8sCoa
-+cUd62cMPk7piQW29oFiQPYsStfo09u9JXbalKhol9oPrDtQfrQ==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-28-cert.pem b/test/fixtures/x509-escaping/alt-28-cert.pem
-new file mode 100644
-index 0000000000..147fba3aff
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-28-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE1DCCArygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+IzAhMB8GA1UdEQQYMBagFAYIKwYBBQUHCAegCBYGYWJjMTIzMA0GCSqGSIb3DQEB
-+CwUAA4ICAQA2KjgKCSLg/rDajrBTtVIu14rAP1pMwFZWrxcpTbN+fOs2dYQXZf7d
-+/GaozSMSchjPAJ8lTFfEB20Mur/E284LlQPuQKqHHn3gIh92VkHHBHjj0ohnfigg
-+eBHNMUisuGyNzKV7VI1+iwCoPBZC7ptbE4X08osVxxRESj+IT0TwtKDONTIIeogW
-+6VhsKTQ1HM6AMbhVe0Led/ENxFFMquB25GG/hVB4ZzPmsJZzNdZYNNMa34kNcMN3
-+5OFcxWV/4Hc77JYsqM9fE9gBaKC9pQE0XwIrOMQSaGYx+GO8Ty33YlM+oYBt6TMH
-+/9oU8HVvEYW9GAyptNbXPOwyv/wikNBsJyDGfvuDoiTZ9iMFb/bEoWHSK/rYmAgk
-+D272zxiPS3YgaZkvhlYZ+60w5CCgXoN5L0Zq9yAOTv92/VHFnMPrTP7zfD+4eUHY
-+lg+A7pOCIUK4cIDUXQefn1dU5/8DHJ8aM+KQDBfkKOH3me3GzIKjtKQjhwYFiJ8L
-+vD4V6+nq90GasShQDKUbMVbCxfyqlvrXOP0an+FxdknadnD5hRT3UsU9SRxAdkXi
-+3er2sXpuULYqOst55Ahnj7D5uDN4KBoatZwFd1iw0CVPoox7ixZ2zOAkwVqzaEAq
-+0yWyIlELm9/FdF78fu6LPrFKI1H4MH+0TQrF4MiyJWPvET7t8WKJsA==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-29-cert.pem b/test/fixtures/x509-escaping/alt-29-cert.pem
-new file mode 100644
-index 0000000000..434bda3e8e
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-29-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE1DCCArygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+IzAhMB8GA1UdEQQYMBagFAYIKwYBBQUHCAegCAwGYWJjMTIzMA0GCSqGSIb3DQEB
-+CwUAA4ICAQCIFfHE09aftJrS629ZBBRKjRiVcxN0/FjeEHWbnb+3Re/LoU/Y64BT
-+LmjMBB6wik3JxxUtLs2UYExQKfz3zmB+O99lR94of3V3RXPCe9Dz8C12iohYBvVO
-+q+WzXyg8g4zoIndn9+ByR+JJsuk+WVTZd50wRaRvssUB5yhpLaFdZpnLUBdV5J2d
-+shmefZxr0NgMb9p75wvWgZ2BiZQDeTR93+PWaZTMdSxZh6ynfG//5sxxw5fLm3pv
-+eVo3oQQ8px9j8G83ouiDZJn7XZgNfXYNq7wo3yaqXX0zlCE00K6tXGI6FkKJnVdQ
-+si+JYfGjzTM39JqFU9YYOOc3Gfw20iKIEQ0jnE0Z+z9Pv2GAel0UNdovluttxu9R
-+CJcPJOLS+TMd/sAwCAELvhPpeWsDLhfd+lG7ofE/nM6hzec6apWYyCqqlYIdE8WK
-+rtHXBIMGk/5Eo+2KDGQHgpMs/P8fNUL6FBx/i1pjm5nSHveDQryepEmOJq9NJCBW
-+1AJhE4jCXMv+43Fnr1OSATNiOd+1KfQ7KC5PFkpZLY4GDFZcbLBKYj1TWx4WzRnm
-+EW7cC/00Z3Cd76L5i+y1Xr44nbQcAMw6TlT6vvZjFCbCO+ZDUJSZBZMpWwBI/gAf
-+MNzYPltOGm+GZUuxib2MSF9Qy8c9NegENmsK+zyPT3N9mUHCl9nknA==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-3-cert.pem b/test/fixtures/x509-escaping/alt-3-cert.pem
-new file mode 100644
-index 0000000000..59185b64a4
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-3-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE1jCCAr6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+JTAjMCEGA1UdEQQaMBiGFmh0dHA6Ly9leGFtcGxlLmNvbS9hLGIwDQYJKoZIhvcN
-+AQELBQADggIBAEKwv45Zp5xJEGENPrOIwrGmuBDMtBPmXtSKydKSNUgrv08u4dHL
-+n295L7jIwQ3SnRjS8PrZWD8RQ46hgFRY9pqk1uTys4jB7lki0eAUBC7oPn7q0GUv
-+ojdSwOEjp5bfXyuRv7Z+3y2gD8pcCZsqcCjF5Svim6Q3pXMLRKQFhzhzL9k/gsNF
-+lJ8KcLBECJSm5nUrZIRHPdIGYmWJG+t8CfS3E6OIyHILK1xCc1MasEpmYVoY9uzT
-+2W2z+3pvwQqfdXO+lEOsT9dnjM/WbnkQMTWAn+++YFtkvA4kON4b/cp9imnXok02
-+vq7MCbN+b5CJXIhKMC5eNA36ez5hou0MUmnsNo9ai1gVJXRoL67YgUh1yMfcAaSM
-+Sfy3UBF++Az/yQo4AWtqWk4KPePdcsrYo9Fke1inUl+M12gkdIz+efbElHMqehbt
-+lunbyFI/7CY6/Tno+T1cDkQlTouHK8Ddb1cPhkJbE4euRuLGdtn2AcFSemYGtib0
-+ffuhnEBF8M8enPVyLjYA/3sELkmmaHMtgDTm0+XYQJtjIbvGcY7+bftPZgbXPVGv
-+7+tiYjwarIexXN5yzMasgFI5+7qLSQJHcmwrzOm8K+Bzx34f20vwR4M2FJ6cqUeN
-+qzdN1HSNp8aYNilaFa3+hfGRG9CZnVP8up8BwYx736EMu0G3yAp6UqqJ
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-30-cert.pem b/test/fixtures/x509-escaping/alt-30-cert.pem
-new file mode 100644
-index 0000000000..1b67d1f782
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-30-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE1TCCAr2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+JDAiMCAGA1UdEQQZMBegFQYIKwYBBQUHCAegCRYHYWJjAGRlZjANBgkqhkiG9w0B
-+AQsFAAOCAgEAgG06c7GRpPohHa1X/YQVQGWa/J/f3qok3cu1nrD2H5Dkw1eAVPcQ
-+lsng08lOxwSI0OgqJw0jl+ljLKuhHI3U68KbFmUO3Jw7uLDk1+UniRSNkfxVOrlc
-+7YTlmsxiDgQdX6/TAHu6bERx147NqVzB4/I6qpX7ouLv4E7xdQgjKuvhWlJ+Fg/0
-+pQ7EleQymRN6Y8qO6RwEWYao5pypg8/22cE3jgXleLM+5qWHqJs2ZewPQf7uo4Bf
-+IwSUV5H0weftiSN+kOLYiNfUago108VHuk5sCIKr92q4WAJgA5C6ylcUWaJCKbCv
-+HQYR/QG10Mrn4JCzzni90aBHrQoYQ8msEDH1QKyMJiNz6XXzwBP6bvgPlB2f7nPW
-+ERpH45M2I4Z3dZYFw8bF7CcOIUuR0/Zu2WN22IhqhjVQSZPzdRWJt5Rr1mFUz+Nv
-+Ymdi0w68KyRUiuOpKNLczDDnYpc9EqGBprnMOxALS4mQn1ySBXbZAXnTTdEzN5fM
-+L4CXWUzIBVKv56Mn5YskhbCd+N8GV9Nj/A6dBwa004CQxbgAj+ndNWc7+h4iSNlz
-+9VPHK2Kju6j4fVpe10jzSoEs0nnrsPy5Lxa6C4KhXBBJ3cPl6wWNe2mgbEqG9Pq2
-+KrCizuFkIfZTAeSrR+prZXLw6cjmKPPEtNbK2JbteL2SEDT/3AjmmZE=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-4-cert.pem b/test/fixtures/x509-escaping/alt-4-cert.pem
-new file mode 100644
-index 0000000000..086af8e02e
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-4-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE2DCCAsCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+JzAlMCMGA1UdEQQcMBqGGGh0dHA6Ly9leGFtcGxlLmNvbS9hJTJDYjANBgkqhkiG
-+9w0BAQsFAAOCAgEAPu7ubyZw1rOQJhFX6nBHyCYaBzaKxRZOHOFCjMrD/YQXPUNM
-+Hs+8ChOeQ4M82jTyiP7XgF8EumDcckDIlIYvGXGrCB/6VcCVL1vPPtzjSaiF3PlG
-+/dh0OlPvevr5Ajz7ZtFFwxeQ2EfsHiry8qnlDJSEjrh4Trcx9YzdkSZz8DaoODXz
-+ctR/p1JEnQ6h/Axa6hdqTzbzTsINN7gD5Wi3ObfQbK6Ug/CuH6Zr8bdTsmeGcnD0
-+fqHptuLVNcROykneYziXDzcqGwrZnYaOF54a4ibV/OfrBcgEKeDwsCrLs3nztSC4
-+whV7DXZwaLl2KWl4/suBNI1cIKbxII1xTFLTog+UYz0zSZGPrtbt7zrlM4yG033t
-+h9xIGUKebaNpQYkoxOc/+kKhbKCeL3klfxJoX+6Gf8DkTP7byX2HovfWV1rJbh57
-+YZ04Bh69VmyxE4iyb1tAh5xh1bArCR9m96eXS/0KIZbykxltQGyHf1jpWw/4Wi3n
-+oadkpMcyNX76M1xBJ5u03JL8+LWrXuzf/ScWdmPUWulAEhbo4fn4oRwP2C3l0vVQ
-+iL482cIq1zF91lssRwQ17k38phulRdm+7W65/VI7hLoG6lXiSiHLH8e39hHO8Jey
-+Z+BBvn8x+aFgIvpBK/MX35s0gSrl/UiIZPU9glnktSsX5D+aaQynbuvbOW8=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-5-cert.pem b/test/fixtures/x509-escaping/alt-5-cert.pem
-new file mode 100644
-index 0000000000..04a918008c
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-5-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE6jCCAtKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+OTA3MDUGA1UdEQQuMCyGKmh0dHA6Ly9leGFtcGxlLmNvbS9hLCBETlM6Z29vZC5l
-+eGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEANAyZnL8f81Aax/0Rhw3CCdcQ
-+SXF3dpAolObQB8rlirRZ7yOY1v3Poj411aV0x9zM6mjOJZwarUTL7kbO7odQxGhB
-+x7O0DvUoG15VTvs0XLNHTPgnXtNjKOZ7XXVMzb46APfYSqdzMqhRWfy+Iaikp494
-+urtqkVt05q2amzq7EXbXI8JQWhkJkhjBTowfZnpZUw4JeeqMNRZT9Ldv2XDZjaYS
-+lkHOLzTmSmm2mf1oxhKGcRCgUCr/pzVUfDA3RBz25a6PWAQt4b2r8k5jydWyOeCZ
-++sjacoK5/E1PcdaOFJAjuAfbRMeK/gz2+yJwaB39Yh77t/9vQC0G6aiAmO0HxjJE
-+L6Lb8BG/QNYBS7gGhzKFVXVVv5yXRioO9vMv0i8uxShqD2Lo/MbrNtRgi3eMFESd
-+3NxUPXS1jMq2/SaXrENdKqNNi06LbnLaYpI3BLZ/Katq0V9ESlhcC2nT5uNBPiLr
-+DNSekaIGobbTDkuV896L7jqsQpU+sgs4XqaISGgk2wAfnwbfpeiBCL8oH9yCYAO0
-+1YlevrMGjBNvhysoABv7qaorqeL97ffRhjOZ72/fm2axD5l9MvWEFIf7L5uOah0f
-+hF5vScQYgyWNuK8wjzT2tl0CuxvEyI7N4fkUEk+ZMkyI1Obx17p+d4SFyuq7wTXR
-+05oWMsCMDyzxvFDv92w=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-6-cert.pem b/test/fixtures/x509-escaping/alt-6-cert.pem
-new file mode 100644
-index 0000000000..6643519957
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-6-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIEyzCCArOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+GjAYMBYGA1UdEQQPMA2CC2V45G1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQBB
-+lBfIjUH7/PbpC00TWTOSR6sAzyBr681lSxYAgFLduDdfR/bTkI1p7txIAgennoUq
-++9slIIMaR799BUtQDfAQRYdbsWiG/+5Lj3JXs33LPPTdW1C97LOPlnnbRJh1sjbi
-+UfGdxvdPA6iuyWhfwPZd+4IrcN+kefkvEnRkvDMGwmfmKQDjbu2mSIAIe+ECyLLu
-+wdSI2sPBSUKQEKk+dABYq9TcdxlA+OSPjgs5ZF3NK3s/or7ay2r/i8be5TswY4Up
-+IwByEk+7AST6ijwi3P8EN0HAyyuOfpBelWZCQgdEGt40Mpa58AwBGqdrCZ5wDAz5
-+nBx6GscZUsqG9sVM71Tgq7Bc1b69FXUYAhmFucnXizHv1Ys0oGQVza1tkKbaLEFQ
-+WvXWc7zW/0hTzvmtogKn/oM6GoNcQiW8KCwaCJq1TTv7Tip9znfB496tDruOr+2w
-+HoqZTJ7ERklz0mlZ38ISTuaz+Qkn1KjBYh4tgP/wZIjIyppAaAr+JdqXzBejfb4M
-+6x0S1AG9QgvyR1xDv3Vljjkh3m55kktTWSOfjS6aSzomaAyVAgi/vhHkxhsoBhgQ
-+41+ffkhM9ps9wkmguwqOXsByQAZUQEJQigO39qYuGuJEDV8Bu8i/T5BuuJWP4BRF
-+X+now5ObP73ufyFwYGsSgblivHUX4z/zAt4kp4AMXw==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-7-cert.pem b/test/fixtures/x509-escaping/alt-7-cert.pem
-new file mode 100644
-index 0000000000..6c0f287a1b
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-7-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE0jCCArqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+ITAfMB0GA1UdEQQWMBSCEiJldmlsLmV4YW1wbGUuY29tIjANBgkqhkiG9w0BAQsF
-+AAOCAgEAKmYr4QEnNq1Sy9lYePNRR60jufFXk44bczNT/wA6kvXKgv472V9wltVb
-+yJVvYUWkTO8ahlELNLfqRcuih6myV64WJoewog8mwby0lBYr6bAz86DdeN/B9rFD
-+OYnev1Ux4um45l42XP8acgJCoqn8+EE+H4AeMrz2xxHt+IDy4vUOowZna82f1Pcp
-+O+vhod2uXlukfnhofVK4lMHl4++4kECkmUYl8U+L/zXwzOb4S3Yksffmadgo7ERk
-+rJYLMLztvCk6TtP+p4NcvrE90dmss7R8hfw3asfjXsRbAMigdfSMKzGB2IHoHeV6
-+fpmJy6kotfwulDrbr2QtrWOYdMrm1wT6ohT355KZQxcZr3VcK9gqEjcYafqIsXtA
-+wYAaorKXaz7UkmFCDbk/24UuHgNgCl4KkGsFNwW6whTMpb9WnvPR7F798tiIbOL+
-+FK6yA1q3Z2500lmloQWcUFBX48DViG3bsTJ9wmQ28aPqHVd5gTmTm/7W2iRGx36N
-+PmbAk17J/bUzUSORgrPi2FLNNFg64x40pfdAyrF9ZBNcsVCFCUgOQHgMh4OjX/n7
-+khmNbMYiOvJEoUbZ9flNr4AYY3ucpxQ2peTl4DNsVZZ8Xyh96h3URu63Ji9+xLrQ
-+jSUtNHUCJaC3E9yTaIDc8jMli9s5/ElDZRkPxRP8o4VOt9KcLvU=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-8-cert.pem b/test/fixtures/x509-escaping/alt-8-cert.pem
-new file mode 100644
-index 0000000000..201b520f8b
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-8-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIExDCCAqygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+EzARMA8GA1UdEQQIMAaHBAgICAgwDQYJKoZIhvcNAQELBQADggIBAHfvavrzBLuS
-+MMJwNkJGVt1W856zeZ6NZJ5vx2ZXziYxAkzw9N0pLHwgfzS8pXEPSZ6vMoeYMaH0
-+zr/S5tHSMGEwOp/dIoxE4Hm1uMzugHFxNp34hvqsaDbwKMpQQzEPhN1QvAkD9IXL
-+H2wOLqm+ZaTkT3OvOyJoml56wyUJ0nU746RuXgJHTFiWsUTPqT9bvofedC80MUyH
-+MX2lA1oy8nzJa9h7JqsxOE4uccRhpCRf+PxeYvOdsUxyDWw8+rjwe4Ulr0yVjwnD
-+x9ha/fTl96mYXyJGLtQvZmkllrctxcs0o82+wMZWBw4iPH/VnI7dj36b2uIHdrrf
-+cVurEPcVE03zLwukjQPZh9otleTwmQI1wqg/Gm2OahXy/0f0fpBDQnPycczn8nFw
-+nj6avmHubWVvzmEoKmOtavGEAbUn7ntQfsvM5JpiM+ck3MDMP9i9cMZvWKH8Eial
-+ZnYcXkgAatWwp4Cbsv4H7LMNisKjrcY+r+MpaYYIpTRNp/s/P5bMCIVt07yosePg
-+m9VWy03+hQJmD4/THeJsjuczPSBtsoJiKoTJ5TndmpFaG6J6lBVvpXJhoiW/QIgX
-+u2QIb8Z6bRK/eQ8UVYm0/ZQLN+OOzYiQfm0AFbFpYhl46o6QNZ03P6GRLshv+N3E
-+CX66ucPLd4QJitUy39LZjMlC0YxTZUry
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/alt-9-cert.pem b/test/fixtures/x509-escaping/alt-9-cert.pem
-new file mode 100644
-index 0000000000..660e65b8ed
---- /dev/null
-+++ b/test/fixtures/x509-escaping/alt-9-cert.pem
-@@ -0,0 +1,28 @@
-+-----BEGIN CERTIFICATE-----
-+MIIExDCCAqygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+EzARMA8GA1UdEQQIMAaHBAgIBAQwDQYJKoZIhvcNAQELBQADggIBAIefUJjnOtt8
-+viFkr3lupabUMwSgtBXVCp+M9xhKqcSnYReSgg/LcqVDaXmU4s23n0Bc0M51HQMG
-+puTpfr34ZUSQiLup9huELm5L+lcpYANJsKrBo+vz1w+fkPlcxXvXHpLzgb393XSJ
-+/Prn7lNBrrh9b74azUEhz1KPmFbbMs7IwlhE1+stQ107VeSGvKlAOmaYdnVG1PXl
-+AG7KJynpE5Ex8XF1ONQLneTdvo8gXZueb07SY+my5wrCQhSlh4/6Y2MnE9h+9ugx
-+BfdU72okDaYRH1MAfFeAsUE7Y52cQqm26b7nBz0+IeP+uk7oqDLF+PGHfjeUGXGW
-+aGFfaLk8Dl2gMg1DsRE8zcT215Dl4rqOtwbhW8kX7XzYE0sA7cnyZ0daLrrtxwe6
-+MhrAOjYklRZpwUvy6E2IyipKwWSuKHLUk3mVxPrxVqvye2enZWW1PJeHNdL//Ogx
-+5Mm++BOTNR+61pg/UrATlO3GMK6ggAfkP8H1r3jp24hc/TkXRkoUuWZqtjC5+qwB
-+KVIPlr+/0zIhzDjNbN0TMgqv/Yz4/wCUjsmCPJu21C3+BP2O5ZD2e4hYe/X9kuhC
-+YGWTf8dpq0LgYgVHqwXo0gCU/Ich9KtaJmCgZRUrzMl1aIYhqpuR2EW8H1bs3a0P
-+/7wXhGudHCwm6j2H5/tbsREeYInl3mv4
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/create-certs.js b/test/fixtures/x509-escaping/create-certs.js
-new file mode 100644
-index 0000000000..b84547e1d0
---- /dev/null
-+++ b/test/fixtures/x509-escaping/create-certs.js
-@@ -0,0 +1,502 @@
-+'use strict';
-+
-+const asn1 = require('asn1.js');
-+const crypto = require('crypto');
-+const { writeFileSync } = require('fs');
-+const rfc5280 = require('asn1.js-rfc5280');
-+const BN = asn1.bignum;
-+
-+const oid = {
-+ commonName: [2, 5, 4, 3],
-+ countryName: [2, 5, 4, 6],
-+ localityName: [2, 5, 4, 7],
-+ rsaEncryption: [1, 2, 840, 113549, 1, 1, 1],
-+ sha256WithRSAEncryption: [1, 2, 840, 113549, 1, 1, 11],
-+ xmppAddr: [1, 3, 6, 1, 5, 5, 7, 8, 5],
-+ srvName: [1, 3, 6, 1, 5, 5, 7, 8, 7],
-+ ocsp: [1, 3, 6, 1, 5, 5, 7, 48, 1],
-+ caIssuers: [1, 3, 6, 1, 5, 5, 7, 48, 2],
-+ privateUnrecognized: [1, 3, 9999, 12, 34]
-+};
-+
-+const digest = 'SHA256';
-+
-+const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
-+ modulusLength: 4096,
-+ publicKeyEncoding: {
-+ type: 'pkcs1',
-+ format: 'der'
-+ }
-+});
-+
-+writeFileSync('server-key.pem', privateKey.export({
-+ type: 'pkcs8',
-+ format: 'pem'
-+}));
-+
-+const now = Date.now();
-+const days = 3650;
-+
-+function utilType(name, fn) {
-+ return asn1.define(name, function() {
-+ this[fn]();
-+ });
-+}
-+
-+const Null_ = utilType('Null_', 'null_');
-+const null_ = Null_.encode('der');
-+
-+const IA5String = utilType('IA5String', 'ia5str');
-+const PrintableString = utilType('PrintableString', 'printstr');
-+const UTF8String = utilType('UTF8String', 'utf8str');
-+
-+const subjectCommonName = PrintableString.encode('evil.example.com', 'der');
-+
-+const sans = [
-+ { type: 'dNSName', value: 'good.example.com, DNS:evil.example.com' },
-+ { type: 'uniformResourceIdentifier', value: 'http://example.com/' },
-+ { type: 'uniformResourceIdentifier', value: 'http://example.com/?a=b&c=d' },
-+ { type: 'uniformResourceIdentifier', value: 'http://example.com/a,b' },
-+ { type: 'uniformResourceIdentifier', value: 'http://example.com/a%2Cb' },
-+ {
-+ type: 'uniformResourceIdentifier',
-+ value: 'http://example.com/a, DNS:good.example.com'
-+ },
-+ { type: 'dNSName', value: Buffer.from('exämple.com', 'latin1') },
-+ { type: 'dNSName', value: '"evil.example.com"' },
-+ { type: 'iPAddress', value: Buffer.from('08080808', 'hex') },
-+ { type: 'iPAddress', value: Buffer.from('08080404', 'hex') },
-+ { type: 'iPAddress', value: Buffer.from('0008080404', 'hex') },
-+ { type: 'iPAddress', value: Buffer.from('000102030405', 'hex') },
-+ {
-+ type: 'iPAddress',
-+ value: Buffer.from('0a0b0c0d0e0f0000000000007a7b7c7d', 'hex')
-+ },
-+ { type: 'rfc822Name', value: 'foo@example.com' },
-+ { type: 'rfc822Name', value: 'foo@example.com, DNS:good.example.com' },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode('Hannover', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode('München', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode('Berlin, DNS:good.example.com', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode('Berlin, DNS:good.example.com\0evil.example.com', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode(
-+ 'Berlin, DNS:good.example.com\\\0evil.example.com', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode('Berlin\r\n', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'directoryName',
-+ value: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ {
-+ type: oid.countryName,
-+ value: PrintableString.encode('DE', 'der')
-+ }
-+ ],
-+ [
-+ {
-+ type: oid.localityName,
-+ value: UTF8String.encode('Berlin/CN=good.example.com', 'der')
-+ }
-+ ]
-+ ]
-+ }
-+ },
-+ {
-+ type: 'registeredID',
-+ value: oid.sha256WithRSAEncryption
-+ },
-+ {
-+ type: 'registeredID',
-+ value: oid.privateUnrecognized
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.xmppAddr,
-+ value: UTF8String.encode('abc123', 'der')
-+ }
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.xmppAddr,
-+ value: UTF8String.encode('abc123, DNS:good.example.com', 'der')
-+ }
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.xmppAddr,
-+ value: UTF8String.encode('good.example.com\0abc123', 'der')
-+ }
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.privateUnrecognized,
-+ value: UTF8String.encode('abc123', 'der')
-+ }
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.srvName,
-+ value: IA5String.encode('abc123', 'der')
-+ }
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.srvName,
-+ value: UTF8String.encode('abc123', 'der')
-+ }
-+ },
-+ {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.srvName,
-+ value: IA5String.encode('abc\0def', 'der')
-+ }
-+ }
-+];
-+
-+for (let i = 0; i < sans.length; i++) {
-+ const san = sans[i];
-+
-+ const tbs = {
-+ version: 'v3',
-+ serialNumber: new BN('01', 16),
-+ signature: {
-+ algorithm: oid.sha256WithRSAEncryption,
-+ parameters: null_
-+ },
-+ issuer: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ { type: oid.commonName, value: subjectCommonName }
-+ ]
-+ ]
-+ },
-+ validity: {
-+ notBefore: { type: 'utcTime', value: now },
-+ notAfter: { type: 'utcTime', value: now + days * 86400000 }
-+ },
-+ subject: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ { type: oid.commonName, value: subjectCommonName }
-+ ]
-+ ]
-+ },
-+ subjectPublicKeyInfo: {
-+ algorithm: {
-+ algorithm: oid.rsaEncryption,
-+ parameters: null_
-+ },
-+ subjectPublicKey: {
-+ unused: 0,
-+ data: publicKey
-+ }
-+ },
-+ extensions: [
-+ {
-+ extnID: 'subjectAlternativeName',
-+ critical: false,
-+ extnValue: [san]
-+ }
-+ ]
-+ };
-+
-+ // Self-sign the certificate.
-+ const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der');
-+ const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey);
-+
-+ // Construct the signed certificate.
-+ const cert = {
-+ tbsCertificate: tbs,
-+ signatureAlgorithm: {
-+ algorithm: oid.sha256WithRSAEncryption,
-+ parameters: null_
-+ },
-+ signature: {
-+ unused: 0,
-+ data: signature
-+ }
-+ };
-+
-+ // Store the signed certificate.
-+ const pem = rfc5280.Certificate.encode(cert, 'pem', {
-+ label: 'CERTIFICATE'
-+ });
-+ writeFileSync(`./alt-${i}-cert.pem`, `${pem}\n`);
-+}
-+
-+const infoAccessExtensions = [
-+ [
-+ {
-+ accessMethod: oid.ocsp,
-+ accessLocation: {
-+ type: 'uniformResourceIdentifier',
-+ value: 'http://good.example.com/\nOCSP - URI:http://evil.example.com/',
-+ },
-+ },
-+ ],
-+ [
-+ {
-+ accessMethod: oid.caIssuers,
-+ accessLocation: {
-+ type: 'uniformResourceIdentifier',
-+ value: 'http://ca.example.com/\nOCSP - URI:http://evil.example.com',
-+ },
-+ },
-+ {
-+ accessMethod: oid.ocsp,
-+ accessLocation: {
-+ type: 'dNSName',
-+ value: 'good.example.com\nOCSP - URI:http://ca.nodejs.org/ca.cert',
-+ },
-+ },
-+ ],
-+ [
-+ {
-+ accessMethod: oid.privateUnrecognized,
-+ accessLocation: {
-+ type: 'uniformResourceIdentifier',
-+ value: 'http://ca.example.com/',
-+ },
-+ },
-+ ],
-+ [
-+ {
-+ accessMethod: oid.ocsp,
-+ accessLocation: {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.xmppAddr,
-+ value: UTF8String.encode('good.example.com', 'der'),
-+ },
-+ },
-+ },
-+ {
-+ accessMethod: oid.ocsp,
-+ accessLocation: {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.privateUnrecognized,
-+ value: UTF8String.encode('abc123', 'der')
-+ },
-+ },
-+ },
-+ {
-+ accessMethod: oid.ocsp,
-+ accessLocation: {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.srvName,
-+ value: IA5String.encode('abc123', 'der')
-+ }
-+ }
-+ },
-+ ],
-+ [
-+ {
-+ accessMethod: oid.ocsp,
-+ accessLocation: {
-+ type: 'otherName',
-+ value: {
-+ 'type-id': oid.xmppAddr,
-+ value: UTF8String.encode('good.example.com\0abc123', 'der'),
-+ },
-+ },
-+ },
-+ ],
-+];
-+
-+for (let i = 0; i < infoAccessExtensions.length; i++) {
-+ const infoAccess = infoAccessExtensions[i];
-+
-+ const tbs = {
-+ version: 'v3',
-+ serialNumber: new BN('01', 16),
-+ signature: {
-+ algorithm: oid.sha256WithRSAEncryption,
-+ parameters: null_
-+ },
-+ issuer: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ { type: oid.commonName, value: subjectCommonName }
-+ ]
-+ ]
-+ },
-+ validity: {
-+ notBefore: { type: 'utcTime', value: now },
-+ notAfter: { type: 'utcTime', value: now + days * 86400000 }
-+ },
-+ subject: {
-+ type: 'rdnSequence',
-+ value: [
-+ [
-+ { type: oid.commonName, value: subjectCommonName }
-+ ]
-+ ]
-+ },
-+ subjectPublicKeyInfo: {
-+ algorithm: {
-+ algorithm: oid.rsaEncryption,
-+ parameters: null_
-+ },
-+ subjectPublicKey: {
-+ unused: 0,
-+ data: publicKey
-+ }
-+ },
-+ extensions: [
-+ {
-+ extnID: 'authorityInformationAccess',
-+ critical: false,
-+ extnValue: infoAccess
-+ }
-+ ]
-+ };
-+
-+ // Self-sign the certificate.
-+ const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der');
-+ const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey);
-+
-+ // Construct the signed certificate.
-+ const cert = {
-+ tbsCertificate: tbs,
-+ signatureAlgorithm: {
-+ algorithm: oid.sha256WithRSAEncryption,
-+ parameters: null_
-+ },
-+ signature: {
-+ unused: 0,
-+ data: signature
-+ }
-+ };
-+
-+ // Store the signed certificate.
-+ const pem = rfc5280.Certificate.encode(cert, 'pem', {
-+ label: 'CERTIFICATE'
-+ });
-+ writeFileSync(`./info-${i}-cert.pem`, `${pem}\n`);
-+}
-diff --git a/test/fixtures/x509-escaping/google/intermediate.pem b/test/fixtures/x509-escaping/google/intermediate.pem
-new file mode 100644
-index 0000000000..9d2aeb32c4
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/intermediate.pem
-@@ -0,0 +1,11 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBjjCCATSgAwIBAgIBAjAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDEwRSb290MCAX
-+DTAwMDEwMTAwMDAwMFoYDzIwOTkwMTAxMDAwMDAwWjAXMRUwEwYDVQQDEwxJbnRl
-+cm1lZGlhdGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM
-+qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY
-+tM/Bo3cwdTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQlGcYbYohaK3S+XGeq
-+CTi4LLHeLTAfBgNVHSMEGDAWgBQlGcYbYohaK3S+XGeqCTi4LLHeLTAiBgNVHR4B
-+Af8EGDAWoBQwEoIQYXR0YWNrZXIuZXhhbXBsZTAKBggqhkjOPQQDAgNIADBFAiEA
-+uZhmF3buUdhzHjXLZQSOyT41DqUUX/VKBEraDu+gj+wCIG/R1arbHFRFnEuoVgZI
-+bihwUpUZjIZ5YwJcBu6yuXlZ
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/google/key.pem b/test/fixtures/x509-escaping/google/key.pem
-new file mode 100644
-index 0000000000..102a9d8816
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/key.pem
-@@ -0,0 +1,5 @@
-+-----BEGIN PRIVATE KEY-----
-+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaNbpDxJET5xVHxd/
-+ig5x2u2KUIe0jaCVWqarpIN/582hRANCAAR7DaOQvpvA47q2XxjMqxJVf/FvZm2f
-+tiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkYtM/B
-+-----END PRIVATE KEY-----
-diff --git a/test/fixtures/x509-escaping/google/leaf0.pem b/test/fixtures/x509-escaping/google/leaf0.pem
-new file mode 100644
-index 0000000000..ce19dc9699
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/leaf0.pem
-@@ -0,0 +1,10 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBajCCARCgAwIBAgIBAzAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l
-+ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV
-+BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM
-+qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY
-+tM/Bo1MwUTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ
-+OLgssd4tMCAGA1UdEQQZMBeCFWJsYWguYXR0YWNrZXIuZXhhbXBsZTAKBggqhkjO
-+PQQDAgNIADBFAiEA4NgHDxVrBjNW+So4MrRZMwDknvjRaBsB4j2IwVRKl4sCIDpg
-+Bhm4ZdHwlUYrALkXa3dFBy8kXBkVumY7UJpbB2mO
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/google/leaf1.pem b/test/fixtures/x509-escaping/google/leaf1.pem
-new file mode 100644
-index 0000000000..0b45056656
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/leaf1.pem
-@@ -0,0 +1,10 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBdTCCARygAwIBAgIBBDAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l
-+ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV
-+BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM
-+qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY
-+tM/Bo18wXTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ
-+OLgssd4tMCwGA1UdEQQlMCOCCm5vZGVqcy5vcmeCFWJsYWguYXR0YWNrZXIuZXhh
-+bXBsZTAKBggqhkjOPQQDAgNHADBEAiAOFFOCfA6c/iZWxbDn5QMjNdtZbtJPBcRv
-+uEgSqWrGTAIgK5RK0xGK8UZb2aM2VjGNTYozlcwKaLgQukA+UnKrrJg=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/google/leaf2.pem b/test/fixtures/x509-escaping/google/leaf2.pem
-new file mode 100644
-index 0000000000..9cf03fae7d
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/leaf2.pem
-@@ -0,0 +1,10 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBejCCASCgAwIBAgIBBTAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l
-+ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV
-+BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM
-+qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY
-+tM/Bo2MwYTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ
-+OLgssd4tMDAGA1UdEQQpMCeCJW5vZGVqcy5vcmcsIEROUzpibGFoLmF0dGFja2Vy
-+LmV4YW1wbGUwCgYIKoZIzj0EAwIDSAAwRQIgWfT1VXQA79PxgM0DsfeoiwZCc2Be
-+v3/RCRYoRky9DgICIQDUTjndnBQ0KeIWhuMjtSz1C5uPUYofKe7pV2qb/57kvA==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/google/leaf3.pem b/test/fixtures/x509-escaping/google/leaf3.pem
-new file mode 100644
-index 0000000000..55a64fdc89
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/leaf3.pem
-@@ -0,0 +1,10 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBZzCCAQ2gAwIBAgIBBjAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l
-+ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV
-+BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM
-+qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY
-+tM/Bo1AwTjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ
-+OLgssd4tMB0GA1UdEQQWMBSGEmh0dHBzOi8vbm9kZWpzLm9yZzAKBggqhkjOPQQD
-+AgNIADBFAiEArZgaxFBuPYFWCXeFTkXhV57MKxG/tIJ2Z3Wzts2Im7QCICoukuRf
-+EsQN7g6h30fRuLOIdbfCCduc7YVpkkSlwe99
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/google/leaf4.pem b/test/fixtures/x509-escaping/google/leaf4.pem
-new file mode 100644
-index 0000000000..668a659f45
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/leaf4.pem
-@@ -0,0 +1,10 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBdTCCARugAwIBAgIBBzAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l
-+ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMDwxHzAdBgNV
-+BAsMFm9yZyB1bml0CkNOPW5vZGVqcy5vcmcxGTAXBgNVBAMTEGF0dGFja2VyLmV4
-+YW1wbGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjMqxJV
-+f/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkYtM/B
-+ozEwLzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJOLgs
-+sd4tMAoGCCqGSM49BAMCA0gAMEUCIQCpchwik2NT0v8ifDT8aMqOLv5YwqB7oeOu
-+LincYQYMagIgZc2U7DBrdEAWNfuAJx4I+ZkluIcswcdnOhbriOrTSHg=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/google/root.pem b/test/fixtures/x509-escaping/google/root.pem
-new file mode 100644
-index 0000000000..68eb00ae86
---- /dev/null
-+++ b/test/fixtures/x509-escaping/google/root.pem
-@@ -0,0 +1,9 @@
-+-----BEGIN CERTIFICATE-----
-+MIIBQTCB56ADAgECAgEBMAoGCCqGSM49BAMCMA8xDTALBgNVBAMTBFJvb3QwIBcN
-+MDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNVBAMTBFJvb3Qw
-+WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjMqxJVf/FvZm2f
-+tiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkYtM/BozIwMDAP
-+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQlGcYbYohaK3S+XGeqCTi4LLHeLTAK
-+BggqhkjOPQQDAgNJADBGAiEA+Y5oEpcG6aRK5qQFLYRi2FrOSSLF1/dI4HtBh0mk
-+GFoCIQD1DpNg6m5ZaogRW1mY1wmR5HFIr3gG8PYDRimQogXUxg==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/info-0-cert.pem b/test/fixtures/x509-escaping/info-0-cert.pem
-new file mode 100644
-index 0000000000..6872b9870a
---- /dev/null
-+++ b/test/fixtures/x509-escaping/info-0-cert.pem
-@@ -0,0 +1,30 @@
-+-----BEGIN CERTIFICATE-----
-+MIIFDTCCAvWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+XDBaMFgGCCsGAQUFBwEBBEwwSjBIBggrBgEFBQcwAYY8aHR0cDovL2dvb2QuZXhh
-+bXBsZS5jb20vCk9DU1AgLSBVUkk6aHR0cDovL2V2aWwuZXhhbXBsZS5jb20vMA0G
-+CSqGSIb3DQEBCwUAA4ICAQAAd/bIBmSIOJg+Rp96/BDpsZQYgYTyBNWrnBkuHQ0M
-+bovgqEEI/5xiYGEzXhrzmWrUoG40PDeVrpCSsW5m+bsO4zDQeWW5mXejbr0Iwflf
-+TYDxwGUUakAcZ1c5yJ/ABjKy0Tocb9bSzln+tc+HNStp86bbgrhb/wjddn6ca21V
-+cuNFZbN+0SM0LxcWO8oGKXF0HFo0durGhamcH5B/D38FYkaVR5QXoOsWVqtPFjW2
-+t67rmKS6XKaz2JhZDpWDZmDofCoFu/zlkPHXkq7yyrkJ/8qpJCznkZmLn+B1WA+y
-+SrSOYMpQ6RnzMx7wK5UafX5J+lMv16+LTb/n1KAd4zElcqt5eRPLcEuknIEgC2X/
-+AY1ooyN/Xb4QnqvtTmhzIDb7lzzMowi5QrG3rRYMldxG2Rdqwjc8qa5Tgh7EsiU8
-+A/n5X/6cxA1zoyakSHFXzGtazIkPc+zFfOaV1+gpJtd2vD2T+FrmkL1fgazuHXNZ
-+hAQq0RGZWPsCdxm7dG4w5bd3YgRKfD2ck+b9Imu0ta4pqMDHZYgncaeOuuHzHgXA
-+MIvxIG5JfwYUJLUqBUz8hwDVcNMpnscyn2msdpiwXK0AahucBQjbyZ6sovoxmgk5
-+xLdnq2GTtdghwdkF9DYK0ZekDlk1XWbP0tR5Cevo6WlMx+cbEBG+OSfNd8/dFrkd
-+aw==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/info-1-cert.pem b/test/fixtures/x509-escaping/info-1-cert.pem
-new file mode 100644
-index 0000000000..05247873d8
---- /dev/null
-+++ b/test/fixtures/x509-escaping/info-1-cert.pem
-@@ -0,0 +1,31 @@
-+-----BEGIN CERTIFICATE-----
-+MIIFVTCCAz2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+gaMwgaAwgZ0GCCsGAQUFBwEBBIGQMIGNMEUGCCsGAQUFBzAChjlodHRwOi8vY2Eu
-+ZXhhbXBsZS5jb20vCk9DU1AgLSBVUkk6aHR0cDovL2V2aWwuZXhhbXBsZS5jb20w
-+RAYIKwYBBQUHMAGCOGdvb2QuZXhhbXBsZS5jb20KT0NTUCAtIFVSSTpodHRwOi8v
-+Y2Eubm9kZWpzLm9yZy9jYS5jZXJ0MA0GCSqGSIb3DQEBCwUAA4ICAQCbwqw8YKIt
-+Ht9qegR076xpnxuiH0THPGsgazvhCmEr5YHJ68sR1LexjneQDhpNXcnpYpfk6J4d
-+Tu0ApMSbVypFyHcd88g0qVYI9JF+CTNnzut/Zn6xgnUjVjrSz6SZPhkMcBX9ahtY
-+tzswzcyTzso5Do5pxvCWDI+bshgIhC3CYNyAjyOyyhnQrwcOcoatlhDmX1fCk+dC
-+fhmzurBFNIz2gwDC7aRjcaUdTIlYnd6qHk5xLs3neBm44gNk17GazPIPo04LTKXs
-+ZYzvDEUAdJ2FJMiYqSvvEv4k9ozx5HtwtncZpu46El2PQRANgj1UhemYVmHfbdU+
-+7Q+rCv+Loq2v76fddhc1cM3gCQ+6SW2QmRo2rShRGxpuSuZiTngwgdQEGrkQq7Sv
-+r695V7NlHWJgvv1r49wGmqWkviH5l6A0QdzL6TNYhwqCRsjxgsvCZUpOlZPASiME
-+jhwBIOMy1YUSdEMnBrbuemawvbfocSuUlHaodwLZvwMgqHvNz/8ebMyRyyZrnmCx
-+TYh8d0JIcA57VvfaZvvsPPV7TO7WLoJgbmuqM02JzzkJMh0fbt2oi1cqJL65V5Sn
-+z0sXh/A/BzB4QawI93f9m0hX7RtuT1SolTNVyhg7dm1MwfO8khpfz5LLgflVwgN8
-+6egKc6L755SlqZRMT03txH2UCBizLz1gjA==
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/info-2-cert.pem b/test/fixtures/x509-escaping/info-2-cert.pem
-new file mode 100644
-index 0000000000..06212d4e12
---- /dev/null
-+++ b/test/fixtures/x509-escaping/info-2-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE5DCCAsygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+MzAxMC8GCCsGAQUFBwEBBCMwITAfBgUrzg8MIoYWaHR0cDovL2NhLmV4YW1wbGUu
-+Y29tLzANBgkqhkiG9w0BAQsFAAOCAgEABR5VyTZEQ0AQvdqlk+IDQT85qyf891eN
-+BREiSg5KCei9Kmubv3ZJGoNVwZgybr5sCi5GqWOtG7S0GXvzS6c2Qy+cW0R4DDYs
-+s6IIUn+ex1XygGrRHTDHu6tEUwSJMmOMKBh+iLjhtamD+YHjgOLG3MfadO5/9mvp
-+r412MPhU1VvQ3FC3dZmBUW2gIKNEU4mzwISgPkLJXmBsnxu8F9YqHPgppqsfJ9AF
-+KIc2nX7N3s8w9fCc03FrihdkE2C802jy71px5aPqa1xrIT/YBq/1fKTcYRAWF/pd
-+iy2G1v0pz0kYu2/yPIC/xlFcUgeFqR/biwxAD9T9rp7rq+dpIJA5BUCpXVULqhY1
-+SVZ22WKS0NR5rbu4BPDMShTOiwaDSwFQtI0OxM0g5zVFVjFOc6YbFu7ZyfLQ582S
-+vgVU5/vaHANnEsCSUegXyLofqxTMPbM1rqibFmv2A4pm1Mp18ZFmqwh8cm6C0f7F
-+qjdzBuSkcktTCq/dLX5yTm9aocyzye9cfNBjiGUregJEF7sD3nzsokEGj+S320w2
-+5yUl95xgrHr+5bdDUEox+trTeBnddC4VxrieeH+Wv45try0Go48yK7b1Aqfu9G4B
-+B/as+upQ+YjMG8mAe6JJ9JibpTvTmatYAsssEKT1vDZ5trqo4C5/utfbuyaf7qtx
-+O+jFfYToPtE=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/info-3-cert.pem b/test/fixtures/x509-escaping/info-3-cert.pem
-new file mode 100644
-index 0000000000..1825949bd3
---- /dev/null
-+++ b/test/fixtures/x509-escaping/info-3-cert.pem
-@@ -0,0 +1,30 @@
-+-----BEGIN CERTIFICATE-----
-+MIIFMDCCAxigAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+fzB9MHsGCCsGAQUFBwEBBG8wbTAqBggrBgEFBQcwAaAeBggrBgEFBQcIBaASDBBn
-+b29kLmV4YW1wbGUuY29tMB0GCCsGAQUFBzABoBEGBSvODwwioAgMBmFiYzEyMzAg
-+BggrBgEFBQcwAaAUBggrBgEFBQcIB6AIFgZhYmMxMjMwDQYJKoZIhvcNAQELBQAD
-+ggIBACR9nH4pRlcSIIF9DEExlJvLtkeFWHGIAYLBuauHmdzPdbq9Py9M5DOcc7yd
-+OQYVYwW26hASb+3CYzhRQaWKOR+T/OwP+QMUl5Y6nc3HzLdYTSen2LLAYHySXK3G
-+gTdOhmVQwdh+IzhpjLXC67/9gn/F1p73Ixv/0PBZzmC64DOp1ogso9RICu0xTAbo
-+h8mdN4/Tbh9Ikd89lb91x1Xf86NyC7ZvSA9dUO07/3B6B0kkqCdP9Ytlsrt2wbt3
-+2TVPp+ghjbPjdLrJUi3fbdC2CgjV2oLiYr1h7qn7SmYPNgOpDPKBI4Cei7UO+Wow
-+yLCxBO0HgLZKcZorJFofekPjqtQYYj1sw3OEIcifMAmoHT7H57onfoQbRDpt57k2
-+rHJKgzrRuT8Qbl3OHSkiWRE3u0S9kAg7QEq27e2fuvh23p+YHEiYIjAR9XLVh7/Q
-+EG5QDfDq3MvtgD/khAd36il61T5h8F4u3MhONFMuwJ/TYtGR6QINrv4DqLBM1pRr
-+LMApQYi0w/MCRj2wLeAro9NflE+PFDk+l44ojvnEUYAGUyIzWp80bjQrV7Up6sgQ
-+HehcmxxTrOmiqrfw08c1aHhmGeplmPpQEET1wIjnyj49sfdSPYxg5Lh+f/l79fLb
-+jFemE8otKfog84vNGbPFl/AHwxjKCeCA/MaNJz3y3RYVsZn6
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/info-4-cert.pem b/test/fixtures/x509-escaping/info-4-cert.pem
-new file mode 100644
-index 0000000000..8f1e69afec
---- /dev/null
-+++ b/test/fixtures/x509-escaping/info-4-cert.pem
-@@ -0,0 +1,29 @@
-+-----BEGIN CERTIFICATE-----
-+MIIE9jCCAt6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls
-+LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ
-+MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-+ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv
-+WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt
-+qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1
-+aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN
-+DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY
-+BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3
-+icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z
-+UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc
-+nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M
-+iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm
-+R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj
-+RTBDMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAaAlBggrBgEFBQcIBaAZDBdn
-+b29kLmV4YW1wbGUuY29tAGFiYzEyMzANBgkqhkiG9w0BAQsFAAOCAgEAQERLvjQB
-+E2fmTVgHbr4MVXPfse9Xxk9TK8/IhxDNnql4bor3xat5oP+tDHVRi2StajfIcJlX
-+C9blYOWg4w6QH3pmD6M7eQGOw7ntOUid4R2vhX3XiK3QB1h8lWSPFmSwBHA47mMJ
-+IkrKNIo9+M9b7M05YwbAENi3TPgT8h2Ej9V4DUjLIEhDcu8fSh3FkNpZ2HohZ2I3
-+QPe23FB052jX7uPfeZ9gcjL/iGxuTuPbKWxzZ/Gy2RmS8xfLkJESvvQ8a0H4f7Ij
-+yjn7qYUkY6FoHxyg5BU34YNaJCmfgzRIE53Kv2FMPwj2JaXmIguR+mSDAbc0xjw3
-+G3dRoCqhZugn8C6I5FhuXHdu6zSuuHtwOGEf07y5Im2sBsPVoq+Txh/mv3Zy9Ydy
-+0yCDuq87jKSZd7FKorHOEoQY94UMs33PYjS4h/hYWiysYUeR0mlbjr4gyv1KH6K8
-+JERGpI/OE+vzfOtgj/Z46/+wn7jF0LBCin7Jn5Zw1a1TNsiHKAjqW/P4vJxxUW++
-+FtYwJhI7XJehwNNFra9rSC5M4TkpaqAZnbPvWZWxWVJIEYFgNjnt+b/VOpRpv5bJ
-+7BOlVvP+56KF+vlmCnzVBmlHcr45sZUZ3mw3Sb6dcF0V0VaNQKw/F5EteQyafIIl
-+dvCwwV4OwLwPliPAvwYfVEI41Dv3mF4fN7k=
-+-----END CERTIFICATE-----
-diff --git a/test/fixtures/x509-escaping/package.json b/test/fixtures/x509-escaping/package.json
-new file mode 100644
-index 0000000000..37d9f2a938
---- /dev/null
-+++ b/test/fixtures/x509-escaping/package.json
-@@ -0,0 +1,12 @@
-+{
-+ "name": "x509-escaping",
-+ "version": "1.0.0",
-+ "description": "create certificates for x509-escaping test",
-+ "main": "createCert.js",
-+ "license": "SEE LICENSE IN ../../../LICENSE",
-+ "private": true,
-+ "dependencies": {
-+ "asn1.js": "^5.4.1",
-+ "asn1.js-rfc5280": "^3.0.0"
-+ }
-+}
-diff --git a/test/fixtures/x509-escaping/server-key.pem b/test/fixtures/x509-escaping/server-key.pem
-new file mode 100644
-index 0000000000..db1d2652d0
---- /dev/null
-+++ b/test/fixtures/x509-escaping/server-key.pem
-@@ -0,0 +1,52 @@
-+-----BEGIN PRIVATE KEY-----
-+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCxEWd00u9E9T/k
-+o6WcCKjhZ7tjnfVylnA7M0EHOwvdivgD46eAb1omsonLagiVrZrG7EpYuMhtz+g3
-+Yv1d0nvFvv8ge9UIdnN8EDTDzLpJ3KbNqHURraiXuBDqa3rdY4JBakCcuYHl1bj1
-+OTew7xl1FWc1je04rBTQGTFIRdmJZYyc9bIw9WkY6msod0w1PDcLhZS3emh/eYaL
-+4zAQWrVhQfWzf4rZzFaI/a5n0o75aUkTuvxDDQ51V2d6WkSU3KbOnf2JW+QJXfzs
-+NOeiYA9AnfY59evr4GEeG8VZdGuUG39uDCIWmAUT8elhXXqVq+NdBqc6VUNLDJbq
-+CmMx/Ecp48EHO6X5uXm0xViZIVPNIzqiiRhVt4nFfwPQZrTgaq2+tD7/zD1yED4O
-+1FhlDl5twH2N7+oG06HsEluQdLPrj7IedpneGVKMs078Ddov7j6icYv/RZHVetDl
-+rzDDHjLJWwxyAWzdGdkhtMGPd6B9i4TtF/PU3J3nbpLn5XfEBFu4jJ+w+5Wvk5a6
-+0gF1ERy/OLBM/e8sro2sEBIpp1tN1wJVBZOtTIi4VVDhwDRQUiwb2d1Re7GQ7+mc
-+z5D/01qxW6S+w0IKrpwJUjR3mpa0OU98KfKVJkeyeEBLkEhDdnGTDqZ9E/ickGos
-+rW2gAAYKgzXk725dpxTdpLEosfDbpwIDAQABAoICAAwUElkTPHQZQKsBiL38jzyU
-+/WDduQ0AexZmuCRcoEIUBTgKsvXdYqpqGmEwUfaX2YuBOc8Uh8OJ357Ll1nrjjre
-+fPvDxrPllJodZuQGVpzMOuqjd5zlmi8DRNAg1cg9TfjVXSPzuYsqiYvcw9JDdRqa
-+A6jRDiIEBwVs+oIiFaU8MpvQXL/fNbSX5QhlHuMwwNZ93beoV3F+ojFvpWswLNg+
-+DhsY86lIuYxttZRqdgtIZc49PpD6VoalmC7t8mivJofImi9g/8ytxx97umNGpzOy
-+ssWgY1/7NdS+czdXbDE1sPsaQ8cDxrDmGxPjswV7rK4/Um/1ufnoGXFMlRinS1lQ
-+nns4VAFefVUCk81LRyFb+X97NXPGC1p4zNlC1ZoihMgWKJBzH0uk5K/hURS/wDNZ
-+epm9ssnEQrFGJhEI+635srfn9SVRZ8xNh+oCguo5NaZm/BezC6iBQeoaBmVL2lY8
-+KLztN/JQd6MMZi3CWhTn0ZAtVNMxGjU9/yrdWIkX9EV8Sw68fqLGoKQXI67AOynQ
-+5AnUyEjhVu7M39gYL71l7BVpuG7qaX8l4brzBcgzFldvuhuNCx0SW4gU2/Nx4OwY
-+BLOX1LOrpD+5M9YwcbtSxcxz97nP8efb3hUK3QD2iuZ9Fa6zKWsoreMb7Jku38i7
-+e41lupAIkxxuxGBe1YrZAoIBAQDVF7Kru6tsaWtvJw5cbZpKxcuUHHQ0X3XRgA+H
-+uWfT8EbxmDpgcG8polqiYuXPFWcrElmtWeBCYXazGZocHRV8y+ri/9c2rMTH6Bni
-+TcYfsc4E8WY6adxfUqajgQ2zShdZbxZtBvSP50HheZ0a+L2qn2MWDUN/mbwYEmom
-+SonVx3MSJWm/Vrh5i4b/L/+9u7uumIjWYFK6pKdLerTfbXO7ZsNR9KDIOBLDnUcf
-++6K2vcclZN7aga1S7wTsrX+k9C/OQuj8ONMWQHCxryp5RAmgtArTBrJZq8el1lcG
-+518Vo4QuOqsqTdAhqiImoPKe4NNCs1iTS9BdCqNYiF8sbmeJAoIBAQDUuL5ebQ68
-+6vqTKYD47ZtCzeqziN3Y/0a1BsyZh0/snNmK5WIr4T0vX0Y/XG0EpkZdpW3odMBv
-+CemKs6Zm+pfOUGu20PTJcdSOXRbFiVYSeQnfa0l3iXZvY9Ottz/IU/mWPuU3hc18
-+hOZD9tKiwYDzZREg6L4XRizfT70UkD2eTz4lGBjR092TTj8WqSaI9GF6d9B6Aw9Y
-+OCZdTqV7hPe0Rnvd1XiGsk68HN2Np47HHwwPsKMCYj8YNKmsUF8QSXmCkijlDeJW
-+bC6TjAHlvnN6n1LjaLwULUs9Rb2fkNUOqsgR+T8YlqbclJbzC7gW53M/68c9eOQ1
-+Y01JnzsB3S2vAoIBAQDT8DP2djtzIg6GiNPRvfj9cWifMQWqqV8nNTU9Cnxn4MzO
-+sVcuX+VQBXgblj13D5SC1Ed5ELDplMJYM5iBabPbYX2GtGq6qG83XHOSD0SEdXWw
-+mN/SLUPPUwcGC+8yaPh8LO6jFY3cKmft9+T31Hnf35LPdfWyTZc0YexNlUkt5Kdg
-+XvGkKn5j9RAZcwXrEXMDnhZLEZZ2qBj0C2El71hyBS0ysBnRyWNwR1dcSgx1sJ8H
-+ZCH6NYvLtoqxU4Zm6684eHf9lA7uTL1JHC0kWzUwLqGtbTWp1h5FpL790NVTUkS/
-+Lf7bnnTpZqt8vAtTVc0IxBPOvFLKlzALd+cg69XxAoIBAQCv6Sbkh2NMrzUQRZ42
-+PKfMkuSoG2L6dABQ65J+0/swPHVZ+1830kf6yNsawqAU3DwMbSV6ujH4oUXUQcQ2
-+HL01DCRHRn1nqQ6RvEF8kZnwJNAZRmu2wqKCcxc17Ph9/ZPEv7ZmN+w6MN0LDy4Z
-+EdRFcyq7AD1SmeG5ugMu4ilSpU1K96ZuvrnZezeI0dDgKNgDotlwTN9/oM95EfSf
-+NNJy7ma4iDPnj8S0o1pELnBQEkizIOtsqTpsFgDKUpyKp3golh3jbZvixAuwUHOx
-+PdHZca/mB1KhjONPhEDPl8HZIznYQzn+Z3cNqoM58lMF/di834ogN7zguYHMhDUT
-+0YhZAoIBAHlYhuni+gyrn4tyZgep68VXW7wQxSvgSj8cpZAuT/w0UKAU53J5QTWZ
-+aGHeICXvgvpalUL+2dGwASlOvPa52ekcOPd2+qKWyss0zA4ksI7mNE2vjFUcOr+S
-+n9QSNvu3E8dYAjzSIsizcQbPTlk6A/TmytNJ4x67ZVGCmKXw1ZzzSrxSbAIdY254
-+TxSGchrfcy0ofXIL2HXq16FRmesORTJFkkyQaldzn4y7S6HJ/vGppImTfeac1MwG
-+jLYljIkIbt+nB1c8HeNvARmBa6M2pxB9f72oRMVqFdUUc5AxXuWP9v6xk227EuCq
-+TBORAafu9WxKVwUsHa1rE1uGgNEfRJ8=
-+-----END PRIVATE KEY-----
-diff --git a/test/parallel/test-tls-0-dns-altname.js b/test/parallel/test-tls-0-dns-altname.js
-index 4bc87e44cb..e5cb8e3d48 100644
---- a/test/parallel/test-tls-0-dns-altname.js
-+++ b/test/parallel/test-tls-0-dns-altname.js
-@@ -44,7 +44,7 @@ const server = tls.createServer({
- }, common.mustCall(() => {
- const cert = c.getPeerCertificate();
- assert.strictEqual(cert.subjectaltname,
-- 'DNS:good.example.org\0.evil.example.com, ' +
-+ 'DNS:"good.example.org\\u0000.evil.example.com", ' +
- 'DNS:just-another.example.com, ' +
- 'IP Address:8.8.8.8, ' +
- 'IP Address:8.8.4.4, ' +
-diff --git a/test/parallel/test-x509-escaping.js b/test/parallel/test-x509-escaping.js
-new file mode 100644
-index 0000000000..4e0f82767d
---- /dev/null
-+++ b/test/parallel/test-x509-escaping.js
-@@ -0,0 +1,349 @@
-+'use strict';
-+
-+const common = require('../common');
-+if (!common.hasCrypto)
-+ common.skip('missing crypto');
-+
-+const assert = require('assert');
-+const tls = require('tls');
-+const fixtures = require('../common/fixtures');
-+
-+const { hasOpenSSL3 } = common;
-+
-+// Test that all certificate chains provided by the reporter are rejected.
-+{
-+ const rootPEM = fixtures.readSync('x509-escaping/google/root.pem');
-+ const intermPEM = fixtures.readSync('x509-escaping/google/intermediate.pem');
-+ const keyPEM = fixtures.readSync('x509-escaping/google/key.pem');
-+
-+ const numLeaves = 5;
-+
-+ for (let i = 0; i < numLeaves; i++) {
-+ // TODO(tniessen): this test case requires proper handling of URI SANs,
-+ // which node currently does not implement.
-+ if (i === 3) continue;
-+
-+ const name = `x509-escaping/google/leaf${i}.pem`;
-+ const leafPEM = fixtures.readSync(name, 'utf8');
-+
-+ const server = tls.createServer({
-+ key: keyPEM,
-+ cert: leafPEM + intermPEM,
-+ }, common.mustNotCall()).listen(common.mustCall(() => {
-+ const { port } = server.address();
-+ const socket = tls.connect(port, {
-+ ca: rootPEM,
-+ servername: 'nodejs.org',
-+ }, common.mustNotCall());
-+ socket.on('error', common.mustCall());
-+ })).unref();
-+ }
-+}
-+
-+// Test escaping rules for subject alternative names.
-+{
-+ const expectedSANs = [
-+ 'DNS:"good.example.com\\u002c DNS:evil.example.com"',
-+ // URIs should not require escaping.
-+ 'URI:http://example.com/',
-+ 'URI:http://example.com/?a=b&c=d',
-+ // Unless they contain commas.
-+ 'URI:"http://example.com/a\\u002cb"',
-+ // Percent encoding should not require escaping.
-+ 'URI:http://example.com/a%2Cb',
-+ // Malicious attempts should be escaped.
-+ 'URI:"http://example.com/a\\u002c DNS:good.example.com"',
-+ // Non-ASCII characters in DNS names should be treated as Latin-1.
-+ 'DNS:"ex\\u00e4mple.com"',
-+ // It should not be possible to cause unescaping without escaping.
-+ 'DNS:"\\"evil.example.com\\""',
-+ // IPv4 addresses should be represented as usual.
-+ 'IP Address:8.8.8.8',
-+ 'IP Address:8.8.4.4',
-+ // For backward-compatibility, include invalid IP address lengths.
-+ hasOpenSSL3 ? 'IP Address:<invalid length=5>' : 'IP Address:<invalid>',
-+ hasOpenSSL3 ? 'IP Address:<invalid length=6>' : 'IP Address:<invalid>',
-+ // IPv6 addresses are represented as OpenSSL does.
-+ 'IP Address:A0B:C0D:E0F:0:0:0:7A7B:7C7D',
-+ // Regular email addresses don't require escaping.
-+ 'email:foo@example.com',
-+ // ... but should be escaped if they contain commas.
-+ 'email:"foo@example.com\\u002c DNS:good.example.com"',
-+ 'DirName:/C=DE/L=Hannover',
-+ // TODO(tniessen): support UTF8 in DirName
-+ 'DirName:"/C=DE/L=M\\\\xC3\\\\xBCnchen"',
-+ 'DirName:"/C=DE/L=Berlin\\u002c DNS:good.example.com"',
-+ 'DirName:"/C=DE/L=Berlin\\u002c DNS:good.example.com\\\\x00' +
-+ 'evil.example.com"',
-+ 'DirName:"/C=DE/L=Berlin\\u002c DNS:good.example.com\\\\\\\\x00' +
-+ 'evil.example.com"',
-+ // These next two tests might be surprising. OpenSSL applies its own rules
-+ // first, which introduce backslashes, which activate node's escaping.
-+ // Unfortunately, there are also differences between OpenSSL 1.1.1 and 3.0.
-+ 'DirName:"/C=DE/L=Berlin\\\\x0D\\\\x0A"',
-+ hasOpenSSL3 ?
-+ 'DirName:"/C=DE/L=Berlin\\\\/CN=good.example.com"' :
-+ 'DirName:/C=DE/L=Berlin/CN=good.example.com',
-+ // TODO(tniessen): even OIDs that are well-known (such as the following,
-+ // which is sha256WithRSAEncryption) should be represented numerically only.
-+ 'Registered ID:sha256WithRSAEncryption',
-+ // This is an OID that will likely never be assigned to anything, thus
-+ // OpenSSL should not know it.
-+ 'Registered ID:1.3.9999.12.34',
-+ hasOpenSSL3 ?
-+ 'othername: XmppAddr::abc123' :
-+ 'othername:<unsupported>',
-+ hasOpenSSL3 ?
-+ 'othername:" XmppAddr::abc123\\u002c DNS:good.example.com"' :
-+ 'othername:<unsupported>',
-+ hasOpenSSL3 ?
-+ 'othername:" XmppAddr::good.example.com\\u0000abc123"' :
-+ 'othername:<unsupported>',
-+ // This is unsupported because the OID is not recognized.
-+ 'othername:<unsupported>',
-+ hasOpenSSL3 ? 'othername: SRVName::abc123' : 'othername:<unsupported>',
-+ // This is unsupported because it is an SRVName with a UTF8String value,
-+ // which is not allowed for SRVName.
-+ 'othername:<unsupported>',
-+ hasOpenSSL3 ?
-+ 'othername:" SRVName::abc\\u0000def"' :
-+ 'othername:<unsupported>',
-+ ];
-+
-+ const serverKey = fixtures.readSync('x509-escaping/server-key.pem', 'utf8');
-+
-+ for (let i = 0; i < expectedSANs.length; i++) {
-+ const pem = fixtures.readSync(`x509-escaping/alt-${i}-cert.pem`, 'utf8');
-+
-+ // X509Certificate interface is not supported in v12.x & v14.x. Disable
-+ // checks for subjectAltName with expectedSANs. The testcase is ported
-+ // from v17.x
-+ //
-+ // Test the subjectAltName property of the X509Certificate API.
-+ // const cert = new X509Certificate(pem);
-+ // assert.strictEqual(cert.subjectAltName, expectedSANs[i]);
-+
-+ // Test that the certificate obtained by checkServerIdentity has the correct
-+ // subjectaltname property.
-+ const server = tls.createServer({
-+ key: serverKey,
-+ cert: pem,
-+ }, common.mustCall((conn) => {
-+ conn.destroy();
-+ server.close();
-+ })).listen(common.mustCall(() => {
-+ const { port } = server.address();
-+ tls.connect(port, {
-+ ca: pem,
-+ servername: 'example.com',
-+ checkServerIdentity: (hostname, peerCert) => {
-+ assert.strictEqual(hostname, 'example.com');
-+ assert.strictEqual(peerCert.subjectaltname, expectedSANs[i]);
-+ },
-+ }, common.mustCall());
-+ }));
-+ }
-+}
-+
-+// Test escaping rules for authority info access.
-+{
-+ const expectedInfoAccess = [
-+ {
-+ text: 'OCSP - URI:"http://good.example.com/\\u000a' +
-+ 'OCSP - URI:http://evil.example.com/"',
-+ legacy: {
-+ 'OCSP - URI': [
-+ 'http://good.example.com/\nOCSP - URI:http://evil.example.com/',
-+ ],
-+ },
-+ },
-+ {
-+ text: 'CA Issuers - URI:"http://ca.example.com/\\u000a' +
-+ 'OCSP - URI:http://evil.example.com"\n' +
-+ 'OCSP - DNS:"good.example.com\\u000a' +
-+ 'OCSP - URI:http://ca.nodejs.org/ca.cert"',
-+ legacy: {
-+ 'CA Issuers - URI': [
-+ 'http://ca.example.com/\nOCSP - URI:http://evil.example.com',
-+ ],
-+ 'OCSP - DNS': [
-+ 'good.example.com\nOCSP - URI:http://ca.nodejs.org/ca.cert',
-+ ],
-+ },
-+ },
-+ {
-+ text: '1.3.9999.12.34 - URI:http://ca.example.com/',
-+ legacy: {
-+ '1.3.9999.12.34 - URI': [
-+ 'http://ca.example.com/',
-+ ],
-+ },
-+ },
-+ hasOpenSSL3 ? {
-+ text: 'OCSP - othername: XmppAddr::good.example.com\n' +
-+ 'OCSP - othername:<unsupported>\n' +
-+ 'OCSP - othername: SRVName::abc123',
-+ legacy: {
-+ 'OCSP - othername': [
-+ ' XmppAddr::good.example.com',
-+ '<unsupported>',
-+ ' SRVName::abc123',
-+ ],
-+ },
-+ } : {
-+ text: 'OCSP - othername:<unsupported>\n' +
-+ 'OCSP - othername:<unsupported>\n' +
-+ 'OCSP - othername:<unsupported>',
-+ legacy: {
-+ 'OCSP - othername': [
-+ '<unsupported>',
-+ '<unsupported>',
-+ '<unsupported>',
-+ ],
-+ },
-+ },
-+ hasOpenSSL3 ? {
-+ text: 'OCSP - othername:" XmppAddr::good.example.com\\u0000abc123"',
-+ legacy: {
-+ 'OCSP - othername': [
-+ ' XmppAddr::good.example.com\0abc123',
-+ ],
-+ },
-+ } : {
-+ text: 'OCSP - othername:<unsupported>',
-+ legacy: {
-+ 'OCSP - othername': [
-+ '<unsupported>',
-+ ],
-+ },
-+ },
-+ ];
-+
-+ const serverKey = fixtures.readSync('x509-escaping/server-key.pem', 'utf8');
-+
-+ for (let i = 0; i < expectedInfoAccess.length; i++) {
-+ const pem = fixtures.readSync(`x509-escaping/info-${i}-cert.pem`, 'utf8');
-+ const expected = expectedInfoAccess[i];
-+
-+ // X509Certificate interface is not supported in v12.x & v14.x. Disable
-+ // checks for cert.infoAccess with expected text. The testcase is ported
-+ // from v17.x
-+ // Test the subjectAltName property of the X509Certificate API.
-+ // const cert = new X509Certificate(pem);
-+ // assert.strictEqual(cert.infoAccess,
-+ // `${expected.text}${hasOpenSSL3 ? '' : '\n'}`);
-+
-+ // Test that the certificate obtained by checkServerIdentity has the correct
-+ // subjectaltname property.
-+ const server = tls.createServer({
-+ key: serverKey,
-+ cert: pem,
-+ }, common.mustCall((conn) => {
-+ conn.destroy();
-+ server.close();
-+ })).listen(common.mustCall(() => {
-+ const { port } = server.address();
-+ tls.connect(port, {
-+ ca: pem,
-+ servername: 'example.com',
-+ checkServerIdentity: (hostname, peerCert) => {
-+ assert.strictEqual(hostname, 'example.com');
-+ assert.deepStrictEqual(peerCert.infoAccess,
-+ Object.assign(Object.create(null),
-+ expected.legacy));
-+ },
-+ }, common.mustCall());
-+ }));
-+ }
-+}
-+
-+// The internal parsing logic must match the JSON specification exactly.
-+{
-+ // This list is partially based on V8's own JSON tests.
-+ const invalidJSON = [
-+ '"\\a invalid escape"',
-+ '"\\v invalid escape"',
-+ '"\\\' invalid escape"',
-+ '"\\x42 invalid escape"',
-+ '"\\u202 invalid escape"',
-+ '"\\012 invalid escape"',
-+ '"Unterminated string',
-+ '"Unterminated string\\"',
-+ '"Unterminated string\\\\\\"',
-+ '"\u0000 control character"',
-+ '"\u001e control character"',
-+ '"\u001f control character"',
-+ ];
-+
-+ for (const invalidStringLiteral of invalidJSON) {
-+ // Usually, checkServerIdentity returns an error upon verification failure.
-+ // In this case, however, it should throw an error since this is not a
-+ // verification error. Node.js itself will never produce invalid JSON string
-+ // literals, so this can only happen when users construct invalid subject
-+ // alternative name strings (that do not follow escaping rules).
-+ assert.throws(() => {
-+ tls.checkServerIdentity('example.com', {
-+ subjectaltname: `DNS:${invalidStringLiteral}`,
-+ });
-+ }, {
-+ code: 'ERR_TLS_CERT_ALTNAME_FORMAT',
-+ message: 'Invalid subject alternative name string'
-+ });
-+ }
-+}
-+
-+// While node does not produce commas within SAN entries, it should parse them
-+// correctly (i.e., not simply split at commas).
-+{
-+ // Regardless of the quotes, splitting this SAN string at commas would
-+ // cause checkServerIdentity to see 'DNS:b.example.com' and thus to accept
-+ // the certificate for b.example.com.
-+ const san = 'DNS:"a.example.com, DNS:b.example.com, DNS:c.example.com"';
-+
-+ // This is what node used to do, and which is not correct!
-+ const hostname = 'b.example.com';
-+ assert.strictEqual(san.split(', ')[1], `DNS:${hostname}`);
-+
-+ // The new implementation should parse the string correctly.
-+ const err = tls.checkServerIdentity(hostname, { subjectaltname: san });
-+ assert(err);
-+ assert.strictEqual(err.code, 'ERR_TLS_CERT_ALTNAME_INVALID');
-+ assert.strictEqual(err.message, 'Hostname/IP does not match certificate\'s ' +
-+ 'altnames: Host: b.example.com. is not in ' +
-+ 'the cert\'s altnames: DNS:"a.example.com, ' +
-+ 'DNS:b.example.com, DNS:c.example.com"');
-+}
-+
-+// The subject MUST be ignored if a dNSName subject alternative name exists.
-+{
-+ const key = fixtures.readKey('incorrect_san_correct_subject-key.pem');
-+ const cert = fixtures.readKey('incorrect_san_correct_subject-cert.pem');
-+
-+ // The hostname is the CN, but not a SAN entry.
-+ const servername = 'good.example.com';
-+
-+ // X509Certificate interface is not supported in v12.x & v14.x. Disable
-+ // checks for certX509.subject and certX509.subjectAltName with expected
-+ // value. The testcase is ported from v17.x
-+ //
-+ // const certX509 = new X509Certificate(cert);
-+ // assert.strictEqual(certX509.subject, `CN=${servername}`);
-+ // assert.strictEqual(certX509.subjectAltName, 'DNS:evil.example.com');
-+
-+ // Try connecting to a server that uses the self-signed certificate.
-+ const server = tls.createServer({ key, cert }, common.mustNotCall());
-+ server.listen(common.mustCall(() => {
-+ const { port } = server.address();
-+ const socket = tls.connect(port, {
-+ ca: cert,
-+ servername,
-+ }, common.mustNotCall());
-+ socket.on('error', common.mustCall((err) => {
-+ assert.strictEqual(err.code, 'ERR_TLS_CERT_ALTNAME_INVALID');
-+ assert.strictEqual(err.message, 'Hostname/IP does not match ' +
-+ "certificate's altnames: Host: " +
-+ "good.example.com. is not in the cert's" +
-+ ' altnames: DNS:evil.example.com');
-+ }));
-+ })).unref();
-+}
---
-2.17.1
-
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs_12.22.2.bb b/meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb
index 2c7d3b3edd..8dbdd088e9 100644
--- a/meta-oe/recipes-devtools/nodejs/nodejs_12.22.2.bb
+++ b/meta-oe/recipes-devtools/nodejs/nodejs_12.22.12.bb
@@ -1,7 +1,7 @@
DESCRIPTION = "nodeJS Evented I/O for V8 JavaScript"
HOMEPAGE = "http://nodejs.org"
LICENSE = "MIT & BSD & Artistic-2.0"
-LIC_FILES_CHKSUM = "file://LICENSE;md5=8c66ff8861d9f96076a7cb61e3d75f54"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=93997aa7a45ba0f25f9c61aaab153ab8"
DEPENDS = "openssl"
DEPENDS_append_class-target = " nodejs-native"
@@ -22,12 +22,11 @@ SRC_URI = "http://nodejs.org/dist/v${PV}/node-v${PV}.tar.xz \
file://big-endian.patch \
file://mips-warnings.patch \
file://0001-Remove-use-of-register-r7-because-llvm-now-issues-an.patch \
- file://CVE-2021-44532.patch \
"
SRC_URI_append_class-target = " \
file://0002-Using-native-binaries.patch \
"
-SRC_URI[sha256sum] = "7fd805571df106f086f4c45e131efed98bfd62628d9dec96bd62f8c11b0c48dc"
+SRC_URI[sha256sum] = "bc42b7f8495b9bfc7f7850dd180bb02a5bdf139cc232b8c6f02a6967e20714f2"
S = "${WORKDIR}/node-v${PV}"
diff --git a/meta-oe/recipes-support/c-ares/c-ares/0001-fix-configure-error-mv-libcares.pc.cmakein-to-libcar.patch b/meta-oe/recipes-support/c-ares/c-ares/0001-fix-configure-error-mv-libcares.pc.cmakein-to-libcar.patch
deleted file mode 100644
index 8f15f8424c..0000000000
--- a/meta-oe/recipes-support/c-ares/c-ares/0001-fix-configure-error-mv-libcares.pc.cmakein-to-libcar.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From f2f1e134bf5d9d0789942848e03006af8d926cf8 Mon Sep 17 00:00:00 2001
-From: Wang Mingyu <wangmy@cn.fujitsu.com>
-Date: Tue, 17 Mar 2020 12:53:35 +0800
-Subject: [PATCH] fix configure error : mv libcares.pc.cmakein to
- libcares.pc.cmake
-
-Signed-off-by: Wang Mingyu <wangmy@cn.fujitsu.com>
----
- CMakeLists.txt | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 3a5878d..c2e5740 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -563,7 +563,7 @@ IF (CARES_STATIC)
- ENDIF()
-
- # Write ares_config.h configuration file. This is used only for the build.
--CONFIGURE_FILE (libcares.pc.cmakein ${PROJECT_BINARY_DIR}/libcares.pc @ONLY)
-+CONFIGURE_FILE (libcares.pc.cmake ${PROJECT_BINARY_DIR}/libcares.pc @ONLY)
-
-
-
---
-2.17.1
-
diff --git a/meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-fix-formatting-and-handling-of-root.patch b/meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-fix-formatting-and-handling-of-root.patch
deleted file mode 100644
index d1cb54aefb..0000000000
--- a/meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-fix-formatting-and-handling-of-root.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-From: bradh352 <brad@brad-house.com>
-Date: Fri, 11 Jun 2021 12:39:24 -0400
-Subject: [2/2] ares_expand_name(): fix formatting and handling of root name
- response
-Origin: https://github.com/c-ares/c-ares/commit/44c009b8e62ea1929de68e3f438181bea469ec14
-Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-3672
-
-Fixes issue introduced in prior commit with formatting and handling
-of parsing a root name response which should not be escaped.
-
-Fix By: Brad House
-CVE: CVE-2021-3672
-Upstream-Status: Backport [http://snapshot.debian.org/archive/debian-security/20210810T064453Z/pool/updates/main/c/c-ares/c-ares_1.17.1-1%2Bdeb11u1.debian.tar.xz]
-Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com>
----
- ares_expand_name.c | 62 ++++++++++++++++++++++++--------------
- 1 file changed, 40 insertions(+), 22 deletions(-)
-
-diff --git a/ares_expand_name.c b/ares_expand_name.c
-index f1c874a97cfc..eb9268c1ff0a 100644
---- a/ares_expand_name.c
-+++ b/ares_expand_name.c
-@@ -127,27 +127,37 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
- }
- else
- {
-- len = *p;
-+ int name_len = *p;
-+ len = name_len;
- p++;
-+
- while (len--)
- {
-- if (!isprint(*p)) {
-- /* Output as \DDD for consistency with RFC1035 5.1 */
-- *q++ = '\\';
-- *q++ = '0' + *p / 100;
-- *q++ = '0' + (*p % 100) / 10;
-- *q++ = '0' + (*p % 10);
-- } else if (is_reservedch(*p)) {
-- *q++ = '\\';
-- *q++ = *p;
-- } else {
-- *q++ = *p;
-- }
-+ /* Output as \DDD for consistency with RFC1035 5.1, except
-+ * for the special case of a root name response */
-+ if (!isprint(*p) && !(name_len == 1 && *p == 0))
-+ {
-+
-+ *q++ = '\\';
-+ *q++ = '0' + *p / 100;
-+ *q++ = '0' + (*p % 100) / 10;
-+ *q++ = '0' + (*p % 10);
-+ }
-+ else if (is_reservedch(*p))
-+ {
-+ *q++ = '\\';
-+ *q++ = *p;
-+ }
-+ else
-+ {
-+ *q++ = *p;
-+ }
- p++;
- }
- *q++ = '.';
- }
-- }
-+ }
-+
- if (!indir)
- *enclen = aresx_uztosl(p + 1U - encoded);
-
-@@ -194,21 +204,29 @@ static int name_length(const unsigned char *encoded, const unsigned char *abuf,
- }
- else if (top == 0x00)
- {
-- offset = *encoded;
-+ int name_len = *encoded;
-+ offset = name_len;
- if (encoded + offset + 1 >= abuf + alen)
- return -1;
- encoded++;
-+
- while (offset--)
- {
-- if (!isprint(*encoded)) {
-- n += 4;
-- } else if (is_reservedch(*encoded)) {
-- n += 2;
-- } else {
-- n += 1;
-- }
-+ if (!isprint(*encoded) && !(name_len == 1 && *encoded == 0))
-+ {
-+ n += 4;
-+ }
-+ else if (is_reservedch(*encoded))
-+ {
-+ n += 2;
-+ }
-+ else
-+ {
-+ n += 1;
-+ }
- encoded++;
- }
-+
- n++;
- }
- else
---
-2.32.0
-
diff --git a/meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-should-escape-more-characters.patch b/meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-should-escape-more-characters.patch
deleted file mode 100644
index 3603ef1278..0000000000
--- a/meta-oe/recipes-support/c-ares/c-ares/ares_expand_name-should-escape-more-characters.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From: bradh352 <brad@brad-house.com>
-Date: Fri, 11 Jun 2021 11:27:45 -0400
-Subject: [1/2] ares_expand_name() should escape more characters
-Origin: https://github.com/c-ares/c-ares/commit/362f91d807d293791008cdb7616d40f7784ece83
-Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-3672
-
-RFC1035 5.1 specifies some reserved characters and escaping sequences
-that are allowed to be specified. Expand the list of reserved characters
-and also escape non-printable characters using the \DDD format as
-specified in the RFC.
-
-Bug Reported By: philipp.jeitner@sit.fraunhofer.de
-Fix By: Brad House (@bradh352)
-CVE: CVE-2021-3672
-Upstream-Status: Backport [http://snapshot.debian.org/archive/debian-security/20210810T064453Z/pool/updates/main/c/c-ares/c-ares_1.17.1-1%2Bdeb11u1.debian.tar.xz]
-Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com>
----
- ares_expand_name.c | 41 +++++++++++++++++++++++++++++++++++---
- 1 file changed, 38 insertions(+), 3 deletions(-)
-
-diff --git a/ares_expand_name.c b/ares_expand_name.c
-index 407200ef5b4b..f1c874a97cfc 100644
---- a/ares_expand_name.c
-+++ b/ares_expand_name.c
-@@ -32,6 +32,26 @@
- static int name_length(const unsigned char *encoded, const unsigned char *abuf,
- int alen);
-
-+/* Reserved characters for names that need to be escaped */
-+static int is_reservedch(int ch)
-+{
-+ switch (ch) {
-+ case '"':
-+ case '.':
-+ case ';':
-+ case '\\':
-+ case '(':
-+ case ')':
-+ case '@':
-+ case '$':
-+ return 1;
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
- /* Expand an RFC1035-encoded domain name given by encoded. The
- * containing message is given by abuf and alen. The result given by
- * *s, which is set to a NUL-terminated allocated buffer. *enclen is
-@@ -111,9 +131,18 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
- p++;
- while (len--)
- {
-- if (*p == '.' || *p == '\\')
-+ if (!isprint(*p)) {
-+ /* Output as \DDD for consistency with RFC1035 5.1 */
-+ *q++ = '\\';
-+ *q++ = '0' + *p / 100;
-+ *q++ = '0' + (*p % 100) / 10;
-+ *q++ = '0' + (*p % 10);
-+ } else if (is_reservedch(*p)) {
- *q++ = '\\';
-- *q++ = *p;
-+ *q++ = *p;
-+ } else {
-+ *q++ = *p;
-+ }
- p++;
- }
- *q++ = '.';
-@@ -171,7 +200,13 @@ static int name_length(const unsigned char *encoded, const unsigned char *abuf,
- encoded++;
- while (offset--)
- {
-- n += (*encoded == '.' || *encoded == '\\') ? 2 : 1;
-+ if (!isprint(*encoded)) {
-+ n += 4;
-+ } else if (is_reservedch(*encoded)) {
-+ n += 2;
-+ } else {
-+ n += 1;
-+ }
- encoded++;
- }
- n++;
---
-2.32.0
-
diff --git a/meta-oe/recipes-support/c-ares/c-ares/cmake-install-libcares.pc.patch b/meta-oe/recipes-support/c-ares/c-ares/cmake-install-libcares.pc.patch
deleted file mode 100644
index 0eb7e4bbb3..0000000000
--- a/meta-oe/recipes-support/c-ares/c-ares/cmake-install-libcares.pc.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From 12414304245cce6ef0e8b9547949be5109845353 Mon Sep 17 00:00:00 2001
-From: Changqing Li <changqing.li@windriver.com>
-Date: Tue, 24 Jul 2018 13:33:33 +0800
-Subject: [PATCH] cmake: Install libcares.pc
-
-Prepare and install libcares.pc file during cmake build, so libraries
-using pkg-config to find libcares will not fail.
-
-Signed-off-by: Alexey Firago <alexey_firago@mentor.com>
-
-update to 1.14.0, fix patch warning
-
-Signed-off-by: Changqing Li <changqing.li@windriver.com>
----
- CMakeLists.txt | 28 +++++++++++++++++++++++-----
- 1 file changed, 23 insertions(+), 5 deletions(-)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index fd123e1..3a5878d 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -214,22 +214,25 @@ ADD_DEFINITIONS(${SYSFLAGS})
-
-
- # Tell C-Ares about libraries to depend on
-+# Also pass these libraries to pkg-config file
-+SET(CARES_PRIVATE_LIBS_LIST)
- IF (HAVE_LIBRESOLV)
-- LIST (APPEND CARES_DEPENDENT_LIBS resolv)
-+ LIST (APPEND CARES_PRIVATE_LIBS_LIST "-lresolv")
- ENDIF ()
- IF (HAVE_LIBNSL)
-- LIST (APPEND CARES_DEPENDENT_LIBS nsl)
-+ LIST (APPEND CARES_PRIVATE_LIBS_LIST "-lnsl")
- ENDIF ()
- IF (HAVE_LIBSOCKET)
-- LIST (APPEND CARES_DEPENDENT_LIBS socket)
-+ LIST (APPEND CARES_PRIVATE_LIBS_LIST "-lsocket")
- ENDIF ()
- IF (HAVE_LIBRT)
-- LIST (APPEND CARES_DEPENDENT_LIBS rt)
-+ LIST (APPEND CARES_PRIVATE_LIBS_LIST "-lrt")
- ENDIF ()
- IF (WIN32)
-- LIST (APPEND CARES_DEPENDENT_LIBS ws2_32 Advapi32)
-+ LIST (APPEND CARES_PRIVATE_LIBS_LIST "-lws2_32")
- ENDIF ()
-
-+string (REPLACE ";" " " CARES_PRIVATE_LIBS "${CARES_PRIVATE_LIBS_LIST}")
-
- # When checking for symbols, we need to make sure we set the proper
- # headers, libraries, and definitions for the detection to work properly
-@@ -554,6 +557,15 @@ CONFIGURE_FILE (ares_build.h.cmake ${PROJECT_BINARY_DIR}/ares_build.h)
- # Write ares_config.h configuration file. This is used only for the build.
- CONFIGURE_FILE (ares_config.h.cmake ${PROJECT_BINARY_DIR}/ares_config.h)
-
-+# Pass required CFLAGS to pkg-config in case of static library
-+IF (CARES_STATIC)
-+ SET (CPPFLAG_CARES_STATICLIB "-DCARES_STATICLIB")
-+ENDIF()
-+
-+# Write ares_config.h configuration file. This is used only for the build.
-+CONFIGURE_FILE (libcares.pc.cmakein ${PROJECT_BINARY_DIR}/libcares.pc @ONLY)
-+
-+
-
- # TRANSFORM_MAKEFILE_INC
- #
-@@ -728,6 +740,12 @@ IF (CARES_INSTALL)
- INSTALL (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcares.pc" COMPONENT Devel DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
- ENDIF ()
-
-+# pkg-config file
-+IF (CARES_INSTALL)
-+ SET (PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
-+ INSTALL (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcares.pc" DESTINATION ${PKGCONFIG_INSTALL_DIR})
-+ENDIF ()
-+
- # Legacy chain-building variables (provided for compatibility with old code).
- # Don't use these, external code should be updated to refer to the aliases directly (e.g., Cares::cares).
- SET (CARES_FOUND 1 CACHE INTERNAL "CARES LIBRARY FOUND")
---
-2.17.1
-
diff --git a/meta-oe/recipes-support/c-ares/c-ares_1.16.1.bb b/meta-oe/recipes-support/c-ares/c-ares_1.18.1.bb
index 692a5f0d6e..25ce45d74c 100644
--- a/meta-oe/recipes-support/c-ares/c-ares_1.16.1.bb
+++ b/meta-oe/recipes-support/c-ares/c-ares_1.18.1.bb
@@ -5,16 +5,8 @@ SECTION = "libs"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE.md;md5=fb997454c8d62aa6a47f07a8cd48b006"
-PV = "1.16.1+gitr${SRCPV}"
-
-SRC_URI = "\
- git://github.com/c-ares/c-ares.git;branch=main;protocol=https \
- file://cmake-install-libcares.pc.patch \
- file://0001-fix-configure-error-mv-libcares.pc.cmakein-to-libcar.patch \
- file://ares_expand_name-should-escape-more-characters.patch \
- file://ares_expand_name-fix-formatting-and-handling-of-root.patch \
-"
-SRCREV = "74a1426ba60e2cd7977e53a22ef839c87415066e"
+SRC_URI = "git://github.com/c-ares/c-ares.git;branch=main"
+SRCREV = "2aa086f822aad5017a6f2061ef656f237a62d0ed"
UPSTREAM_CHECK_GITTAGREGEX = "cares-(?P<pver>\d+_(\d_?)+)"
diff --git a/meta-python/recipes-devtools/python/python-lxml.inc b/meta-python/recipes-devtools/python/python-lxml.inc
index 05b5eae462..0276a3e81a 100644
--- a/meta-python/recipes-devtools/python/python-lxml.inc
+++ b/meta-python/recipes-devtools/python/python-lxml.inc
@@ -18,6 +18,8 @@ LIC_FILES_CHKSUM = "file://LICENSES.txt;md5=e4c045ebad958ead4b48008f70838403 \
DEPENDS += "libxml2 libxslt"
+SRC_URI += "file://CVE-2022-2309.patch"
+
SRC_URI[md5sum] = "f088e452ed45b030b6f84269f1e84d11"
SRC_URI[sha256sum] = "8620ce80f50d023d414183bf90cc2576c2837b88e00bea3f33ad2630133bbb60"
diff --git a/meta-python/recipes-devtools/python/python3-lxml/CVE-2022-2309.patch b/meta-python/recipes-devtools/python/python3-lxml/CVE-2022-2309.patch
new file mode 100644
index 0000000000..ff3fcee6e2
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-lxml/CVE-2022-2309.patch
@@ -0,0 +1,94 @@
+From ccbda4b0669f418b2f00c4f099733cebe633eb47 Mon Sep 17 00:00:00 2001
+From: Hitendra Prajapati <hprajapati@mvista.com>
+Date: Fri, 29 Jul 2022 10:16:59 +0530
+Subject: [PATCH] CVE-2022-2309
+
+Upstream-Status: Backport [https://github.com/lxml/lxml/commit/86368e9cf70a0ad23cccd5ee32de847149af0c6f]
+CVE: CVE-2022-2309
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ src/lxml/apihelpers.pxi | 7 ++++---
+ src/lxml/iterparse.pxi | 11 ++++++-----
+ src/lxml/tests/test_etree.py | 20 ++++++++++++++++++++
+ 3 files changed, 30 insertions(+), 8 deletions(-)
+
+diff --git a/src/lxml/apihelpers.pxi b/src/lxml/apihelpers.pxi
+index 5eb3416..88a031d 100644
+--- a/src/lxml/apihelpers.pxi
++++ b/src/lxml/apihelpers.pxi
+@@ -246,9 +246,10 @@ cdef dict _build_nsmap(xmlNode* c_node):
+ while c_node is not NULL and c_node.type == tree.XML_ELEMENT_NODE:
+ c_ns = c_node.nsDef
+ while c_ns is not NULL:
+- prefix = funicodeOrNone(c_ns.prefix)
+- if prefix not in nsmap:
+- nsmap[prefix] = funicodeOrNone(c_ns.href)
++ if c_ns.prefix or c_ns.href:
++ prefix = funicodeOrNone(c_ns.prefix)
++ if prefix not in nsmap:
++ nsmap[prefix] = funicodeOrNone(c_ns.href)
+ c_ns = c_ns.next
+ c_node = c_node.parent
+ return nsmap
+diff --git a/src/lxml/iterparse.pxi b/src/lxml/iterparse.pxi
+index 4c20506..3da7485 100644
+--- a/src/lxml/iterparse.pxi
++++ b/src/lxml/iterparse.pxi
+@@ -419,7 +419,7 @@ cdef int _countNsDefs(xmlNode* c_node):
+ count = 0
+ c_ns = c_node.nsDef
+ while c_ns is not NULL:
+- count += 1
++ count += (c_ns.href is not NULL)
+ c_ns = c_ns.next
+ return count
+
+@@ -430,9 +430,10 @@ cdef int _appendStartNsEvents(xmlNode* c_node, list event_list) except -1:
+ count = 0
+ c_ns = c_node.nsDef
+ while c_ns is not NULL:
+- ns_tuple = (funicode(c_ns.prefix) if c_ns.prefix is not NULL else '',
+- funicode(c_ns.href))
+- event_list.append( (u"start-ns", ns_tuple) )
+- count += 1
++ if c_ns.href:
++ ns_tuple = (funicodeOrEmpty(c_ns.prefix),
++ funicode(c_ns.href))
++ event_list.append( (u"start-ns", ns_tuple) )
++ count += 1
+ c_ns = c_ns.next
+ return count
+diff --git a/src/lxml/tests/test_etree.py b/src/lxml/tests/test_etree.py
+index b997e4d..69e1bf1 100644
+--- a/src/lxml/tests/test_etree.py
++++ b/src/lxml/tests/test_etree.py
+@@ -1448,6 +1448,26 @@ class ETreeOnlyTestCase(HelperTestCase):
+ [1,2,1,4],
+ counts)
+
++ def test_walk_after_parse_failure(self):
++ # This used to be an issue because libxml2 can leak empty namespaces
++ # between failed parser runs. iterwalk() failed to handle such a tree.
++ try:
++ etree.XML('''<anot xmlns="1">''')
++ except etree.XMLSyntaxError:
++ pass
++ else:
++ assert False, "invalid input did not fail to parse"
++
++ et = etree.XML('''<root> </root>''')
++ try:
++ ns = next(etree.iterwalk(et, events=('start-ns',)))
++ except StopIteration:
++ # This would be the expected result, because there was no namespace
++ pass
++ else:
++ # This is a bug in libxml2
++ assert not ns, repr(ns)
++
+ def test_itertext_comment_pi(self):
+ # https://bugs.launchpad.net/lxml/+bug/1844674
+ XML = self.etree.XML
+--
+2.25.1
+