Summary
OpenSSL 3.5.6 (released April 7, 2026) added NULL checks to OSSL_PARAM_BLD_push_octet_string (openssl/openssl@d5ad0b8). This causes a panic in TLS 1.3 handshakes when using GOEXPERIMENT=systemcrypto, because addOctetString in the vendored golang-fips/openssl/v2/params.go passes a NULL pointer for empty/nil Go slices (e.g. the empty context in TLS 1.3 ExpandLabel).
The upstream golang-fips/openssl v2 branch already has a fix for this — replacing nil slices with []byte{} before calling OSSL_PARAM_BLD_push_octet_string. However, this fix has not been picked up in the microsoft/go vendored copy yet.
Reproduction
Build any Go FIPS binary on a system with OpenSSL >= 3.5.6 (or 3.6.2):
GOEXPERIMENT=systemcrypto CGO_ENABLED=1 go run main.go
Where main.go makes any HTTPS request:
package main
import (
"log"
"net/http"
)
func main() {
resp, err := http.Get("https://www.google.com")
if err != nil {
panic(err)
}
log.Printf("Status: %d\n", resp.StatusCode)
}
Panic
panic: failed to add parameter data: OSSL_PARAM_BLD_push_octet_string
openssl error(s):
40D77BADA5710000:error:078C0102:common libcrypto routines:OSSL_PARAM_BLD_push_octet_string:passed a null parameter:crypto/param_build.c:369:
goroutine 55 [running]:
crypto/tls/internal/tls13.ExpandLabel[...](... {0x0, 0x0, 0x0}, 0x10)
/usr/lib/go/src/crypto/tls/internal/tls13/tls13.go:40 +0x3e5
crypto/tls.(*cipherSuiteTLS13).trafficKey(...)
/usr/lib/go/src/crypto/tls/key_schedule.go:29 +0x8e
...
The {0x0, 0x0, 0x0} is the nil context slice passed to ExpandLabel during TLS 1.3 key derivation. The vendored pbase() converts this to a NULL unsafe.Pointer, which OpenSSL 3.5.6 now rejects.
Root cause
In src/vendor/github.com/golang-fips/openssl/v2/params.go:
func (b *paramBuilder) addOctetString(name cString, value []byte) {
if !b.check() {
return
}
if len(value) != 0 {
b.pinner.Pin(&value[0])
}
// pbase(value) returns NULL when len(value) == 0
if _, err := ossl.OSSL_PARAM_BLD_push_octet_string(b.bld, name.ptr(), pbase(value), len(value)); err != nil {
b.err = addParamError{name.str(), err}
}
}
Fix
The upstream golang-fips/openssl v2 branch already has the fix — passing a non-nil empty slice instead of nil:
https://github.com/golang-fips/openssl/blob/v2/params.go
This needs to be synced into the vendored copy in microsoft/go.
Affected versions
- microsoft/go v1.26.2-1 (confirmed)
- microsoft/go v1.25.8-1 (same vulnerable code path)
- Any microsoft/go binary running against OpenSSL >= 3.5.6
Related
Summary
OpenSSL 3.5.6 (released April 7, 2026) added NULL checks to
OSSL_PARAM_BLD_push_octet_string(openssl/openssl@d5ad0b8). This causes a panic in TLS 1.3 handshakes when usingGOEXPERIMENT=systemcrypto, becauseaddOctetStringin the vendoredgolang-fips/openssl/v2/params.gopasses a NULL pointer for empty/nil Go slices (e.g. the empty context in TLS 1.3ExpandLabel).The upstream
golang-fips/opensslv2 branch already has a fix for this — replacing nil slices with[]byte{}before callingOSSL_PARAM_BLD_push_octet_string. However, this fix has not been picked up in the microsoft/go vendored copy yet.Reproduction
Build any Go FIPS binary on a system with OpenSSL >= 3.5.6 (or 3.6.2):
Where main.go makes any HTTPS request:
Panic
The
{0x0, 0x0, 0x0}is the nil context slice passed toExpandLabelduring TLS 1.3 key derivation. The vendoredpbase()converts this to a NULLunsafe.Pointer, which OpenSSL 3.5.6 now rejects.Root cause
In
src/vendor/github.com/golang-fips/openssl/v2/params.go:Fix
The upstream
golang-fips/opensslv2 branch already has the fix — passing a non-nil empty slice instead of nil:https://github.com/golang-fips/openssl/blob/v2/params.go
This needs to be synced into the vendored copy in microsoft/go.
Affected versions
Related