mirror of
https://github.com/golang/go
synced 2024-11-22 08:14:40 -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
|
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
|
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) {
|
|||||||
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) {
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user