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)
+}
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{}
var conn io.ReadWriteCloser
if req.URL.Scheme == "http" {
conn, err = net.Dial("tcp", "", addr)
+ if err != nil {
+ return nil, err
+ }
} else { // https
conn, err = tls.Dial("tcp", "", addr)
- }
- if err != nil {
- return nil, err
+ 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)