mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
Starting in grpc-go v1.67.0, clients and servers reject TLS handshakes when ALPN is not negotiated. This changed the default value of GRPC_ENFORCE_ALPN_ENABLED from false to true. The default flip is in https://github.com/grpc/grpc-go/pull/7535 Our mailbox transport handshake can reach endpoints that currently do not negotiate ALPN, so LNC session setup started failing and the lnc_auth flow timed out, with malformed header/content-type errors showing up later on the stream path. This adds mailbox-specific TLS transport credentials that allow a missing negotiated ALPN value for mailbox links. The mailbox server path and the integration-test mailbox clients now use these credentials, so session establishment works again.
121 lines
3.3 KiB
Go
121 lines
3.3 KiB
Go
package session
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
|
|
"google.golang.org/grpc/credentials"
|
|
)
|
|
|
|
const http2Proto = "h2"
|
|
|
|
// NewMailboxTLSCredentials creates transport credentials for mailbox
|
|
// connections. Unlike grpc's default TLS credentials, this allows endpoints
|
|
// that don't negotiate ALPN yet. This is needed as a workaround for grpc-go
|
|
// v1.67.0 ALPN enforcement added by https://github.com/grpc/grpc-go/pull/7535
|
|
//
|
|
// TODO: remove this file when all target mailbox endpoints support ALPN.
|
|
func NewMailboxTLSCredentials(
|
|
config *tls.Config) credentials.TransportCredentials {
|
|
|
|
tlsConfig := &tls.Config{}
|
|
if config != nil {
|
|
tlsConfig = config.Clone()
|
|
}
|
|
|
|
return &mailboxTLSCreds{config: tlsConfig}
|
|
}
|
|
|
|
// mailboxTLSCreds is a mailbox-specific TransportCredentials implementation
|
|
// that keeps TLS enabled but tolerates peers that do not negotiate ALPN.
|
|
type mailboxTLSCreds struct {
|
|
config *tls.Config
|
|
}
|
|
|
|
// ClientHandshake performs the client side TLS handshake for mailbox links
|
|
// while allowing an empty negotiated ALPN value from the remote endpoint.
|
|
func (c *mailboxTLSCreds) ClientHandshake(ctx context.Context, authority string,
|
|
rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
|
|
|
|
cfg := c.config.Clone()
|
|
if cfg.ServerName == "" {
|
|
serverName, _, err := net.SplitHostPort(authority)
|
|
if err != nil {
|
|
serverName = authority
|
|
}
|
|
cfg.ServerName = serverName
|
|
}
|
|
|
|
cfg.NextProtos = appendH2(cfg.NextProtos)
|
|
|
|
conn := tls.Client(rawConn, cfg)
|
|
if err := conn.HandshakeContext(ctx); err != nil {
|
|
_ = conn.Close()
|
|
|
|
return nil, nil, err
|
|
}
|
|
|
|
return conn, tlsAuthInfo(conn.ConnectionState()), nil
|
|
}
|
|
|
|
// ServerHandshake performs the server side TLS handshake for mailbox links
|
|
// while allowing an empty negotiated ALPN value from the peer.
|
|
func (c *mailboxTLSCreds) ServerHandshake(rawConn net.Conn) (
|
|
net.Conn, credentials.AuthInfo, error) {
|
|
|
|
cfg := c.config.Clone()
|
|
cfg.NextProtos = appendH2(cfg.NextProtos)
|
|
|
|
conn := tls.Server(rawConn, cfg)
|
|
if err := conn.Handshake(); err != nil {
|
|
_ = conn.Close()
|
|
|
|
return nil, nil, err
|
|
}
|
|
|
|
return conn, tlsAuthInfo(conn.ConnectionState()), nil
|
|
}
|
|
|
|
// Info returns protocol metadata for these transport credentials.
|
|
func (c *mailboxTLSCreds) Info() credentials.ProtocolInfo {
|
|
return credentials.ProtocolInfo{
|
|
SecurityProtocol: "tls",
|
|
SecurityVersion: "1.2",
|
|
ServerName: c.config.ServerName,
|
|
}
|
|
}
|
|
|
|
// Clone returns a copy of these transport credentials.
|
|
func (c *mailboxTLSCreds) Clone() credentials.TransportCredentials {
|
|
return &mailboxTLSCreds{config: c.config.Clone()}
|
|
}
|
|
|
|
// OverrideServerName overrides the TLS server name used by the client side
|
|
// handshake.
|
|
func (c *mailboxTLSCreds) OverrideServerName(serverNameOverride string) error {
|
|
c.config.ServerName = serverNameOverride
|
|
|
|
return nil
|
|
}
|
|
|
|
// tlsAuthInfo builds credentials.AuthInfo from TLS connection state.
|
|
func tlsAuthInfo(state tls.ConnectionState) credentials.TLSInfo {
|
|
return credentials.TLSInfo{
|
|
State: state,
|
|
CommonAuthInfo: credentials.CommonAuthInfo{
|
|
SecurityLevel: credentials.PrivacyAndIntegrity,
|
|
},
|
|
}
|
|
}
|
|
|
|
// appendH2 ensures "h2" is present in the ALPN protocol list.
|
|
func appendH2(nextProtos []string) []string {
|
|
for _, proto := range nextProtos {
|
|
if proto == http2Proto {
|
|
return nextProtos
|
|
}
|
|
}
|
|
|
|
return append(nextProtos, http2Proto)
|
|
}
|