mirror of
https://github.com/golang/go
synced 2024-11-22 01:34:41 -07:00
http: check https certificate against host name
Fixes #1093. R=agl, agl1 CC=golang-dev https://golang.org/cl/2115045
This commit is contained in:
parent
eddddf042d
commit
a4514c42dd
@ -670,3 +670,10 @@ func (c *Conn) PeerCertificates() []*x509.Certificate {
|
||||
|
||||
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 {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsValidForHost returns true iff c is a valid certificate for the given host.
|
||||
func (c *Certificate) IsValidForHost(h string) bool {
|
||||
type HostnameError struct {
|
||||
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 {
|
||||
for _, match := range c.DNSNames {
|
||||
if matchHostnames(match, h) {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// 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{}
|
||||
|
@ -96,8 +96,8 @@ func TestCertificateParse(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !certs[0].IsValidForHost("mail.google.com") {
|
||||
t.Errorf("cert not valid for host")
|
||||
if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,12 +59,22 @@ func send(req *Request) (resp *Response, err os.Error) {
|
||||
var conn io.ReadWriteCloser
|
||||
if req.URL.Scheme == "http" {
|
||||
conn, err = net.Dial("tcp", "", addr)
|
||||
} else { // https
|
||||
conn, err = tls.Dial("tcp", "", addr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else { // https
|
||||
conn, err = tls.Dial("tcp", "", addr)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user