From 2539b13d19072f0ff8912125a5384cf9f1286871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=B1=E4=B8=8B?= Date: Mon, 9 Jan 2023 15:20:58 +0900 Subject: [PATCH 1/4] Add base cases for checking hostname --- lib/std/crypto/Certificate.zig | 47 +++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index fe211c614671..6fcbe0ce100e 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -272,29 +272,52 @@ pub const Parsed = struct { return error.CertificateHostMismatch; } + // Check hostname according to RFC2818 specification: + // + // If more than one identity of a given type is present in + // the certificate (e.g., more than one dNSName name, a match in any one + // of the set is considered acceptable.) Names may contain the wildcard + // character * which is considered to match any single domain name + // component or component fragment. E.g., *.a.com matches foo.a.com but + // not bar.foo.a.com. f*.com matches foo.com but not bar.com. fn checkHostName(host_name: []const u8, dns_name: []const u8) bool { if (mem.eql(u8, dns_name, host_name)) { return true; // exact match } - if (mem.startsWith(u8, dns_name, "*.")) { - // wildcard certificate, matches any subdomain - // TODO: I think wildcards are not supposed to match any prefix but - // only match exactly one subdomain. - if (mem.endsWith(u8, host_name, dns_name[1..])) { - // The host_name has a subdomain, but the important part matches. - return true; + var it_host = std.mem.split(u8, host_name, "."); + var it_dns = std.mem.split(u8, dns_name, "."); + + const len_match = while (true) { + const host = it_host.next(); + const dns = it_dns.next(); + + if (host == null or dns == null) { + break host == null and dns == null; } - if (mem.eql(u8, dns_name[2..], host_name)) { - // The host_name has no subdomain and matches exactly. - return true; + + // If not a wildcard and they dont + // match then there is no match. + if (mem.eql(u8, dns.?, "*") == false and mem.eql(u8, dns.?, host.?) == false) { + return false; } - } + }; - return false; + // If the components are not the same + // length then there is no match. + return len_match; } }; +test "Parsed checkHostName" { + const expectEqual = std.testing.expectEqual; + + try expectEqual(true, Parsed.checkHostName("ziglang.org", "ziglang.org")); + try expectEqual(true, Parsed.checkHostName("bar.ziglang.org", "*.ziglang.org")); + try expectEqual(false, Parsed.checkHostName("foo.bar.ziglang.org", "*.ziglang.org")); + try expectEqual(false, Parsed.checkHostName("lang.org", "zig*.org")); +} + pub fn parse(cert: Certificate) !Parsed { const cert_bytes = cert.buffer; const certificate = try der.Element.parse(cert_bytes, cert.index); From fec9fd4515f69ccd7c3286b48d8df1b91377224c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=B1=E4=B8=8B?= Date: Mon, 9 Jan 2023 15:33:19 +0900 Subject: [PATCH 2/4] Add fragment case --- lib/std/crypto/Certificate.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index 6fcbe0ce100e..8e96955aae45 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -285,6 +285,14 @@ pub const Parsed = struct { return true; // exact match } + // In the case of the wildcard not being + // in the subdomain. + if (mem.indexOf(u8, dns_name, "*")) |idx| { + if (idx > 0) { + return mem.eql(u8, host_name[0..idx], dns_name[0..idx]); + } + } + var it_host = std.mem.split(u8, host_name, "."); var it_dns = std.mem.split(u8, dns_name, "."); @@ -309,12 +317,13 @@ pub const Parsed = struct { } }; -test "Parsed checkHostName" { +test "Parsed.checkHostName" { const expectEqual = std.testing.expectEqual; try expectEqual(true, Parsed.checkHostName("ziglang.org", "ziglang.org")); try expectEqual(true, Parsed.checkHostName("bar.ziglang.org", "*.ziglang.org")); try expectEqual(false, Parsed.checkHostName("foo.bar.ziglang.org", "*.ziglang.org")); + try expectEqual(true, Parsed.checkHostName("ziglang.org", "zig*.org")); try expectEqual(false, Parsed.checkHostName("lang.org", "zig*.org")); } From c24a7a6f959770bddc7156130580195eee6cacd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=B1=E4=B8=8B?= Date: Mon, 9 Jan 2023 19:38:20 +0900 Subject: [PATCH 3/4] Apply zig fmt fixes --- lib/std/crypto/Certificate.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index 8e96955aae45..7cb91e073bd0 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -304,7 +304,7 @@ pub const Parsed = struct { break host == null and dns == null; } - // If not a wildcard and they dont + // If not a wildcard and they dont // match then there is no match. if (mem.eql(u8, dns.?, "*") == false and mem.eql(u8, dns.?, host.?) == false) { return false; From d938267c660168cafa8b44fad6dbd8b72f0338e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=B1=E4=B8=8B?= Date: Thu, 19 Jan 2023 20:16:50 +0900 Subject: [PATCH 4/4] Remove fragment case --- lib/std/crypto/Certificate.zig | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index 7cb91e073bd0..113910e43c6c 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -275,7 +275,7 @@ pub const Parsed = struct { // Check hostname according to RFC2818 specification: // // If more than one identity of a given type is present in - // the certificate (e.g., more than one dNSName name, a match in any one + // the certificate (e.g., more than one DNSName name, a match in any one // of the set is considered acceptable.) Names may contain the wildcard // character * which is considered to match any single domain name // component or component fragment. E.g., *.a.com matches foo.a.com but @@ -285,14 +285,6 @@ pub const Parsed = struct { return true; // exact match } - // In the case of the wildcard not being - // in the subdomain. - if (mem.indexOf(u8, dns_name, "*")) |idx| { - if (idx > 0) { - return mem.eql(u8, host_name[0..idx], dns_name[0..idx]); - } - } - var it_host = std.mem.split(u8, host_name, "."); var it_dns = std.mem.split(u8, dns_name, "."); @@ -323,7 +315,7 @@ test "Parsed.checkHostName" { try expectEqual(true, Parsed.checkHostName("ziglang.org", "ziglang.org")); try expectEqual(true, Parsed.checkHostName("bar.ziglang.org", "*.ziglang.org")); try expectEqual(false, Parsed.checkHostName("foo.bar.ziglang.org", "*.ziglang.org")); - try expectEqual(true, Parsed.checkHostName("ziglang.org", "zig*.org")); + try expectEqual(false, Parsed.checkHostName("ziglang.org", "zig*.org")); try expectEqual(false, Parsed.checkHostName("lang.org", "zig*.org")); }