@@ -316,29 +316,53 @@ pub const Parsed = struct {
316316 return error .CertificateHostMismatch ;
317317 }
318318
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.
319327 fn checkHostName (host_name : []const u8 , dns_name : []const u8 ) bool {
320328 if (mem .eql (u8 , dns_name , host_name )) {
321329 return true ; // exact match
322330 }
323331
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 ;
331341 }
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 ;
335347 }
336- }
348+ };
337349
338- return false ;
350+ // If the components are not the same
351+ // length then there is no match.
352+ return len_match ;
339353 }
340354};
341355
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+
342366pub fn parse (cert : Certificate ) ! Parsed {
343367 const cert_bytes = cert .buffer ;
344368 const certificate = try der .Element .parse (cert_bytes , cert .index );
0 commit comments