Wildcard certs should only validate one level of sub domain

This commit is contained in:
山下 2023-01-20 04:13:42 +09:00 committed by GitHub
parent 989b0e620b
commit 6c98c8d891
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -316,29 +316,53 @@ 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;
}
if (mem.eql(u8, dns_name[2..], host_name)) {
// The host_name has no subdomain and matches exactly.
return true;
}
}
var it_host = std.mem.split(u8, host_name, ".");
var it_dns = std.mem.split(u8, dns_name, ".");
return false;
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 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;
}
};
// 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("ziglang.org", "zig*.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);