func performHandshakeAndValidation(conn *tls.Conn, uri *url.URL) error { if err := conn.Handshake(); err != nil { return err } cs := conn.ConnectionState() if !cs.NegotiatedProtocolIsMutual || cs.NegotiatedProtocol != protocol.ProtocolName { return fmt.Errorf("protocol negotiation error") } q := uri.Query() relayIDs := q.Get("id") if relayIDs != "" { relayID, err := syncthingprotocol.DeviceIDFromString(relayIDs) if err != nil { return fmt.Errorf("relay address contains invalid verification id: %s", err) } certs := cs.PeerCertificates if cl := len(certs); cl != 1 { return fmt.Errorf("unexpected certificate count: %d", cl) } remoteID := syncthingprotocol.NewDeviceID(certs[0].Raw) if remoteID != relayID { return fmt.Errorf("relay id does not match. Expected %v got %v", relayID, remoteID) } } return nil }
// StartTLS takes an identity and an authority certificate and upgrades the net.Conn on the protocol to TLS // It returns the CommonName from the peer certitifcate, or an error func (p *Protocol) StartTLS(identity *security.Identity, caCertificate *security.Certificate) (string, error) { var ( err error tlsConn *tls.Conn ) if err = p.WriteBytesWithDeadline([]byte{TLS}); err != nil { return "", err } // Build the config config := new(tls.Config) config.ServerName = p.serverName // Setup the tls connection if err = p.tlsSetup(config, identity, caCertificate); err != nil { return "", err } // Upgrade the connection to TLS // TODO: Add a deadline here? tlsConn = tls.Client(p.conn, config) if err = tlsConn.Handshake(); err != nil { return "", err } // Capture the connection state cs := tlsConn.ConnectionState() // And replace the original connection p.conn = net.Conn(tlsConn) p.setupBuffers() return cs.PeerCertificates[0].Subject.CommonName, nil }
// HandleStartTLS is the companion to StartTLS, and will do the connection upgrade. It assumes // that the TLS command byte has already been read. Like StartTLS it returns the peer name, or // an error func (p *Protocol) HandleStartTLS(identity *security.Identity, caCertificate *security.Certificate) (string, error) { var ( err error tlsConn *tls.Conn ) // Build the config config := new(tls.Config) config.ClientAuth = tls.RequireAndVerifyClientCert // Setup the tls connection if err := p.tlsSetup(config, identity, caCertificate); err != nil { return "", err } // Upgrade the connection to TLS // TODO: Add a deadline here? tlsConn = tls.Server(p.conn, config) if err = tlsConn.Handshake(); err != nil { return "", err } // Capture the connection state cs := tlsConn.ConnectionState() // And replace the original connection p.conn = net.Conn(tlsConn) p.setupBuffers() // Send an Ack p.Ack() return cs.PeerCertificates[0].Subject.CommonName, nil }
// getChain returns chain of certificates retrieved from TLS session // established at given addr (host:port) for hostname provided. If addr is // empty, then hostname:443 is used. func getChain(hostname, addr string) ([]*x509.Certificate, error) { if hostname == "" { return nil, errors.New("empty hostname") } var ( conn *tls.Conn err error ) type tempErr interface { Temporary() bool } conf := &tls.Config{ServerName: hostname} if addr == "" { addr = hostname + ":443" } dialer := &net.Dialer{ Timeout: 30 * time.Second, } for i := 0; i < 3; i++ { if i > 0 { time.Sleep(time.Duration(i) * time.Second) } conn, err = tls.DialWithDialer(dialer, "tcp", addr, conf) if e, ok := err.(tempErr); ok && e.Temporary() { continue } if err != nil { return nil, err } defer conn.Close() return conn.ConnectionState().PeerCertificates, nil } return nil, err }
func postVerifyTLSConnection(conn *tls.Conn, config *TLSConfig) error { st := conn.ConnectionState() if !st.HandshakeComplete { return errors.New("incomplete handshake") } // no more checks if no extra configs available if config == nil { return nil } versions := config.Versions if versions == nil { versions = tlsDefaultVersions } versionOK := false for _, version := range versions { versionOK = versionOK || st.Version == uint16(version) } if !versionOK { return fmt.Errorf("tls version %v not configured", TLSVersion(st.Version)) } return nil }
// SessionResumeScan tests that host is able to resume sessions across all addresses. func sessionResumeScan(addr, hostname string) (grade Grade, output Output, err error) { config := defaultTLSConfig(hostname) config.ClientSessionCache = tls.NewLRUClientSessionCache(1) conn, err := tls.DialWithDialer(Dialer, Network, addr, config) if err != nil { return } if err = conn.Close(); err != nil { return } return multiscan(addr, func(addrport string) (g Grade, o Output, e error) { var conn *tls.Conn if conn, e = tls.DialWithDialer(Dialer, Network, addrport, config); e != nil { return } conn.Close() if o = conn.ConnectionState().DidResume; o.(bool) { g = Good } return }) }
func enrichWithOwnChecks(conn *tls.Conn, tlsConfig *tls.Config) error { var err error if err = conn.Handshake(); err != nil { conn.Close() return err } opts := x509.VerifyOptions{ Roots: tlsConfig.RootCAs, CurrentTime: time.Now(), DNSName: "", Intermediates: x509.NewCertPool(), } certs := conn.ConnectionState().PeerCertificates for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } _, err = certs[0].Verify(opts) if err != nil { conn.Close() return err } return nil }
func connect(app string, keyFile string, certFile string, sandbox bool) { defer CapturePanic(fmt.Sprintf("connection to apns server error %s", app)) cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Printf("server : loadKeys: %s", err) } config := tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true} endPoint := APNS_ENDPOINT if sandbox { endPoint = APNS_SANDBOX_ENDPOINT } var conn *tls.Conn for { conn, err = tls.Dial("tcp", endPoint, &config) if err != nil { log.Println("连接服务器有误, 2秒后将重连", err) time.Sleep(time.Second * 2) } else { break } } log.Println("client is connect to ", conn.RemoteAddr()) state := conn.ConnectionState() log.Println("client: hand shake ", state.HandshakeComplete) log.Println("client: mutual", state.NegotiatedProtocolIsMutual) if sandbox { app = app + DEVELOP_SUBFIX } info := &ConnectInfo{Connection: conn, App: app, Sandbox: sandbox, lastActivity: time.Now().Unix()} socketCN <- info }
func test_conn(conn *tls.Conn, options *ScanOptions, record *ScanRecord) bool { //check SSL certificate success := false for _, cert := range conn.ConnectionState().PeerCertificates { for _, verifyHost := range options.Config.ScanGoogleIP.SSLCertVerifyHosts { if cert.VerifyHostname(verifyHost) != nil { return false } else { success = true } } if success { break } } for _, verifyHost := range options.Config.ScanGoogleIP.HTTPVerifyHosts { conn.SetReadDeadline(time.Now().Add(record.httpVerifyTimeout)) req, _ := http.NewRequest("HEAD", "https://"+verifyHost, nil) res, err := httputil.NewClientConn(conn, nil).Do(req) if nil != err || res.StatusCode >= 400 { return false } } return true }
func main() { ripmgr := randip.NewRandIPv4Mgr(true, 1249767200) for { newIP, err := ripmgr.GetNextIP() if err != nil { log.Println("IP Addr Exhausted") return } else { go func() { log.Println(newIP.String()) config := tls.Config{InsecureSkipVerify: true, ServerName: "google.com"} var err error var newConn *tls.Conn newConn, err = tls.DialWithDialer(&net.Dialer{Timeout: 2 * time.Second}, "tcp", newIP.String()+":443", &config) if err != nil { log.Println(err) } else { conState := newConn.ConnectionState() fmt.Println(newConn.RemoteAddr(), conState.PeerCertificates[0].NotBefore, conState.PeerCertificates[0].NotAfter, conState.PeerCertificates[0].SerialNumber) //jsonCert,_ := json.MarshalIndent(conState.PeerCertificates[0],""," ") //fmt.Println(string(jsonCert)) newConn.Close() } }() } } }
func getPublicKey(tlsConn *tls.Conn) ([]byte, error) { state := tlsConn.ConnectionState() for _, v := range state.PeerCertificates { return x509.MarshalPKIXPublicKey(v.PublicKey) } return []byte{}, nil }
func handle_tlsconn(conn *tls.Conn, context *Context) bool { conn.SetDeadline(time.Now().Add(config.TimeoutTLS)) err := conn.Handshake() if err != nil { util.Log(0, "ERROR! [SECURITY] TLS Handshake: %v", err) return false } var no_deadline time.Time conn.SetDeadline(no_deadline) state := conn.ConnectionState() if len(state.PeerCertificates) == 0 { util.Log(0, "ERROR! [SECURITY] TLS peer has no certificate") return false } cert := state.PeerCertificates[0] // docs are unclear about this but I think leaf certificate is the first entry because that's as it is in tls.Certificate if util.LogLevel >= 2 { // because creating the dump is expensive util.Log(2, "DEBUG! [SECURITY] Peer certificate presented by %v:\n%v", conn.RemoteAddr(), CertificateInfo(cert)) } for _, cacert := range config.CACert { err = cert.CheckSignatureFrom(cacert) if err == nil { if string(cacert.RawSubject) != string(cert.RawIssuer) { err = fmt.Errorf("Certificate was issued by wrong CA: \"%v\" instead of \"%v\"", cacert.Subject, cert.Issuer) } else { break // stop checking if we found a match for a CA. err == nil here! } } } if err != nil { util.Log(0, "ERROR! [SECURITY] TLS peer presented certificate not signed by trusted CA: %v", err) return false } for _, e := range cert.Extensions { if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 17 { parseSANExtension(e.Value, context) } else if len(e.Id) == 9 && e.Id[0] == 1 && e.Id[1] == 3 && e.Id[2] == 6 && e.Id[3] == 1 && e.Id[4] == 4 && e.Id[5] == 1 && e.Id[6] == 45753 && e.Id[7] == 1 { switch e.Id[8] { case 5: err = parseConnectionLimits(e.Value, context) if err != nil { util.Log(0, "ERROR! [SECURITY] GosaConnectionLimits: %v", err) } case 6: //err = parseAccessControl(e.Value, context) //if err != nil { util.Log(0, "ERROR! [SECURITY] GosaAccessControl: %v", err) } } } } context.TLS = true return true }
// Default TLS peer name function - returns the CN of the certificate func defaultTlsPeerName(tlsConn *tls.Conn) (tlsPeer string, ok bool) { state := tlsConn.ConnectionState() if len(state.PeerCertificates) <= 0 { return "", false } cn := state.PeerCertificates[0].Subject.CommonName return cn, true }
// DialTLSFunc returns the adequate dial function, when using SSL, depending on // whether we're using insecure TLS (certificate verification is disabled), or we // have some trusted certs, or we're on android.1 // If the client's config has some trusted certs, the server's certificate will // be checked against those in the config after the TLS handshake. func (c *Client) DialTLSFunc() func(network, addr string) (net.Conn, error) { if !c.useTLS() { return nil } trustedCerts := c.getTrustedCerts() var stdTLS bool if !c.insecureAnyTLSCert && len(trustedCerts) == 0 { // TLS with normal/full verification. stdTLS = true if !android.IsChild() { // Not android, so let the stdlib deal with it return nil } } return func(network, addr string) (net.Conn, error) { var conn *tls.Conn var err error if android.IsChild() { ac, err := android.Dial(network, addr) if err != nil { return nil, err } var tlsConfig *tls.Config if stdTLS { tlsConfig, err = android.TLSConfig() if err != nil { return nil, err } } else { tlsConfig = &tls.Config{InsecureSkipVerify: true} } conn = tls.Client(ac, tlsConfig) if err := conn.Handshake(); err != nil { return nil, err } } else { conn, err = tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: true}) if err != nil { return nil, err } } if c.insecureAnyTLSCert { return conn, nil } certs := conn.ConnectionState().PeerCertificates if len(certs) < 1 { return nil, fmt.Errorf("no TLS peer certificates from %s", addr) } sig := hashutil.SHA256Prefix(certs[0].Raw) for _, v := range trustedCerts { if v == sig { return conn, nil } } return nil, fmt.Errorf("TLS server at %v presented untrusted certificate (signature %q)", addr, sig) } }
// DialTLSFunc returns the adequate dial function, when using SSL, depending on // whether we're using insecure TLS (certificate verification is disabled), or we // have some trusted certs, or we're on android. // If the client's config has some trusted certs, the server's certificate will // be checked against those in the config after the TLS handshake. func (c *Client) DialTLSFunc() func(network, addr string) (net.Conn, error) { if !c.useTLS() { return nil } trustedCerts := c.getTrustedCerts() var stdTLS bool if !c.InsecureTLS && len(trustedCerts) == 0 { // TLS with normal/full verification stdTLS = true if !android.IsChild() { // Not android, so let the stdlib deal with it return nil } } return func(network, addr string) (net.Conn, error) { var conn *tls.Conn var err error if android.IsChild() { con, err := android.Dial(network, addr) if err != nil { return nil, err } var tlsConfig *tls.Config if stdTLS { tlsConfig, err = android.TLSConfig() if err != nil { return nil, err } } else { tlsConfig = &tls.Config{InsecureSkipVerify: true} } conn = tls.Client(con, tlsConfig) if err = conn.Handshake(); err != nil { return nil, err } } else { conn, err = tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: true}) if err != nil { return nil, err } } if c.InsecureTLS { return conn, nil } certs := conn.ConnectionState().PeerCertificates if certs == nil || len(certs) < 1 { return nil, errors.New("Could not get server's certificate from the TLS connection.") } sig := hashutil.SHA256Prefix(certs[0].Raw) for _, v := range trustedCerts { if v == sig { return conn, nil } } return nil, fmt.Errorf("Server's certificate %v is not in the trusted list", sig) } }
func verifyLegacyCertificate(conn *tls.Conn, expectedCertificate *x509.Certificate) error { certs := conn.ConnectionState().PeerCertificates if len(certs) < 1 { return ContextError(errors.New("no certificate to verify")) } if !bytes.Equal(certs[0].Raw, expectedCertificate.Raw) { return ContextError(errors.New("unexpected certificate")) } return nil }
func verifyClientAddrMatch(c *tls.Conn) error { err := c.Handshake() if err != nil { return err } addr, _, err := net.SplitHostPort(c.RemoteAddr().String()) if err != nil { return err } return c.ConnectionState().VerifiedChains[0][0].VerifyHostname(addr) }
func NewResolver(conn *tls.Conn, endpoint string, logger *logrus.Entry) (*Resolver, error) { certs := conn.ConnectionState().PeerCertificates chain := []ResolverPair{} for _, cert := range certs { cn := cert.Subject.CommonName if len(cert.Subject.OrganizationalUnit) > 0 && cn != "" { ou := cert.Subject.OrganizationalUnit[0] chain = append(chain, ResolverPair{cn, ou}) } } if len(chain) == 0 { return nil, errors.New("Cannot found CommonName or OrganizationalUnit in peer certificate") } userId := chain[0].userId role := chain[0].role endpoint = strings.Replace(endpoint, ":userId", userId, 1) endpoint = strings.Replace(endpoint, ":role", role, 1) logger.Debug("Resolve using ", endpoint) response, err := http.Get(endpoint) if err != nil { return nil, err } defer response.Body.Close() content, err := ioutil.ReadAll(response.Body) if err != nil { return nil, err } res := &Resolver{} err = json.Unmarshal(content, res) if err != nil { return nil, err } addrAndPort := strings.Join([]string{res.RawAddr, "2376"}, ":") addr, err := net.ResolveTCPAddr("tcp", addrAndPort) if err != nil { return nil, err } res.Addr = addr return res, nil }
// tlsConnectionStateString выводит в лог информацию о TLS-соединении. func tlsConnectionStateString(conn *tls.Conn) string { var state = conn.ConnectionState() return fmt.Sprint("Connection state:", "\n------------------------------------------------------------", "\n Local Address: ", conn.LocalAddr(), "\n Remote Address: ", conn.RemoteAddr(), "\n TLS version: ", state.Version, "\n Handshake Complete: ", state.HandshakeComplete, "\n Did Resume: ", state.DidResume, "\n Cipher Suite: ", state.CipherSuite, "\n------------------------------------------------------------") }
func (tcc *TLSClientConfig) Verify(conn *tls.Conn) (*TLSState, error) { var ocsprep *ocsp.Response var der []byte var err error res := new(TLSState) cstate := conn.ConnectionState() res.SNIExist = (tcc.SNI != "") res.PKPExist = (tcc.PKPs != nil && len(tcc.PKPs) > 0) if cstate.OCSPResponse != nil { ocsprep, err = ocsp.ParseResponse(cstate.OCSPResponse, nil) if err != nil { return nil, err } res.OCSPExist = true res.OCSPValid = (ocsprep.Status == ocsp.Good) res.OCSPUnknown = (ocsprep.Status == ocsp.Unknown) } for _, peercert := range cstate.PeerCertificates { der, err = x509.MarshalPKIXPublicKey(peercert.PublicKey) if err != nil { return nil, err } if res.SNIExist && !res.SNIValid && peercert.VerifyHostname(tcc.SNI) == nil { res.SNIValid = true } if res.OCSPValid && !res.OCSPChecked && ocsprep.CheckSignatureFrom(peercert) == nil { res.OCSPChecked = true } rawhash := sha256.Sum256(der) hash := base64.StdEncoding.EncodeToString(rawhash[:]) if res.PKPExist { res.PKPCerts++ valid, ok := tcc.PKPs[hash] switch { case ok && valid: res.PKPValid++ case ok && !valid: res.PKPInvalid++ } } } return res, nil }
func NewTLSRedialTransport(conn *tls.Conn, serverName string) *TLSRedialTransport { t := &TLSRedialTransport{ ServerConn: conn, ServerName: serverName, serverAddr: conn.RemoteAddr().String(), publicKey: conn.ConnectionState().PeerCertificates[0].RawSubjectPublicKeyInfo, } t.Dial = t.dial t.timeout = time.AfterFunc(10*time.Second, t.CloseIdleConnections) return t }
// Handle closing down a connection when the handshake has timedout. func tlsTimeout(c *client, conn *tls.Conn) { c.mu.Lock() nc := c.nc c.mu.Unlock() // Check if already closed if nc == nil { return } cs := conn.ConnectionState() if cs.HandshakeComplete == false { c.Debugf("TLS handshake timeout") c.sendErr("Secure Connection - TLS Required") c.closeConnection() } }
func tryConnect(addr string, strict bool) (errchan chan error) { errchan = make(chan error) go func() { caCertFile, err := ioutil.TempFile("", "logstash-forwarder-cacert") if err != nil { panic(err) } defer func() { os.Remove(caCertFile.Name()) }() ioutil.WriteFile(caCertFile.Name(), []byte(caCert), os.ModeTemporary) // this can be messy because of localhost resolving to ipv6 addresses // but there's no easy way to disable v6 resolution here const wait = 5 const retryLimit = 3 tryAttempt := 0 exinfo := "" config := &NetworkConfig{ SSLCA: caCertFile.Name(), Servers: []string{addr}, Timeout: wait, timeout: time.Second * wait, } var socket *tls.Conn for socket == nil && tryAttempt < retryLimit { select { case socket = <-doConnect(config): case <-time.After(time.Second * wait): log.Printf("INFO: Connect timeout: attempt: %d\n", tryAttempt) tryAttempt++ } } if socket == nil { errchan <- errors.New("Client connect failed. " + exinfo) return } defer socket.Close() log.Printf("INFO: Connected to %s\n", socket.RemoteAddr()) if !socket.ConnectionState().HandshakeComplete { errchan <- errors.New("handshake should be complete") return } errchan <- nil }() return errchan }
func getClientID(tlsConn *tls.Conn) (string, error) { state := tlsConn.ConnectionState() if len(state.PeerCertificates) == 0 { return "", fmt.Errorf("client certificate not found") } cert := state.PeerCertificates[0] parts := strings.Split(cert.Subject.CommonName, "-") if len(parts) != 3 || parts[0] != appname || parts[1] != "client" || len(parts[2]) == 0 { return "", fmt.Errorf("bad client common name") } return parts[2], nil }
// DialFunc returns the adequate dial function, depending on // whether SSL is required, the client's config has some trusted // certs, and we're on android. // If the client's config has some trusted certs, the server's // certificate will be checked against those in the config after // the TLS handshake. func (c *Client) DialFunc() func(network, addr string) (net.Conn, error) { trustedCerts := c.GetTrustedCerts() if !c.useTLS() || (!c.InsecureTLS && len(trustedCerts) == 0) { // No TLS, or TLS with normal/full verification if onAndroid() { return func(network, addr string) (net.Conn, error) { return androidDial(network, addr) } } return nil } return func(network, addr string) (net.Conn, error) { var conn *tls.Conn var err error if onAndroid() { con, err := androidDial(network, addr) if err != nil { return nil, err } conn = tls.Client(con, &tls.Config{InsecureSkipVerify: true}) if err = conn.Handshake(); err != nil { return nil, err } } else { conn, err = tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: true}) if err != nil { return nil, err } } if c.InsecureTLS { return conn, nil } certs := conn.ConnectionState().PeerCertificates if certs == nil || len(certs) < 1 { return nil, errors.New("Could not get server's certificate from the TLS connection.") } sig := misc.SHA1Prefix(certs[0].Raw) for _, v := range trustedCerts { if v == sig { return conn, nil } } return nil, fmt.Errorf("Server's certificate %v is not in the trusted list", sig) } }
// getChain is a helper function that retreives the host's certificate chain. func getChain(addr string, config *tls.Config) (chain []*x509.Certificate, err error) { var conn *tls.Conn conn, err = tls.DialWithDialer(Dialer, Network, addr, config) if err != nil { return } err = conn.Close() if err != nil { return } chain = conn.ConnectionState().PeerCertificates if len(chain) == 0 { err = fmt.Errorf("%s returned empty certificate chain", addr) } return }
/* Check that the TLS connection's certficate can be applied to this connection. Because irc.coldfront.net presents a certificate not as irc.coldfront.net, but as it's actual host (e.g. snow.coldfront.net), We do this by comparing the IP address of the certs name to the IP address of our connection. If they match we're OK. */ func isCertValid(conn *tls.Conn) bool { connAddr := strings.Split(conn.RemoteAddr().String(), ":")[0] cert := conn.ConnectionState().PeerCertificates[0] if len(cert.DNSNames) == 0 { // Cert has single name, the usual case return isIPMatch(cert.Subject.CommonName, connAddr) } // Cert has several valid names for _, certname := range cert.DNSNames { if isIPMatch(certname, connAddr) { return true } } return false }
func verifyServerCerts(conn *tls.Conn, serverName string, config *tls.Config) ([][]*x509.Certificate, error) { certs := conn.ConnectionState().PeerCertificates opts := x509.VerifyOptions{ Roots: config.RootCAs, CurrentTime: time.Now(), DNSName: serverName, Intermediates: x509.NewCertPool(), } for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } return certs[0].Verify(opts) }
func verifyCrypto(conn *tls.Conn) (*Connection, error) { if err := conn.Handshake(); err != nil { return nil, err } certs := conn.ConnectionState().PeerCertificates if len(certs) != 1 { return nil, errors.New(fmt.Sprintf("Illegal number of certificates presented by peer (%d)", len(certs))) } cert := certs[0] if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil { return nil, err } return &Connection{Conn: conn, Id: NewIdentity(cert)}, nil }
// Wrap a net.Conn into a client tls connection, performing any // additional verification as needed. // // As of go 1.3, crypto/tls only supports either doing no certificate // verification, or doing full verification including of the peer's // DNS name. For consul, we want to validate that the certificate is // signed by a known CA, but because consul doesn't use DNS names for // node names, we don't verify the certificate DNS names. Since go 1.3 // no longer supports this mode of operation, we have to do it // manually. func WrapTLSClient(conn net.Conn, tlsConfig *tls.Config) (net.Conn, error) { var err error var tlsConn *tls.Conn tlsConn = tls.Client(conn, tlsConfig) // If crypto/tls is doing verification, there's no need to do // our own. if tlsConfig.InsecureSkipVerify == false { return tlsConn, nil } if err = tlsConn.Handshake(); err != nil { tlsConn.Close() return nil, err } // The following is lightly-modified from the doFullHandshake // method in crypto/tls's handshake_client.go. opts := x509.VerifyOptions{ Roots: tlsConfig.RootCAs, CurrentTime: time.Now(), DNSName: "", Intermediates: x509.NewCertPool(), } certs := tlsConn.ConnectionState().PeerCertificates for i, cert := range certs { if i == 0 { continue } opts.Intermediates.AddCert(cert) } _, err = certs[0].Verify(opts) if err != nil { tlsConn.Close() return nil, err } return tlsConn, err }