@@ -359,6 +359,156 @@ def test_verify_certificate_identity
359359 end
360360 end
361361
362+ def test_verify_hostname
363+ assert_equal ( true , OpenSSL ::SSL . verify_hostname ( "www.example.com" , "*.example.com" ) )
364+ assert_equal ( false , OpenSSL ::SSL . verify_hostname ( "www.subdomain.example.com" , "*.example.com" ) )
365+ end
366+
367+ def test_verify_wildcard
368+ assert_equal ( false , OpenSSL ::SSL . verify_wildcard ( "foo" , "x*" ) )
369+ assert_equal ( true , OpenSSL ::SSL . verify_wildcard ( "foo" , "foo" ) )
370+ assert_equal ( true , OpenSSL ::SSL . verify_wildcard ( "foo" , "f*" ) )
371+ assert_equal ( true , OpenSSL ::SSL . verify_wildcard ( "foo" , "*" ) )
372+ assert_equal ( false , OpenSSL ::SSL . verify_wildcard ( "abc*bcd" , "abcd" ) )
373+ assert_equal ( false , OpenSSL ::SSL . verify_wildcard ( "xn--qdk4b9b" , "x*" ) )
374+ assert_equal ( false , OpenSSL ::SSL . verify_wildcard ( "xn--qdk4b9b" , "*--qdk4b9b" ) )
375+ assert_equal ( true , OpenSSL ::SSL . verify_wildcard ( "xn--qdk4b9b" , "xn--qdk4b9b" ) )
376+ end
377+
378+ # Comments in this test is excerpted from http://tools.ietf.org/html/rfc6125#page-27
379+ def test_post_connection_check_wildcard_san
380+ # case-insensitive ASCII comparison
381+ # RFC 6125, section 6.4.1
382+ #
383+ # "..matching of the reference identifier against the presented identifier
384+ # is performed by comparing the set of domain name labels using a
385+ # case-insensitive ASCII comparison, as clarified by [DNS-CASE] (e.g.,
386+ # "WWW.Example.Com" would be lower-cased to "www.example.com" for
387+ # comparison purposes)
388+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
389+ create_cert_with_san ( 'DNS:*.example.com' ) , 'www.example.com' ) )
390+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
391+ create_cert_with_san ( 'DNS:*.Example.COM' ) , 'www.example.com' ) )
392+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
393+ create_cert_with_san ( 'DNS:*.example.com' ) , 'WWW.Example.COM' ) )
394+ # 1. The client SHOULD NOT attempt to match a presented identifier in
395+ # which the wildcard character comprises a label other than the
396+ # left-most label (e.g., do not match bar.*.example.net).
397+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
398+ create_cert_with_san ( 'DNS:www.*.com' ) , 'www.example.com' ) )
399+ # 2. If the wildcard character is the only character of the left-most
400+ # label in the presented identifier, the client SHOULD NOT compare
401+ # against anything but the left-most label of the reference
402+ # identifier (e.g., *.example.com would match foo.example.com but
403+ # not bar.foo.example.com or example.com).
404+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
405+ create_cert_with_san ( 'DNS:*.example.com' ) , 'foo.example.com' ) )
406+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
407+ create_cert_with_san ( 'DNS:*.example.com' ) , 'bar.foo.example.com' ) )
408+ # 3. The client MAY match a presented identifier in which the wildcard
409+ # character is not the only character of the label (e.g.,
410+ # baz*.example.net and *baz.example.net and b*z.example.net would
411+ # be taken to match baz1.example.net and foobaz.example.net and
412+ # buzz.example.net, respectively). ...
413+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
414+ create_cert_with_san ( 'DNS:baz*.example.com' ) , 'baz1.example.com' ) )
415+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
416+ create_cert_with_san ( 'DNS:*baz.example.com' ) , 'foobaz.example.com' ) )
417+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
418+ create_cert_with_san ( 'DNS:b*z.example.com' ) , 'buzz.example.com' ) )
419+ # Section 6.4.3 of RFC6125 states that client should NOT match identifier
420+ # where wildcard is other than left-most label.
421+ #
422+ # Also implicitly mentions the wildcard character only in singular form,
423+ # and discourages matching against more than one wildcard.
424+ #
425+ # See RFC 6125, section 7.2, subitem 2.
426+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
427+ create_cert_with_san ( 'DNS:*b*.example.com' ) , 'abc.example.com' ) )
428+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
429+ create_cert_with_san ( 'DNS:*b*.example.com' ) , 'ab.example.com' ) )
430+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
431+ create_cert_with_san ( 'DNS:*b*.example.com' ) , 'bc.example.com' ) )
432+ # ... However, the client SHOULD NOT
433+ # attempt to match a presented identifier where the wildcard
434+ # character is embedded within an A-label or U-label [IDNA-DEFS] of
435+ # an internationalized domain name [IDNA-PROTO].
436+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
437+ create_cert_with_san ( 'DNS:xn*.example.com' ) , 'xn1ca.example.com' ) )
438+ # part of A-label
439+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
440+ create_cert_with_san ( 'DNS:xn--*.example.com' ) , 'xn--1ca.example.com' ) )
441+ # part of U-label
442+ # dNSName in RFC5280 is an IA5String so U-label should NOT be allowed
443+ # regardless of wildcard.
444+ #
445+ # See Section 7.2 of RFC 5280:
446+ # IA5String is limited to the set of ASCII characters.
447+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
448+ create_cert_with_san ( 'DNS:á*.example.com' ) , 'á1.example.com' ) )
449+ end
450+
451+ def test_post_connection_check_wildcard_cn
452+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
453+ create_cert_with_name ( '*.example.com' ) , 'www.example.com' ) )
454+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
455+ create_cert_with_name ( '*.Example.COM' ) , 'www.example.com' ) )
456+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
457+ create_cert_with_name ( '*.example.com' ) , 'WWW.Example.COM' ) )
458+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
459+ create_cert_with_name ( 'www.*.com' ) , 'www.example.com' ) )
460+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
461+ create_cert_with_name ( '*.example.com' ) , 'foo.example.com' ) )
462+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
463+ create_cert_with_name ( '*.example.com' ) , 'bar.foo.example.com' ) )
464+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
465+ create_cert_with_name ( 'baz*.example.com' ) , 'baz1.example.com' ) )
466+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
467+ create_cert_with_name ( '*baz.example.com' ) , 'foobaz.example.com' ) )
468+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
469+ create_cert_with_name ( 'b*z.example.com' ) , 'buzz.example.com' ) )
470+ # Section 6.4.3 of RFC6125 states that client should NOT match identifier
471+ # where wildcard is other than left-most label.
472+ #
473+ # Also implicitly mentions the wildcard character only in singular form,
474+ # and discourages matching against more than one wildcard.
475+ #
476+ # See RFC 6125, section 7.2, subitem 2.
477+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
478+ create_cert_with_name ( '*b*.example.com' ) , 'abc.example.com' ) )
479+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
480+ create_cert_with_name ( '*b*.example.com' ) , 'ab.example.com' ) )
481+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
482+ create_cert_with_name ( '*b*.example.com' ) , 'bc.example.com' ) )
483+ assert_equal ( true , OpenSSL ::SSL . verify_certificate_identity (
484+ create_cert_with_name ( 'xn*.example.com' ) , 'xn1ca.example.com' ) )
485+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
486+ create_cert_with_name ( 'xn--*.example.com' ) , 'xn--1ca.example.com' ) )
487+ # part of U-label
488+ # Subject in RFC5280 states case-insensitive ASCII comparison.
489+ #
490+ # See Section 7.2 of RFC 5280:
491+ # IA5String is limited to the set of ASCII characters.
492+ assert_equal ( false , OpenSSL ::SSL . verify_certificate_identity (
493+ create_cert_with_name ( 'á*.example.com' ) , 'á1.example.com' ) )
494+ end
495+
496+ def create_cert_with_san ( san )
497+ ef = OpenSSL ::X509 ::ExtensionFactory . new
498+ cert = OpenSSL ::X509 ::Certificate . new
499+ cert . subject = OpenSSL ::X509 ::Name . parse ( "/DC=some/DC=site/CN=Some Site" )
500+ ext = ef . create_ext ( 'subjectAltName' , san )
501+ cert . add_extension ( ext )
502+ cert
503+ end
504+
505+ def create_cert_with_name ( name )
506+ cert = OpenSSL ::X509 ::Certificate . new
507+ cert . subject = OpenSSL ::X509 ::Name . new ( [ [ 'DC' , 'some' ] , [ 'DC' , 'site' ] , [ 'CN' , name ] ] )
508+ cert
509+ end
510+
511+
362512 # Create NULL byte SAN certificate
363513 def create_null_byte_SAN_certificate ( critical = false )
364514 ef = OpenSSL ::X509 ::ExtensionFactory . new
0 commit comments