diff --git a/connect/comms.go b/connect/comms.go index 2b63f105961164c88c4fc8ec64d1dd1bf98e9cd5..f9e518d279f2ed4829494ed657f45ac56abfda2c 100644 --- a/connect/comms.go +++ b/connect/comms.go @@ -465,7 +465,7 @@ func parseTlsPacket(r io.Reader) (*tlshacks.ClientHelloInfo, bool) { // not be usable until this has been called at least once, unblocking the // listenHTTP func in ServeWithWeb. Future calls will be handled by the // startUpdateCertificate thread. -func (c *ProtoComms) ServeHttps(cert, key []byte) error { +func (c *ProtoComms) ServeHttps(keyPair tls.Certificate) error { if c.mux == nil { return errors.New("mux does not exist; is https enabled?") } @@ -477,16 +477,17 @@ func (c *ProtoComms) ServeHttps(cert, key []byte) error { httpL := c.mux.Match(c.matchWebTls) grpcServer := c.grpcServer - keyPair, err := tls.X509KeyPair( - cert, key) - if err != nil { - return errors.WithMessage(err, "cert & key could not be parsed to valid tls certificate") + var parsedLeafCert *x509.Certificate + var err error + if keyPair.Leaf == nil { + parsedLeafCert, err = x509.ParseCertificate(keyPair.Certificate[0]) + if err != nil { + jww.FATAL.Panicf("Failed to load TLS certificate: %+v", err) + } + } else { + parsedLeafCert = keyPair.Leaf } - parsedLeafCert, err := x509.ParseCertificate(keyPair.Certificate[0]) - if err != nil { - jww.FATAL.Panicf("Failed to load TLS certificate: %+v", err) - } c.httpsX509 = parsedLeafCert listenHTTPS := func(l net.Listener) { diff --git a/connect/connection.go b/connect/connection.go index 31b74642253db0b3b8c5328e4956d4b39d27d69e..24a63cfbb76a81f60e5194a2d06251ade8a4be29 100644 --- a/connect/connection.go +++ b/connect/connection.go @@ -1,6 +1,7 @@ package connect import ( + "crypto/x509" "git.xx.network/elixxir/grpc-web-go-client/grpcweb" jww "github.com/spf13/jwalterweatherman" "google.golang.org/grpc" @@ -51,6 +52,8 @@ type Connection interface { Close() error IsOnline() (time.Duration, bool) + + GetServerCert() (*x509.Certificate, error) clientConnHelpers } diff --git a/connect/connection_test.go b/connect/connection_test.go index 49e66e8e37820cd6c63e77e14aeaa57067f40a35..1f5cd7595539ed05d27fe712e3fadb9d55b10121 100644 --- a/connect/connection_test.go +++ b/connect/connection_test.go @@ -2,6 +2,7 @@ package connect import ( "context" + "crypto/tls" "fmt" "gitlab.com/xx_network/comms/connect/token" pb "gitlab.com/xx_network/comms/messages" @@ -174,7 +175,11 @@ func TestWebConnection_TLS(t *testing.T) { pb.RegisterGenericServer(pc.grpcServer, &TestGenericServer{resp: expectedResponse}) pc.ServeWithWeb() - err = pc.ServeHttps(httpsCertBytes, httpsKeyBytes) + tlsKeypair, err := tls.X509KeyPair(httpsCertBytes, httpsKeyBytes) + if err != nil { + t.Fatal(err) + } + err = pc.ServeHttps(tlsKeypair) if err != nil { t.Fatal(err) } @@ -209,6 +214,11 @@ func TestWebConnection_TLS(t *testing.T) { t.Errorf("Did not receive expected payload") } + _, err = h.GetServerCert() + if err != nil { + t.Errorf("Did not receive cert: %+v", err) + } + pc.Shutdown() h.disconnect() grpcHost.disconnect() @@ -261,7 +271,11 @@ func TestServeWeb_Matchers(t *testing.T) { hostParams := GetDefaultHostParams() hostParams.ConnectionType = ct pc.ServeWithWeb() - err = pc.ServeHttps(httpsCertBytes, httpsKeyBytes) + tlsKeypair, err := tls.X509KeyPair(httpsCertBytes, httpsKeyBytes) + if err != nil { + t.Fatal(err) + } + err = pc.ServeHttps(tlsKeypair) if err != nil { t.Fatal(err) } diff --git a/connect/grpcConn.go b/connect/grpcConn.go index f5a231576d8c5fca970fd26786efe3004bd635ca..c23d76c2a7527fe0fae57771d686250354c0a2ec 100644 --- a/connect/grpcConn.go +++ b/connect/grpcConn.go @@ -1,6 +1,7 @@ package connect import ( + "crypto/x509" "errors" "fmt" "git.xx.network/elixxir/grpc-web-go-client/grpcweb" @@ -40,6 +41,11 @@ func (gc *grpcConn) IsWeb() bool { return false } +// GetServerCert returns an error on grpc hosts +func (gc *grpcConn) GetServerCert() (*x509.Certificate, error) { + return nil, errors.New("GetServerCert not implemented for GRPC hosts") +} + // connectGrpcHelper creates a connection while not under a write lock. // undefined behavior if the caller has not taken the write lock func (gc *grpcConn) connectGrpcHelper() (err error) { diff --git a/connect/host.go b/connect/host.go index c37d07658ac9f04a2c4ed6f8444a9aa486cb3a5a..c98ab054ffdcd8a98e54e751c4fcb3a66632511c 100644 --- a/connect/host.go +++ b/connect/host.go @@ -11,6 +11,7 @@ package connect import ( "context" + "crypto/x509" "fmt" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" @@ -215,6 +216,13 @@ func (h *Host) IsWeb() bool { return h.connection.IsWeb() } +// GetServerCert returns the tls certificate from the server for web hosts +// Note that this will return an error when used on grpc hosts, and will not +// have a certificate ready until something has been sent over the connection. +func (h *Host) GetServerCert() (*x509.Certificate, error) { + return h.connection.GetServerCert() +} + // SetMetricsTesting sets the host metrics to an arbitrary value. Used for testing // purposes only func (h *Host) SetMetricsTesting(m *Metric, face interface{}) { diff --git a/connect/webConn.go b/connect/webConn.go index e0f453b94301ba4aa140a9a383539f791a629a53..54a0b69ead7764a754742339c0d2054bc76b1e7a 100644 --- a/connect/webConn.go +++ b/connect/webConn.go @@ -2,6 +2,7 @@ package connect import ( "crypto/tls" + "crypto/x509" "fmt" "net/http" "net/http/httptrace" @@ -66,6 +67,11 @@ func (wc *webConn) IsWeb() bool { return true } +// GetServerCert returns the server tls certificate stored by the web connection +func (wc *webConn) GetServerCert() (*x509.Certificate, error) { + return wc.connection.GetReceivedCertificate() +} + // connectWebHelper initializes the grpcweb ClientConn object // Note that until the downstream repo is fixed, this doesn't actually // establish a connection past creating the http object. diff --git a/go.mod b/go.mod index ba17b30dd837107b40b8b3c5e191523807e8c947..7a335684daacb5a365e711e56068c3ee05cce2fe 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module gitlab.com/xx_network/comms go 1.19 require ( - git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215181401-0b8a26d47532 + git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221220161254-68bee4d4a516 github.com/golang/protobuf v1.5.2 github.com/improbable-eng/grpc-web v0.15.0 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index b94c70b39a6a3e2f1215af177f10c64bd7775841..ada9e9cc156c4ce8a5f4a4971c18cfb1e56e6192 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215181401-0b8a26d47532 h1:EH4TFLgXGgofV2MsUOgNDmn3X+qfhbQ2RV6zOYRaSdU= -git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221215181401-0b8a26d47532/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo= +git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221220131901-1a7cdcec1831 h1:PQuiXn5EDCJ20q90KSPefHJwiNWGmvuvluNF2vAWcDw= +git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221220131901-1a7cdcec1831/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo= +git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221220161254-68bee4d4a516 h1:Z1AimDI/+3ZZGcmkQaprDKiDn8oGmha7yyPvkDzIuMI= +git.xx.network/elixxir/grpc-web-go-client v0.0.0-20221220161254-68bee4d4a516/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=