| ... | ... | @@ -316,29 +316,53 @@ pub const Parsed = struct { |
| 316 | 316 | return error.CertificateHostMismatch; |
| 317 | 317 | } |
| 318 | 318 | |
| 319 | // Check hostname according to RFC2818 specification: |
| 320 | // |
| 321 | // If more than one identity of a given type is present in |
| 322 | // the certificate (e.g., more than one DNSName name, a match in any one |
| 323 | // of the set is considered acceptable.) Names may contain the wildcard |
| 324 | // character * which is considered to match any single domain name |
| 325 | // component or component fragment. E.g., *.a.com matches foo.a.com but |
| 326 | // not bar.foo.a.com. f*.com matches foo.com but not bar.com. |
| 319 | 327 | fn checkHostName(host_name: []const u8, dns_name: []const u8) bool { |
| 320 | 328 | if (mem.eql(u8, dns_name, host_name)) { |
| 321 | 329 | return true; // exact match |
| 322 | 330 | } |
| 323 | 331 | |
| 324 | | if (mem.startsWith(u8, dns_name, "*.")) { |
| 325 | | // wildcard certificate, matches any subdomain |
| 326 | | // TODO: I think wildcards are not supposed to match any prefix but |
| 327 | | // only match exactly one subdomain. |
| 328 | | if (mem.endsWith(u8, host_name, dns_name[1..])) { |
| 329 | | // The host_name has a subdomain, but the important part matches. |
| 330 | | return true; |
| 332 | var it_host = std.mem.split(u8, host_name, "."); |
| 333 | var it_dns = std.mem.split(u8, dns_name, "."); |
| 334 | |
| 335 | const len_match = while (true) { |
| 336 | const host = it_host.next(); |
| 337 | const dns = it_dns.next(); |
| 338 | |
| 339 | if (host == null or dns == null) { |
| 340 | break host == null and dns == null; |
| 331 | 341 | } |
| 332 | | if (mem.eql(u8, dns_name[2..], host_name)) { |
| 333 | | // The host_name has no subdomain and matches exactly. |
| 334 | | return true; |
| 342 | |
| 343 | // If not a wildcard and they dont |
| 344 | // match then there is no match. |
| 345 | if (mem.eql(u8, dns.?, "*") == false and mem.eql(u8, dns.?, host.?) == false) { |
| 346 | return false; |
| 335 | 347 | } |
| 336 | | } |
| 348 | }; |
| 337 | 349 | |
| 338 | | return false; |
| 350 | // If the components are not the same |
| 351 | // length then there is no match. |
| 352 | return len_match; |
| 339 | 353 | } |
| 340 | 354 | }; |
| 341 | 355 | |
| 356 | test "Parsed.checkHostName" { |
| 357 | const expectEqual = std.testing.expectEqual; |
| 358 | |
| 359 | try expectEqual(true, Parsed.checkHostName("ziglang.org", "ziglang.org")); |
| 360 | try expectEqual(true, Parsed.checkHostName("bar.ziglang.org", "*.ziglang.org")); |
| 361 | try expectEqual(false, Parsed.checkHostName("foo.bar.ziglang.org", "*.ziglang.org")); |
| 362 | try expectEqual(false, Parsed.checkHostName("ziglang.org", "zig*.org")); |
| 363 | try expectEqual(false, Parsed.checkHostName("lang.org", "zig*.org")); |
| 364 | } |
| 365 | |
| 342 | 366 | pub fn parse(cert: Certificate) !Parsed { |
| 343 | 367 | const cert_bytes = cert.buffer; |
| 344 | 368 | const certificate = try der.Element.parse(cert_bytes, cert.index); |