/* tofuproxy -- flexible HTTP proxy, TLS terminator, X.509 certificates manager, WARC/Gemini browser Copyright (C) 2021 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package tofuproxy import ( "context" "crypto/tls" "crypto/x509" "fmt" "net" "strings" "go.cypherpunks.ru/ucspi" "go.stargrave.org/tofuproxy/fifos" ) var sessionCache = tls.NewLRUClientSessionCache(1024) func DialTLS(ctx context.Context, network, addr string) (net.Conn, error) { host := strings.Split(addr, ":")[0] ccg := ClientCertificateGetter{host: host} cfg := tls.Config{ VerifyPeerCertificate: func( rawCerts [][]byte, verifiedChains [][]*x509.Certificate, ) error { return verifyCert(host, nil, rawCerts, verifiedChains) }, ClientSessionCache: sessionCache, NextProtos: []string{"h2", "http/1.1"}, GetClientCertificate: ccg.get, } conn, dialErr := tls.Dial(network, addr, &cfg) if dialErr != nil { if _, ok := dialErr.(ErrRejected); ok { return nil, dialErr } cfg.InsecureSkipVerify = true cfg.VerifyPeerCertificate = func( rawCerts [][]byte, verifiedChains [][]*x509.Certificate, ) error { return verifyCert(host, dialErr, rawCerts, verifiedChains) } var err error conn, err = tls.Dial(network, addr, &cfg) if err != nil { fifos.LogErr <- fmt.Sprintf("%s\t%s", addr, dialErr.Error()) return nil, err } } connState := conn.ConnectionState() if !connState.DidResume { fifos.LogTLS <- fmt.Sprintf( "%s\t%s %s %s\t%s\t%s", addr, ucspi.TLSVersion(connState.Version), tls.CipherSuiteName(connState.CipherSuite), connState.PeerCertificates[0].SignatureAlgorithm, spkiHash(connState.PeerCertificates[0]), connState.NegotiatedProtocol, ) } return conn, nil }