Skip to content

Commit

Permalink
Add additional check for old SSL certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
aledbf committed Nov 29, 2017
1 parent 37a230c commit 930bd7f
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 2 deletions.
108 changes: 108 additions & 0 deletions internal/ingress/controller/certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package controller

import (
"crypto/x509"
"net"
"strings"
"unicode/utf8"
)

// Please check https://github.com/golang/go/issues/22922
//
// Since Go 1.9 the common name field is not used anymore.
// We copy the code to not break existing clusters that doesn't have certificates with SAN yet
// TODO: Remove this helpers in the future.

// verifyHostname returns nil if c is a valid certificate for the named host.
// Otherwise it returns an error describing the mismatch.
func verifyHostname(h string, c *x509.Certificate) error {
// IP addresses may be written in [ ].
candidateIP := h
if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
candidateIP = h[1 : len(h)-1]
}
if ip := net.ParseIP(candidateIP); ip != nil {
// We only match IP addresses against IP SANs.
// https://tools.ietf.org/html/rfc6125#appendix-B.2
for _, candidate := range c.IPAddresses {
if ip.Equal(candidate) {
return nil
}
}
return x509.HostnameError{Certificate: c, Host: candidateIP}
}

lowered := toLowerCaseASCII(h)

if len(c.DNSNames) > 0 {
for _, match := range c.DNSNames {
if matchHostnames(toLowerCaseASCII(match), lowered) {
return nil
}
}
// If Subject Alt Name is given, we ignore the common name.
} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
return nil
}

return x509.HostnameError{Certificate: c, Host: h}
}

// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
// an explicitly ASCII function to avoid any sharp corners resulting from
// performing Unicode operations on DNS labels.
func toLowerCaseASCII(in string) string {
// If the string is already lower-case then there's nothing to do.
isAlreadyLowerCase := true
for _, c := range in {
if c == utf8.RuneError {
// If we get a UTF-8 error then there might be
// upper-case ASCII bytes in the invalid sequence.
isAlreadyLowerCase = false
break
}
if 'A' <= c && c <= 'Z' {
isAlreadyLowerCase = false
break
}
}

if isAlreadyLowerCase {
return in
}

out := []byte(in)
for i, c := range out {
if 'A' <= c && c <= 'Z' {
out[i] += 'a' - 'A'
}
}
return string(out)
}

func matchHostnames(pattern, host string) bool {
host = strings.TrimSuffix(host, ".")
pattern = strings.TrimSuffix(pattern, ".")

if len(pattern) == 0 || len(host) == 0 {
return false
}

patternParts := strings.Split(pattern, ".")
hostParts := strings.Split(host, ".")

if len(patternParts) != len(hostParts) {
return false
}

for i, patternPart := range patternParts {
if i == 0 && patternPart == "*" {
continue
}
if patternPart != hostParts[i] {
return false
}
}

return true
}
11 changes: 9 additions & 2 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1032,8 +1032,15 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
cert := bc.(*ingress.SSLCert)
err = cert.Certificate.VerifyHostname(host)
if err != nil {
glog.Warningf("ssl certificate %v does not contain a Common Name or Subject Alternative Name for host %v", key, host)
continue
glog.Warningf("unexpected error validating SSL certificate %v for host %v. Reason: %v", key, host, err)
glog.Warningf("Validating certificate against DNS names. This will be deprecated in a future version.")
// check the common name field
// https://github.com/golang/go/issues/22922
err := verifyHostname(host, cert.Certificate)
if err != nil {
glog.Warningf("ssl certificate %v does not contain a Common Name or Subject Alternative Name for host %v. Reason: %v", key, host, err)
continue
}
}

servers[host].SSLCertificate = cert.PemFileName
Expand Down

0 comments on commit 930bd7f

Please sign in to comment.