Commit a4514c42 authored by Russ Cox's avatar Russ Cox

http: check https certificate against host name

Fixes #1093.

R=agl, agl1
CC=golang-dev
https://golang.org/cl/2115045
parent eddddf04
...@@ -670,3 +670,10 @@ func (c *Conn) PeerCertificates() []*x509.Certificate { ...@@ -670,3 +670,10 @@ func (c *Conn) PeerCertificates() []*x509.Certificate {
return c.peerCertificates return c.peerCertificates
} }
// VerifyHostname checks that the peer certificate chain is valid for
// connecting to host. If so, it returns nil; if not, it returns an os.Error
// describing the problem.
func (c *Conn) VerifyHostname(host string) os.Error {
return c.PeerCertificates()[0].VerifyHostname(host)
}
...@@ -426,19 +426,37 @@ func matchHostnames(pattern, host string) bool { ...@@ -426,19 +426,37 @@ func matchHostnames(pattern, host string) bool {
return true return true
} }
// IsValidForHost returns true iff c is a valid certificate for the given host. type HostnameError struct {
func (c *Certificate) IsValidForHost(h string) bool { Certificate *Certificate
Host string
}
func (h *HostnameError) String() string {
var valid string
c := h.Certificate
if len(c.DNSNames) > 0 {
valid = strings.Join(c.DNSNames, ", ")
} else {
valid = c.Subject.CommonName
}
return "certificate is valid for " + valid + ", not " + h.Host
}
// VerifyHostname returns nil if c is a valid certificate for the named host.
// Otherwise it returns an os.Error describing the mismatch.
func (c *Certificate) VerifyHostname(h string) os.Error {
if len(c.DNSNames) > 0 { if len(c.DNSNames) > 0 {
for _, match := range c.DNSNames { for _, match := range c.DNSNames {
if matchHostnames(match, h) { if matchHostnames(match, h) {
return true return nil
} }
} }
// If Subject Alt Name is given, we ignore the common name. // If Subject Alt Name is given, we ignore the common name.
return false } else if matchHostnames(c.Subject.CommonName, h) {
return nil
} }
return matchHostnames(c.Subject.CommonName, h) return &HostnameError{c, h}
} }
type UnhandledCriticalExtension struct{} type UnhandledCriticalExtension struct{}
......
...@@ -96,8 +96,8 @@ func TestCertificateParse(t *testing.T) { ...@@ -96,8 +96,8 @@ func TestCertificateParse(t *testing.T) {
t.Error(err) t.Error(err)
} }
if !certs[0].IsValidForHost("mail.google.com") { if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
t.Errorf("cert not valid for host") t.Error(err)
} }
} }
......
...@@ -59,11 +59,21 @@ func send(req *Request) (resp *Response, err os.Error) { ...@@ -59,11 +59,21 @@ func send(req *Request) (resp *Response, err os.Error) {
var conn io.ReadWriteCloser var conn io.ReadWriteCloser
if req.URL.Scheme == "http" { if req.URL.Scheme == "http" {
conn, err = net.Dial("tcp", "", addr) conn, err = net.Dial("tcp", "", addr)
if err != nil {
return nil, err
}
} else { // https } else { // https
conn, err = tls.Dial("tcp", "", addr) conn, err = tls.Dial("tcp", "", addr)
} if err != nil {
if err != nil { return nil, err
return nil, err }
h := req.URL.Host
if hasPort(h) {
h = h[0:strings.LastIndex(h, ":")]
}
if err := conn.(*tls.Conn).VerifyHostname(h); err != nil {
return nil, err
}
} }
err = req.Write(conn) err = req.Write(conn)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment