golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
120.09k stars 17.24k forks source link

crypto/tls: panic with `crypto/tls/fipsonly` #67145

Closed etodd closed 2 weeks ago

etodd commented 2 weeks ago

Go version

go version go1.22.2 linux/amd64

Output of go env in your module/workspace:

O111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT='boringcrypto'
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/root/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/root/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.2'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/root/thing/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4147770740=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I attempted to connect to AWS Aurora over TLS using database/sql with GOEXPERIMENT=boringcrypto and import _ "crypto/tls/fipsonly" and got an error. It is difficult to reproduce because I connected and queried one Aurora instance just fine, but the other threw an error.

What did you see happen?

I got an error when attempting the connection. It was a recovered nil pointer panic. After removing the recover() call, I got this:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x6772f2]

goroutine 1 [running]:
internal/godebug.(*Setting).IncNonDefault(0x7bf6a0?)
        /usr/local/go/src/internal/godebug/godebug.go:102 +0x12
crypto/tls.(*clientHandshakeState).pickCipherSuite(0xc00007eea0)
        /usr/local/go/src/crypto/tls/handshake_client.go:530 +0xbd
crypto/tls.(*clientHandshakeState).processServerHello(0xc00007eea0)
        /usr/local/go/src/crypto/tls/handshake_client.go:755 +0x25
crypto/tls.(*clientHandshakeState).handshake(0xc00007eea0)
        /usr/local/go/src/crypto/tls/handshake_client.go:442 +0x35
crypto/tls.(*Conn).clientHandshake(0xc000004a88, {0x872190, 0xc0000744b0})
        /usr/local/go/src/crypto/tls/handshake_client.go:274 +0x685
crypto/tls.(*Conn).handshakeContext(0xc000004a88, {0x872120, 0xaae120})
        /usr/local/go/src/crypto/tls/conn.go:1553 +0x3cb
crypto/tls.(*Conn).HandshakeContext(...)
        /usr/local/go/src/crypto/tls/conn.go:1493
crypto/tls.(*Conn).Handshake(...)
        /usr/local/go/src/crypto/tls/conn.go:1477
crypto/tls.(*Conn).Write(0x7c1f80?, {0xc00015c029, 0x60, 0x1ff})
        /usr/local/go/src/crypto/tls/conn.go:1194 +0xe5
github.com/lib/pq.(*conn).sendStartupPacket(0xc0001356c0?, 0xc00007a720?)
        /root/thing/vendor/github.com/lib/pq/conn.go:965 +0x78
github.com/lib/pq.(*conn).startup(0xc00015c008, 0xc00007a720)
        /root/thing/vendor/github.com/lib/pq/conn.go:1170 +0x605
github.com/lib/pq.(*Connector).open(0xc0000120c0, {0x872120, 0xaae120})
        /root/thing/vendor/github.com/lib/pq/conn.go:378 +0x4aa
github.com/lib/pq.DialOpen({0x871578, 0xc00012ea10}, {0xc000152000?, 0x20?})
        /root/thing/vendor/github.com/lib/pq/conn.go:328 +0x77
github.com/lib/pq.Open(...)
        /root/thing/vendor/github.com/lib/pq/conn.go:318
main.(*connector).Connect(0x18?, {0xc00011c248?, 0x18?})
        /root/thing/config.go:49 +0xc5
github.com/lib/pq.(*NoticeHandlerConnector).Connect(0xc0000120a8, {0x872120?, 0xaae120?})
        /root/thing/vendor/github.com/lib/pq/notice.go:39 +0x31
database/sql.(*DB).conn(0xc00007e820, {0x872120, 0xaae120}, 0x1)
        /usr/local/go/src/database/sql/sql.go:1415 +0x71e
database/sql.(*DB).query(0xc00007e820, {0x872120, 0xaae120}, {0x7ffa82, 0x9}, {0x0, 0x0, 0x0}, 0x88?)
        /usr/local/go/src/database/sql/sql.go:1749 +0x65
database/sql.(*DB).QueryContext.func1(0x28?)
        /usr/local/go/src/database/sql/sql.go:1732 +0x4f
database/sql.(*DB).retry(0xc000135d38?, 0xc000135d58)
        /usr/local/go/src/database/sql/sql.go:1566 +0x42
database/sql.(*DB).QueryContext(0xc00007e820?, {0x872120?, 0xaae120?}, {0x7ffa82?, 0xc000135e10?}, {0x0?, 0x7ff612?, 0x8?})
        /usr/local/go/src/database/sql/sql.go:1731 +0xc5
database/sql.(*DB).Query(...)
        /usr/local/go/src/database/sql/sql.go:1745
main.main()
        /root/thing/main.go:35 +0x21c
exit status 2

It seems this if statement prevents tlsrsakex.Value() from being called a few lines later: https://github.com/golang/go/blob/dddf0ae40fa0c1223aba191d73a44425a08e1035/src/crypto/tls/common.go#L1014

But then sometime later, this line calls tlsrsakex.IncNonDefault(): https://github.com/golang/go/blob/dddf0ae40fa0c1223aba191d73a44425a08e1035/src/crypto/tls/handshake_client.go#L530

Unfortunately this comment explains that Value() must always be called before IncNonDefault(): https://github.com/golang/go/blob/dddf0ae40fa0c1223aba191d73a44425a08e1035/src/internal/godebug/godebug.go#L100

What did you expect to see?

I expected the connection to succeed for both AWS Aurora instances.

etodd commented 2 weeks ago

Forgot to mention, this is also required to reproduce the behavior:

import _ "crypto/tls/fipsonly" 

I updated the description to include this.

etodd commented 2 weeks ago

I believe this is a duplicate of #65991. Apologies for the noise!