diff --git a/patches/0003-Implement-crypto-internal-backend.patch b/patches/0003-Implement-crypto-internal-backend.patch index 1034d07543..f438eb9b04 100644 --- a/patches/0003-Implement-crypto-internal-backend.patch +++ b/patches/0003-Implement-crypto-internal-backend.patch @@ -24,29 +24,29 @@ desired goexperiments and build tags. src/cmd/internal/testdir/testdir_test.go | 7 + src/cmd/link/internal/ld/main.go | 2 +- src/cmd/link/link_test.go | 8 + + src/crypto/internal/backend/backend_darwin.go | 438 ++++++++++++++++++ + src/crypto/internal/backend/backend_linux.go | 430 +++++++++++++++++ src/crypto/internal/backend/backend_test.go | 56 +++ + .../internal/backend/backend_windows.go | 438 ++++++++++++++++++ src/crypto/internal/backend/bbig/big.go | 17 + - .../internal/backend/bbig/big_windows.go | 12 + .../internal/backend/bbig/big_darwin.go | 12 + - .../internal/backend/bbig/big_linux.go | 12 + - src/crypto/internal/backend/cng_windows.go | 438 ++++++++++++++++++ + src/crypto/internal/backend/bbig/big_linux.go | 12 + + .../internal/backend/bbig/big_windows.go | 12 + src/crypto/internal/backend/common.go | 46 ++ - src/crypto/internal/backend/darwin_darwin.go | 438 ++++++++++++++++++ - .../internal/backend/fips140/cng_windows.go | 35 ++ - .../internal/backend/fips140/darwin_darwin.go | 13 + .../internal/backend/fips140/fips140.go | 70 +++ .../internal/backend/fips140/isrequirefips.go | 9 + .../internal/backend/fips140/norequirefips.go | 9 + .../backend/fips140/nosystemcrypto.go | 13 + - .../internal/backend/fips140/openssl_linux.go | 59 +++ .../fips140/requirefips_nosystemcrypto.go | 15 + .../backend/fips140/skipfipscheck_off.go | 9 + .../backend/fips140/skipfipscheck_on.go | 9 + + .../backend/fips140/systemfips_darwin.go | 13 + + .../backend/fips140/systemfips_linux.go | 59 +++ + .../backend/fips140/systemfips_windows.go | 35 ++ .../opensslsetup/opensslsetup_linux.go | 68 +++ - .../opensslsetup/opensslsetup_linux_test.go | 92 ++++ + .../opensslsetup/opensslsetup_linux_test.go | 92 ++++ .../backend/internal/opensslsetup/stub.go | 8 + src/crypto/internal/backend/nobackend.go | 376 +++++++++++++++ - src/crypto/internal/backend/openssl_linux.go | 430 +++++++++++++++++ src/crypto/internal/backend/stub.s | 10 + src/crypto/systemcrypto_nocgo_linux.go | 18 + src/go/build/deps_test.go | 24 +- @@ -54,29 +54,29 @@ desired goexperiments and build tags. src/runtime/runtime_boring.go | 5 + 43 files changed, 2742 insertions(+), 14 deletions(-) create mode 100644 src/cmd/go/systemcrypto_test.go + create mode 100644 src/crypto/internal/backend/backend_darwin.go + create mode 100644 src/crypto/internal/backend/backend_linux.go create mode 100644 src/crypto/internal/backend/backend_test.go + create mode 100644 src/crypto/internal/backend/backend_windows.go create mode 100644 src/crypto/internal/backend/bbig/big.go - create mode 100644 src/crypto/internal/backend/bbig/big_windows.go create mode 100644 src/crypto/internal/backend/bbig/big_darwin.go create mode 100644 src/crypto/internal/backend/bbig/big_linux.go - create mode 100644 src/crypto/internal/backend/cng_windows.go + create mode 100644 src/crypto/internal/backend/bbig/big_windows.go create mode 100644 src/crypto/internal/backend/common.go - create mode 100644 src/crypto/internal/backend/darwin_darwin.go - create mode 100644 src/crypto/internal/backend/fips140/cng_windows.go - create mode 100644 src/crypto/internal/backend/fips140/darwin_darwin.go create mode 100644 src/crypto/internal/backend/fips140/fips140.go create mode 100644 src/crypto/internal/backend/fips140/isrequirefips.go create mode 100644 src/crypto/internal/backend/fips140/norequirefips.go create mode 100644 src/crypto/internal/backend/fips140/nosystemcrypto.go - create mode 100644 src/crypto/internal/backend/fips140/openssl_linux.go create mode 100644 src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go create mode 100644 src/crypto/internal/backend/fips140/skipfipscheck_off.go create mode 100644 src/crypto/internal/backend/fips140/skipfipscheck_on.go + create mode 100644 src/crypto/internal/backend/fips140/systemfips_darwin.go + create mode 100644 src/crypto/internal/backend/fips140/systemfips_linux.go + create mode 100644 src/crypto/internal/backend/fips140/systemfips_windows.go create mode 100644 src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go create mode 100644 src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go create mode 100644 src/crypto/internal/backend/internal/opensslsetup/stub.go create mode 100644 src/crypto/internal/backend/nobackend.go - create mode 100644 src/crypto/internal/backend/openssl_linux.go create mode 100644 src/crypto/internal/backend/stub.s create mode 100644 src/crypto/systemcrypto_nocgo_linux.go @@ -244,7 +244,7 @@ index e4250e12de8975..feef0080cb12d6 100644 if debug { run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go -index 4396c9de190f1f..91502c9a23f724 100644 +index 78213a7a552e1e..7314eaffa3f800 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -156,10 +156,12 @@ func (t *tester) run() { @@ -734,150 +734,11 @@ index 19607c324ceaef..50439e47260a99 100644 t.Parallel() tmpdir := t.TempDir() -diff --git a/src/crypto/internal/backend/backend_test.go b/src/crypto/internal/backend/backend_test.go -new file mode 100644 -index 00000000000000..093acd82556330 ---- /dev/null -+++ b/src/crypto/internal/backend/backend_test.go -@@ -0,0 +1,56 @@ -+// Copyright 2017 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+package backend -+ -+import ( -+ "testing" -+) -+ -+// Test that Unreachable panics. -+func TestUnreachable(t *testing.T) { -+ defer func() { -+ if Enabled { -+ if err := recover(); err == nil { -+ t.Fatal("expected Unreachable to panic") -+ } -+ } else { -+ if err := recover(); err != nil { -+ t.Fatalf("expected Unreachable to be a no-op") -+ } -+ } -+ }() -+ Unreachable() -+} -+ -+// Test that UnreachableExceptTests does not panic (this is a test). -+func TestUnreachableExceptTests(t *testing.T) { -+ UnreachableExceptTests() -+} -+ -+func TestSupportsRSAPrivateKey(t *testing.T) { -+ if !Enabled { -+ t.Skip("BoringCrypto not enabled") -+ } -+ tests := []struct { -+ bitLen int -+ numPrimes int -+ supported bool -+ }{ -+ {2048, 2, true}, -+ {3072, 2, true}, -+ {4096, 2, true}, -+ {2048, 3, false}, -+ {3072, 3, false}, -+ {4096, 3, false}, -+ } -+ for _, test := range tests { -+ t.Run("", func(t *testing.T) { -+ supported := SupportsRSAPrivateKey(test.bitLen, test.numPrimes) -+ if supported != test.supported { -+ t.Errorf("SupportsRSAPrivateKey(%d, %d) = %v; want %v", test.bitLen, test.numPrimes, supported, test.supported) -+ } -+ }) -+ } -+} -diff --git a/src/crypto/internal/backend/bbig/big.go b/src/crypto/internal/backend/bbig/big.go -new file mode 100644 -index 00000000000000..20251a290dc2e0 ---- /dev/null -+++ b/src/crypto/internal/backend/bbig/big.go -@@ -0,0 +1,17 @@ -+// Copyright 2022 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+//go:build !goexperiment.systemcrypto -+ -+package bbig -+ -+import "math/big" -+ -+func Enc(b *big.Int) []uint { -+ return nil -+} -+ -+func Dec(b []uint) *big.Int { -+ return nil -+} -diff --git a/src/crypto/internal/backend/bbig/big_windows.go b/src/crypto/internal/backend/bbig/big_windows.go -new file mode 100644 -index 00000000000000..9331c34d402ba2 ---- /dev/null -+++ b/src/crypto/internal/backend/bbig/big_windows.go -@@ -0,0 +1,12 @@ -+// Copyright 2022 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+//go:build goexperiment.systemcrypto -+ -+package bbig -+ -+import "github.com/microsoft/go-crypto-winnative/cng/bbig" -+ -+var Enc = bbig.Enc -+var Dec = bbig.Dec -diff --git a/src/crypto/internal/backend/bbig/big_darwin.go b/src/crypto/internal/backend/bbig/big_darwin.go -new file mode 100644 -index 00000000000000..e8884576d05427 ---- /dev/null -+++ b/src/crypto/internal/backend/bbig/big_darwin.go -@@ -0,0 +1,12 @@ -+// Copyright 2022 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+//go:build goexperiment.systemcrypto -+ -+package bbig -+ -+import "github.com/microsoft/go-crypto-darwin/bbig" -+ -+var Enc = bbig.Enc -+var Dec = bbig.Dec -diff --git a/src/crypto/internal/backend/bbig/big_linux.go b/src/crypto/internal/backend/bbig/big_linux.go -new file mode 100644 -index 00000000000000..51396c3db1a871 ---- /dev/null -+++ b/src/crypto/internal/backend/bbig/big_linux.go -@@ -0,0 +1,12 @@ -+// Copyright 2022 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+//go:build goexperiment.systemcrypto -+ -+package bbig -+ -+import "github.com/golang-fips/openssl/v2/bbig" -+ -+var Enc = bbig.Enc -+var Dec = bbig.Dec -diff --git a/src/crypto/internal/backend/cng_windows.go b/src/crypto/internal/backend/cng_windows.go +diff --git a/src/crypto/internal/backend/backend_darwin.go b/src/crypto/internal/backend/backend_darwin.go new file mode 100644 -index 00000000000000..9bc7525be1e462 +index 00000000000000..657e27ed74dc99 --- /dev/null -+++ b/src/crypto/internal/backend/cng_windows.go ++++ b/src/crypto/internal/backend/backend_darwin.go @@ -0,0 +1,438 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style @@ -885,9 +746,9 @@ index 00000000000000..9bc7525be1e462 + +//go:build goexperiment.systemcrypto + -+// Package cng provides access to CNGCrypto implementation functions. -+// Check the variable Enabled to find out whether CNGCrypto is available. -+// If CNGCrypto is not available, the functions in this package all panic. ++// Package darwin provides access to DarwinCrypto implementation functions. ++// Check the variable Enabled to find out whether DarwinCrypto is available. ++// If DarwinCrypto is not available, the functions in this package all panic. +package backend + +import ( @@ -897,15 +758,16 @@ index 00000000000000..9bc7525be1e462 + "crypto/internal/boring/sig" + "crypto/internal/fips140only" + "hash" ++ "io" + _ "unsafe" + -+ "github.com/microsoft/go-crypto-winnative/cng" ++ "github.com/microsoft/go-crypto-darwin/xcrypto" +) + +func init() { -+ // Windows is considered FIPS compliant. ++ // Darwin is considered FIPS compliant. + if err := fips140.Check(func() bool { return true }); err != nil { -+ panic("cngcrypto: " + err.Error()) ++ panic("darwincrypto: " + err.Error()) + } + sig.BoringCrypto() + fips140only.BackendApprovedHash = FIPSApprovedHash @@ -914,143 +776,133 @@ index 00000000000000..9bc7525be1e462 +// Enabled controls whether FIPS crypto is enabled. +const Enabled = true + -+type BigInt = cng.BigInt ++type BigInt = xcrypto.BigInt + -+const RandReader = cng.RandReader ++const RandReader = xcrypto.RandReader + +func SupportsHash(h crypto.Hash) bool { -+ return cng.SupportsHash(h) ++ return xcrypto.SupportsHash(h) +} + +func FIPSApprovedHash(h hash.Hash) bool { -+ return cng.FIPSApprovedHash(h) -+} -+ -+func SupportsSHAKE(securityBits int) bool { -+ return cng.SupportsSHAKE(securityBits) ++ return xcrypto.FIPSApprovedHash(h) +} + -+func SupportsCSHAKE(securityBits int) bool { -+ return cng.SupportsSHAKE(securityBits) -+} ++func SupportsSHAKE(securityBits int) bool { return false } ++func SupportsCSHAKE(securityBits int) bool { return false } + +func SupportsCurve(curve string) bool { + switch curve { -+ case "P-224", "P-256", "P-384", "P-521", "X25519": ++ case "P-256", "P-384", "P-521", "X25519": + return true + } + return false +} + -+func SupportsRSAOAEPLabel(label []byte) bool { return true } -+func SupportsRSAPKCS1v15Encryption() bool { return true } ++func SupportsRSAOAEPLabel(label []byte) bool { ++ // CommonCrypto doesn't support labels ++ // https://github.com/microsoft/go-crypto-darwin/issues/22 ++ return len(label) == 0 ++} ++ ++func SupportsRSAPKCS1v15Encryption() bool { return true } + +func SupportsRSAPKCS1v15Signature(hash crypto.Hash) bool { -+ // 0 and MD5SHA1 are special cases that are always supported for PKCS1v15 signatures. + switch hash { -+ case 0, crypto.MD5SHA1: ++ case crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512, 0: + return true -+ default: -+ return cng.SupportsHash(hash) + } ++ return false +} + -+type Hash = cng.Hash -+type SHAKE = cng.SHAKE -+ -+func NewMD5() hash.Hash { return cng.NewMD5() } -+func NewSHA1() hash.Hash { return cng.NewSHA1() } -+func NewSHA224() hash.Hash { panic("cngcrypto: not available") } -+func NewSHA256() hash.Hash { return cng.NewSHA256() } -+func NewSHA384() hash.Hash { return cng.NewSHA384() } -+func NewSHA512() hash.Hash { return cng.NewSHA512() } -+func NewSHA512_224() hash.Hash { panic("cngcrypto: not available") } -+func NewSHA512_256() hash.Hash { panic("cngcrypto: not available") } -+func NewSHA3_224() *Hash { panic("cngcrypto: not available") } -+func NewSHA3_256() *Hash { return cng.NewSHA3_256() } -+func NewSHA3_384() *Hash { return cng.NewSHA3_384() } -+func NewSHA3_512() *Hash { return cng.NewSHA3_512() } -+ -+func NewSHAKE128() *SHAKE { return cng.NewSHAKE128() } -+func NewSHAKE256() *SHAKE { return cng.NewSHAKE256() } -+func NewCSHAKE128(N, S []byte) *SHAKE { return cng.NewCSHAKE128(N, S) } -+func NewCSHAKE256(N, S []byte) *SHAKE { return cng.NewCSHAKE256(N, S) } -+ -+func MD5(p []byte) (sum [16]byte) { return cng.MD5(p) } -+func SHA1(p []byte) (sum [20]byte) { return cng.SHA1(p) } -+func SHA224(p []byte) (sum [28]byte) { panic("cngcrypto: not available") } -+func SHA256(p []byte) (sum [32]byte) { return cng.SHA256(p) } -+func SHA384(p []byte) (sum [48]byte) { return cng.SHA384(p) } -+func SHA512(p []byte) (sum [64]byte) { return cng.SHA512(p) } -+func SHA512_224(p []byte) (sum [28]byte) { panic("cngcrypto: not available") } -+func SHA512_256(p []byte) (sum [32]byte) { panic("cngcrypto: not available") } -+func SumSHA3_224(p []byte) (sum [28]byte) { panic("cngcrypto: not available") } -+func SumSHA3_256(p []byte) (sum [32]byte) { return cng.SumSHA3_256(p) } -+func SumSHA3_384(p []byte) (sum [48]byte) { return cng.SumSHA3_384(p) } -+func SumSHA3_512(p []byte) (sum [64]byte) { return cng.SumSHA3_512(p) } -+ -+func SumSHAKE128(data []byte, length int) (sum []byte) { return cng.SumSHAKE128(data, length) } -+func SumSHAKE256(data []byte, length int) (sum []byte) { return cng.SumSHAKE256(data, length) } -+ -+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { -+ return cng.NewHMAC(h, key) -+} ++type Hash = xcrypto.Hash + -+func NewAESCipher(key []byte) (cipher.Block, error) { -+ return cng.NewAESCipher(key) ++type SHAKE struct { ++ io.Reader ++ hash.Hash +} + -+func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { -+ return cng.NewGCMTLS(c) -+} ++func (s *SHAKE) MarshalBinary() ([]byte, error) { panic("cryptobackend: not available") } ++func (s *SHAKE) AppendBinary(p []byte) ([]byte, error) { panic("cryptobackend: not available") } ++func (s *SHAKE) UnmarshalBinary(data []byte) error { panic("cryptobackend: not available") } + -+func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { -+ return cng.NewGCMTLS13(c) -+} ++func NewMD5() hash.Hash { return xcrypto.NewMD5() } ++func NewSHA1() hash.Hash { return xcrypto.NewSHA1() } ++func NewSHA224() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA256() hash.Hash { return xcrypto.NewSHA256() } ++func NewSHA384() hash.Hash { return xcrypto.NewSHA384() } ++func NewSHA512() hash.Hash { return xcrypto.NewSHA512() } ++func NewSHA512_224() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA512_256() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA3_224() *Hash { panic("cryptobackend: not available") } ++func NewSHA3_256() *Hash { return xcrypto.NewSHA3_256() } ++func NewSHA3_384() *Hash { return xcrypto.NewSHA3_384() } ++func NewSHA3_512() *Hash { return xcrypto.NewSHA3_512() } + -+type PublicKeyECDSA = cng.PublicKeyECDSA -+type PrivateKeyECDSA = cng.PrivateKeyECDSA ++func NewSHAKE128() *SHAKE { panic("cryptobackend: not available") } ++func NewSHAKE256() *SHAKE { panic("cryptobackend: not available") } ++func NewCSHAKE128(N, S []byte) *SHAKE { panic("cryptobackend: not available") } ++func NewCSHAKE256(N, S []byte) *SHAKE { panic("cryptobackend: not available") } + -+func GenerateKeyECDSA(curve string) (X, Y, D cng.BigInt, err error) { -+ return cng.GenerateKeyECDSA(curve) ++func MD5(p []byte) (sum [16]byte) { return xcrypto.MD5(p) } ++func SHA1(p []byte) (sum [20]byte) { return xcrypto.SHA1(p) } ++func SHA224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } ++func SHA256(p []byte) (sum [32]byte) { return xcrypto.SHA256(p) } ++func SHA384(p []byte) (sum [48]byte) { return xcrypto.SHA384(p) } ++func SHA512(p []byte) (sum [64]byte) { return xcrypto.SHA512(p) } ++func SHA512_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } ++func SHA512_256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } ++func SumSHA3_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } ++func SumSHA3_256(p []byte) (sum [32]byte) { return xcrypto.SumSHA3_256(p) } ++func SumSHA3_384(p []byte) (sum [48]byte) { return xcrypto.SumSHA3_384(p) } ++func SumSHA3_512(p []byte) (sum [64]byte) { return xcrypto.SumSHA3_512(p) } ++ ++func SumSHAKE128(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } ++func SumSHAKE256(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } ++ ++func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { ++ return xcrypto.NewHMAC(h, key) +} + -+func NewPrivateKeyECDSA(curve string, X, Y, D cng.BigInt) (*cng.PrivateKeyECDSA, error) { -+ return cng.NewPrivateKeyECDSA(curve, X, Y, D) ++func NewAESCipher(key []byte) (cipher.Block, error) { ++ return xcrypto.NewAESCipher(key) +} + -+func NewPublicKeyECDSA(curve string, X, Y cng.BigInt) (*cng.PublicKeyECDSA, error) { -+ return cng.NewPublicKeyECDSA(curve, X, Y) ++func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { ++ return xcrypto.NewGCMTLS(c) +} + -+//go:linkname encodeSignature crypto/ecdsa.encodeSignature -+func encodeSignature(r, s []byte) ([]byte, error) ++func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { ++ return xcrypto.NewGCMTLS13(c) ++} + -+//go:linkname parseSignature crypto/ecdsa.parseSignature -+func parseSignature(sig []byte) (r, s []byte, err error) ++type PublicKeyECDSA = xcrypto.PublicKeyECDSA ++type PrivateKeyECDSA = xcrypto.PrivateKeyECDSA + -+func SignMarshalECDSA(priv *cng.PrivateKeyECDSA, hash []byte) ([]byte, error) { -+ r, s, err := cng.SignECDSA(priv, hash) -+ if err != nil { -+ return nil, err -+ } -+ return encodeSignature(r, s) ++func GenerateKeyECDSA(curve string) (X, Y, D xcrypto.BigInt, err error) { ++ return xcrypto.GenerateKeyECDSA(curve) +} + -+func VerifyECDSA(pub *cng.PublicKeyECDSA, hash []byte, sig []byte) bool { -+ rBytes, sBytes, err := parseSignature(sig) -+ if err != nil { -+ return false -+ } -+ return cng.VerifyECDSA(pub, hash, cng.BigInt(rBytes), cng.BigInt(sBytes)) ++func NewPrivateKeyECDSA(curve string, X, Y, D xcrypto.BigInt) (*xcrypto.PrivateKeyECDSA, error) { ++ return xcrypto.NewPrivateKeyECDSA(curve, X, Y, D) +} + -+func SignECDSA(priv *cng.PrivateKeyECDSA, hash []byte) (r, s cng.BigInt, err error) { -+ return cng.SignECDSA(priv, hash) ++func NewPublicKeyECDSA(curve string, X, Y xcrypto.BigInt) (*xcrypto.PublicKeyECDSA, error) { ++ return xcrypto.NewPublicKeyECDSA(curve, X, Y) +} + -+func VerifyECDSARaw(pub *cng.PublicKeyECDSA, hash []byte, r, s cng.BigInt) bool { -+ return cng.VerifyECDSA(pub, hash, r, s) ++//go:linkname encodeSignature crypto/ecdsa.encodeSignature ++func encodeSignature(r, s []byte) ([]byte, error) ++ ++//go:linkname parseSignature crypto/ecdsa.parseSignature ++func parseSignature(sig []byte) (r, s []byte, err error) ++ ++func SignMarshalECDSA(priv *xcrypto.PrivateKeyECDSA, hash []byte) ([]byte, error) { ++ return xcrypto.SignMarshalECDSA(priv, hash) ++} ++ ++func VerifyECDSA(pub *xcrypto.PublicKeyECDSA, hash []byte, sig []byte) bool { ++ return xcrypto.VerifyECDSA(pub, hash, sig) +} + +func SupportsRSAPrivateKey(bits, primes int) bool { @@ -1058,88 +910,107 @@ index 00000000000000..9bc7525be1e462 +} + +func SupportsRSAPublicKey(bits int) bool { -+ return bits >= 512 && bits%8 == 0 && bits <= 16384 ++ return bits >= 1024 && bits%8 == 0 && bits <= 16384 +} + +func SupportsRSASaltLength(sign bool, salt int) bool { -+ if sign { -+ return true -+ } -+ return salt != 0 // rsa.PSSSaltLengthAuto ++ // CommonCrypto doesn't support custom salt length ++ return salt == -1 +} + -+type PublicKeyRSA = cng.PublicKeyRSA -+type PrivateKeyRSA = cng.PrivateKeyRSA ++type PublicKeyRSA = xcrypto.PublicKeyRSA ++type PrivateKeyRSA = xcrypto.PrivateKeyRSA + -+func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *cng.PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { -+ return cng.DecryptRSAOAEP(h, priv, ciphertext, label) ++func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *xcrypto.PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { ++ return xcrypto.DecryptRSAOAEP(h, priv, ciphertext, label) +} + -+func DecryptRSAPKCS1(priv *cng.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ return cng.DecryptRSAPKCS1(priv, ciphertext) ++func DecryptRSAPKCS1(priv *xcrypto.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ return xcrypto.DecryptRSAPKCS1(priv, ciphertext) +} + -+func DecryptRSANoPadding(priv *cng.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ return cng.DecryptRSANoPadding(priv, ciphertext) ++func DecryptRSANoPadding(priv *xcrypto.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ return xcrypto.DecryptRSANoPadding(priv, ciphertext) +} + -+func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *cng.PublicKeyRSA, msg, label []byte) ([]byte, error) { -+ return cng.EncryptRSAOAEP(h, pub, msg, label) ++func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *xcrypto.PublicKeyRSA, msg, label []byte) ([]byte, error) { ++ return xcrypto.EncryptRSAOAEP(h, pub, msg, label) +} + -+func EncryptRSAPKCS1(pub *cng.PublicKeyRSA, msg []byte) ([]byte, error) { -+ return cng.EncryptRSAPKCS1(pub, msg) ++func EncryptRSAPKCS1(pub *xcrypto.PublicKeyRSA, msg []byte) ([]byte, error) { ++ return xcrypto.EncryptRSAPKCS1(pub, msg) +} + -+func EncryptRSANoPadding(pub *cng.PublicKeyRSA, msg []byte) ([]byte, error) { -+ return cng.EncryptRSANoPadding(pub, msg) ++func EncryptRSANoPadding(pub *xcrypto.PublicKeyRSA, msg []byte) ([]byte, error) { ++ return xcrypto.EncryptRSANoPadding(pub, msg) +} + -+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv cng.BigInt, err error) { -+ return cng.GenerateKeyRSA(bits) ++//go:linkname decodeKeyRSA crypto/rsa.decodeKey ++func decodeKeyRSA(data []byte) (N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt, err error) ++ ++//go:linkname encodeKeyRSA crypto/rsa.encodeKey ++func encodeKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt) ([]byte, error) ++ ++//go:linkname encodePublicKeyRSA crypto/rsa.encodePublicKey ++func encodePublicKeyRSA(N, E xcrypto.BigInt) ([]byte, error) ++ ++func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt, err error) { ++ data, err := xcrypto.GenerateKeyRSA(bits) ++ if err != nil { ++ return ++ } ++ return decodeKeyRSA(data) +} + -+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv cng.BigInt) (*cng.PrivateKeyRSA, error) { -+ return cng.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) ++func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt) (*xcrypto.PrivateKeyRSA, error) { ++ encoded, err := encodeKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) ++ if err != nil { ++ return nil, err ++ } ++ return xcrypto.NewPrivateKeyRSA(encoded) +} + -+func NewPublicKeyRSA(N, E cng.BigInt) (*cng.PublicKeyRSA, error) { -+ return cng.NewPublicKeyRSA(N, E) ++func NewPublicKeyRSA(N, E xcrypto.BigInt) (*xcrypto.PublicKeyRSA, error) { ++ encoded, err := encodePublicKeyRSA(N, E) ++ if err != nil { ++ return nil, err ++ } ++ return xcrypto.NewPublicKeyRSA(encoded) +} + -+func SignRSAPKCS1v15(priv *cng.PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { -+ return cng.SignRSAPKCS1v15(priv, h, hashed) ++func SignRSAPKCS1v15(priv *xcrypto.PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { ++ return xcrypto.SignRSAPKCS1v15(priv, h, hashed) +} + -+func SignRSAPSS(priv *cng.PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { -+ return cng.SignRSAPSS(priv, h, hashed, saltLen) ++func SignRSAPSS(priv *xcrypto.PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { ++ return xcrypto.SignRSAPSS(priv, h, hashed, saltLen) +} + -+func VerifyRSAPKCS1v15(pub *cng.PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { -+ return cng.VerifyRSAPKCS1v15(pub, h, hashed, sig) ++func VerifyRSAPKCS1v15(pub *xcrypto.PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { ++ return xcrypto.VerifyRSAPKCS1v15(pub, h, hashed, sig) +} + -+func VerifyRSAPSS(pub *cng.PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { -+ return cng.VerifyRSAPSS(pub, h, hashed, sig, saltLen) ++func VerifyRSAPSS(pub *xcrypto.PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { ++ return xcrypto.VerifyRSAPSS(pub, h, hashed, sig, saltLen) +} + -+type PrivateKeyECDH = cng.PrivateKeyECDH -+type PublicKeyECDH = cng.PublicKeyECDH ++type PrivateKeyECDH = xcrypto.PrivateKeyECDH ++type PublicKeyECDH = xcrypto.PublicKeyECDH + -+func ECDH(priv *cng.PrivateKeyECDH, pub *cng.PublicKeyECDH) ([]byte, error) { -+ return cng.ECDH(priv, pub) ++func ECDH(priv *xcrypto.PrivateKeyECDH, pub *xcrypto.PublicKeyECDH) ([]byte, error) { ++ return xcrypto.ECDH(priv, pub) +} + -+func GenerateKeyECDH(curve string) (*cng.PrivateKeyECDH, []byte, error) { -+ return cng.GenerateKeyECDH(curve) ++func GenerateKeyECDH(curve string) (*xcrypto.PrivateKeyECDH, []byte, error) { ++ return xcrypto.GenerateKeyECDH(curve) +} + -+func NewPrivateKeyECDH(curve string, bytes []byte) (*cng.PrivateKeyECDH, error) { -+ return cng.NewPrivateKeyECDH(curve, bytes) ++func NewPrivateKeyECDH(curve string, bytes []byte) (*xcrypto.PrivateKeyECDH, error) { ++ return xcrypto.NewPrivateKeyECDH(curve, bytes) +} + -+func NewPublicKeyECDH(curve string, bytes []byte) (*cng.PublicKeyECDH, error) { -+ return cng.NewPublicKeyECDH(curve, bytes) ++func NewPublicKeyECDH(curve string, bytes []byte) (*xcrypto.PublicKeyECDH, error) { ++ return xcrypto.NewPublicKeyECDH(curve, bytes) +} + +func SupportsTLS13KDF() bool { @@ -1151,29 +1022,31 @@ index 00000000000000..9bc7525be1e462 +} + +func SupportsHKDF() bool { -+ return cng.SupportsHKDF() ++ return true +} + +func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) { -+ return cng.ExpandHKDF(h, pseudorandomKey, info, keyLength) ++ return xcrypto.ExpandHKDF(h, pseudorandomKey, info, keyLength) +} + +func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) { -+ return cng.ExtractHKDF(h, secret, salt) ++ return xcrypto.ExtractHKDF(h, secret, salt) +} + -+func SupportsPBKDF2() bool { return true } ++func SupportsPBKDF2() bool { ++ return true ++} + -+func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) ([]byte, error) { -+ return cng.PBKDF2(password, salt, iter, keyLen, h) ++func PBKDF2(pass, salt []byte, iter, keyLen int, h func() hash.Hash) ([]byte, error) { ++ return xcrypto.PBKDF2(pass, salt, iter, keyLen, h) +} + +func SupportsTLS1PRF() bool { -+ return true ++ return false +} + +func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error { -+ return cng.TLS1PRF(result, secret, label, seed, h) ++ panic("cryptobackend: not available") +} + +func SupportsDESCipher() bool { @@ -1185,1940 +1058,2067 @@ index 00000000000000..9bc7525be1e462 +} + +func NewDESCipher(key []byte) (cipher.Block, error) { -+ return cng.NewDESCipher(key) ++ return xcrypto.NewDESCipher(key) +} + +func NewTripleDESCipher(key []byte) (cipher.Block, error) { -+ return cng.NewTripleDESCipher(key) ++ return xcrypto.NewTripleDESCipher(key) +} + +func SupportsRC4() bool { return true } + -+type RC4Cipher = cng.RC4Cipher -+ -+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return cng.NewRC4Cipher(key) } -+ -+func SupportsEd25519() bool { return false } ++type RC4Cipher = xcrypto.RC4Cipher + -+type PublicKeyEd25519 struct{} ++func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return xcrypto.NewRC4Cipher(key) } + -+func (k PublicKeyEd25519) Bytes() ([]byte, error) { -+ panic("cryptobackend: not available") ++func SupportsEd25519() bool { ++ return true +} + -+type PrivateKeyEd25519 struct{} -+ -+func (k PrivateKeyEd25519) Bytes() ([]byte, error) { -+ panic("cryptobackend: not available") -+} ++type PublicKeyEd25519 = xcrypto.PublicKeyEd25519 ++type PrivateKeyEd25519 = xcrypto.PrivateKeyEd25519 + +func GenerateKeyEd25519() (PrivateKeyEd25519, error) { -+ panic("cryptobackend: not available") ++ return xcrypto.GenerateKeyEd25519(), nil +} + +func NewPrivateKeyEd25519(priv []byte) (PrivateKeyEd25519, error) { -+ panic("cryptobackend: not available") ++ return xcrypto.NewPrivateKeyEd25519(priv) +} + +func NewPublicKeyEd25519(pub []byte) (PublicKeyEd25519, error) { -+ panic("cryptobackend: not available") ++ return xcrypto.NewPublicKeyEd25519(pub) +} + +func NewPrivateKeyEd25519FromSeed(seed []byte) (PrivateKeyEd25519, error) { -+ panic("cryptobackend: not available") ++ return xcrypto.NewPrivateKeyEd25519FromSeed(seed) +} + +func SignEd25519(priv PrivateKeyEd25519, message []byte) ([]byte, error) { -+ panic("cryptobackend: not available") ++ return xcrypto.SignEd25519(priv, message) +} + +func VerifyEd25519(pub PublicKeyEd25519, message, sig []byte) error { -+ panic("cryptobackend: not available") ++ return xcrypto.VerifyEd25519(pub, message, sig) +} + -+type PrivateKeyDSA = cng.PrivateKeyDSA -+type PublicKeyDSA = cng.PublicKeyDSA -+ +func SupportsDSA(l, n int) bool { -+ // These are the only N values supported by CNG -+ return n == 160 || n == 256 ++ return false +} + -+func GenerateParametersDSA(l, n int) (p, q, g cng.BigInt, err error) { -+ params, err := cng.GenerateParametersDSA(l) -+ if err != nil { -+ return nil, nil, nil, err -+ } -+ return params.P, params.Q, params.G, nil ++func GenerateParametersDSA(l, n int) (p, q, g xcrypto.BigInt, err error) { ++ panic("cryptobackend: not available") +} + -+func GenerateKeyDSA(p, q, g cng.BigInt) (x, y cng.BigInt, err error) { -+ return cng.GenerateKeyDSA(cng.DSAParameters{P: p, Q: q, G: g}) -+} ++type PrivateKeyDSA struct{} ++type PublicKeyDSA struct{} + -+func NewPrivateKeyDSA(p, q, g, x, y cng.BigInt) (*cng.PrivateKeyDSA, error) { -+ return cng.NewPrivateKeyDSA(cng.DSAParameters{P: p, Q: q, G: g}, x, y) ++func GenerateKeyDSA(p, q, g xcrypto.BigInt) (x, y xcrypto.BigInt, err error) { ++ panic("cryptobackend: not available") +} + -+func NewPublicKeyDSA(p, q, g, y cng.BigInt) (*cng.PublicKeyDSA, error) { -+ return cng.NewPublicKeyDSA(cng.DSAParameters{P: p, Q: q, G: g}, y) ++func NewPrivateKeyDSA(p, q, g, x, y xcrypto.BigInt) (*PrivateKeyDSA, error) { ++ panic("cryptobackend: not available") +} + -+func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (cng.BigInt, cng.BigInt, error)) (r, s cng.BigInt, err error) { -+ return cng.SignDSA(priv, hash) ++func NewPublicKeyDSA(p, q, g, y xcrypto.BigInt) (*PublicKeyDSA, error) { ++ panic("cryptobackend: not available") +} + -+func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s cng.BigInt, encodeSignature func(r, s cng.BigInt) ([]byte, error)) bool { -+ return cng.VerifyDSA(pub, hashed, r, s) ++func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (xcrypto.BigInt, xcrypto.BigInt, error)) (r, s xcrypto.BigInt, err error) { ++ panic("cryptobackend: not available") ++} ++ ++func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s xcrypto.BigInt, encodeSignature func(r, s xcrypto.BigInt) ([]byte, error)) bool { ++ panic("cryptobackend: not available") +} + +func SupportsMLKEM768() bool { -+ return cng.SupportsMLKEM() ++ return xcrypto.SupportsMLKEM() +} + +func SupportsMLKEM1024() bool { -+ return cng.SupportsMLKEM() ++ return xcrypto.SupportsMLKEM() +} + -+type DecapsulationKeyMLKEM768 = cng.DecapsulationKeyMLKEM768 -+type EncapsulationKeyMLKEM768 = cng.EncapsulationKeyMLKEM768 ++type DecapsulationKeyMLKEM768 = xcrypto.DecapsulationKeyMLKEM768 ++type EncapsulationKeyMLKEM768 = xcrypto.EncapsulationKeyMLKEM768 + +func GenerateKeyMLKEM768() (DecapsulationKeyMLKEM768, error) { -+ return cng.GenerateKeyMLKEM768() ++ return xcrypto.GenerateKeyMLKEM768() +} + +func NewDecapsulationKeyMLKEM768(seed []byte) (DecapsulationKeyMLKEM768, error) { -+ return cng.NewDecapsulationKeyMLKEM768(seed) ++ return xcrypto.NewDecapsulationKeyMLKEM768(seed) +} + +func NewEncapsulationKeyMLKEM768(encapsulationKey []byte) (EncapsulationKeyMLKEM768, error) { -+ return cng.NewEncapsulationKeyMLKEM768(encapsulationKey) ++ return xcrypto.NewEncapsulationKeyMLKEM768(encapsulationKey) +} + -+type DecapsulationKeyMLKEM1024 = cng.DecapsulationKeyMLKEM1024 -+type EncapsulationKeyMLKEM1024 = cng.EncapsulationKeyMLKEM1024 ++type DecapsulationKeyMLKEM1024 = xcrypto.DecapsulationKeyMLKEM1024 ++type EncapsulationKeyMLKEM1024 = xcrypto.EncapsulationKeyMLKEM1024 + +func GenerateKeyMLKEM1024() (DecapsulationKeyMLKEM1024, error) { -+ return cng.GenerateKeyMLKEM1024() ++ return xcrypto.GenerateKeyMLKEM1024() +} + +func NewDecapsulationKeyMLKEM1024(seed []byte) (DecapsulationKeyMLKEM1024, error) { -+ return cng.NewDecapsulationKeyMLKEM1024(seed) ++ return xcrypto.NewDecapsulationKeyMLKEM1024(seed) +} + +func NewEncapsulationKeyMLKEM1024(encapsulationKey []byte) (EncapsulationKeyMLKEM1024, error) { -+ return cng.NewEncapsulationKeyMLKEM1024(encapsulationKey) ++ return xcrypto.NewEncapsulationKeyMLKEM1024(encapsulationKey) +} + +func SupportsChaCha20Poly1305() bool { -+ return cng.SupportsChaCha20Poly1305() ++ return true +} + +func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) { -+ return cng.NewChaCha20Poly1305(key) -+} -diff --git a/src/crypto/internal/backend/common.go b/src/crypto/internal/backend/common.go -new file mode 100644 -index 00000000000000..a9682181ffa154 ---- /dev/null -+++ b/src/crypto/internal/backend/common.go -@@ -0,0 +1,46 @@ -+// Copyright 2022 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+package backend -+ -+import ( -+ "crypto/internal/boring/sig" -+ "runtime" -+) -+ -+// Unreachable marks code that should be unreachable -+// when backend is in use. -+func Unreachable() { -+ if Enabled { -+ panic("cryptobackend: invalid code execution") -+ } else { -+ // Code that's unreachable is exactly the code -+ // we want to detect for reporting standard Go crypto. -+ sig.StandardCrypto() -+ } -+} -+ -+// Provided by runtime.crypto_backend_runtime_arg0 to avoid os import. -+func runtime_arg0() string -+ -+func hasSuffix(s, t string) bool { -+ return len(s) > len(t) && s[len(s)-len(t):] == t -+} -+ -+// UnreachableExceptTests marks code that should be unreachable -+// when backend is in use. It panics. -+func UnreachableExceptTests() { -+ // runtime_arg0 is not supported on windows. -+ // We are going through the same code patch on linux, -+ // so if we are unintentionally calling an 'unreachable' function, -+ // we will catch it there. -+ if Enabled && runtime.GOOS != "windows" { -+ name := runtime_arg0() -+ // If ran on Windows we'd need to allow _test.exe and .test.exe as well. -+ if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") { -+ println("cryptobackend: unexpected code execution in", name) -+ panic("cryptobackend: invalid code execution") -+ } -+ } ++ return xcrypto.NewChaCha20Poly1305(key) +} -diff --git a/src/crypto/internal/backend/darwin_darwin.go b/src/crypto/internal/backend/darwin_darwin.go +diff --git a/src/crypto/internal/backend/backend_linux.go b/src/crypto/internal/backend/backend_linux.go new file mode 100644 -index 00000000000000..805e95c926a1a1 +index 00000000000000..a4ca780ebb0251 --- /dev/null -+++ b/src/crypto/internal/backend/darwin_darwin.go -@@ -0,0 +1,438 @@ ++++ b/src/crypto/internal/backend/backend_linux.go +@@ -0,0 +1,430 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build goexperiment.systemcrypto + -+// Package darwin provides access to DarwinCrypto implementation functions. -+// Check the variable Enabled to find out whether DarwinCrypto is available. -+// If DarwinCrypto is not available, the functions in this package all panic. ++// Package openssl provides access to OpenSSLCrypto implementation functions. ++// Check the variable Enabled to find out whether OpenSSLCrypto is available. ++// If OpenSSLCrypto is not available, the functions in this package all panic. +package backend + +import ( + "crypto" + "crypto/cipher" + "crypto/internal/backend/fips140" ++ _ "crypto/internal/backend/internal/opensslsetup" + "crypto/internal/boring/sig" + "crypto/internal/fips140only" + "hash" -+ "io" -+ _ "unsafe" + -+ "github.com/microsoft/go-crypto-darwin/xcrypto" ++ "github.com/golang-fips/openssl/v2" +) + ++// Enabled controls whether FIPS crypto is enabled. ++const Enabled = true ++ ++type BigInt = openssl.BigInt ++ +func init() { -+ // Darwin is considered FIPS compliant. -+ if err := fips140.Check(func() bool { return true }); err != nil { -+ panic("darwincrypto: " + err.Error()) ++ // Some distributions, e.g. Azure Linux 3, don't set the `fips=yes` property when running in FIPS mode, ++ // but they configure OpenSSL to use a FIPS-compliant provider (in the case of Azure Linux 3, the SCOSSL provider). ++ // In this cases, openssl.FIPS would return `false` and openssl.FIPSCapable would return `true`. ++ // We don't care about the `fips=yes` property as long as the provider is FIPS-compliant, so use ++ // openssl.FIPSCapable to determine whether FIPS mode is enabled. ++ if err := fips140.Check(func() bool { return openssl.FIPSCapable() }); err != nil { ++ // This path can be reached for the following reasons: ++ // - In OpenSSL 1, the active engine doesn't support FIPS mode. ++ // - In OpenSSL 1, the active engine supports FIPS mode, but it is not enabled. ++ // - In OpenSSL 3, the provider used by default doesn't match the `fips=yes` query. ++ panic("opensslcrypto: " + err.Error() + ": " + openssl.VersionText()) + } + sig.BoringCrypto() + fips140only.BackendApprovedHash = FIPSApprovedHash +} + -+// Enabled controls whether FIPS crypto is enabled. -+const Enabled = true -+ -+type BigInt = xcrypto.BigInt -+ -+const RandReader = xcrypto.RandReader ++const RandReader = openssl.RandReader + +func SupportsHash(h crypto.Hash) bool { -+ return xcrypto.SupportsHash(h) ++ return openssl.SupportsHash(h) +} + +func FIPSApprovedHash(h hash.Hash) bool { -+ return xcrypto.FIPSApprovedHash(h) ++ return openssl.FIPSApprovedHash(h) +} + -+func SupportsSHAKE(securityBits int) bool { return false } -+func SupportsCSHAKE(securityBits int) bool { return false } ++func SupportsSHAKE(securityBits int) bool { ++ return openssl.SupportsSHAKE(securityBits) ++} + -+func SupportsCurve(curve string) bool { -+ switch curve { -+ case "P-256", "P-384", "P-521", "X25519": -+ return true -+ } -+ return false ++func SupportsCSHAKE(securityBits int) bool { ++ return openssl.SupportsCSHAKE(securityBits) +} + -+func SupportsRSAOAEPLabel(label []byte) bool { -+ // CommonCrypto doesn't support labels -+ // https://github.com/microsoft/go-crypto-darwin/issues/22 -+ return len(label) == 0 ++func SupportsCurve(curve string) bool { ++ return openssl.SupportsCurve(curve) +} + -+func SupportsRSAPKCS1v15Encryption() bool { return true } ++func SupportsRSAOAEPLabel(label []byte) bool { return true } ++ ++func SupportsRSAPKCS1v15Encryption() bool { ++ return openssl.SupportsRSAPKCS1v15Encryption() ++} + +func SupportsRSAPKCS1v15Signature(hash crypto.Hash) bool { -+ switch hash { -+ case crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512, 0: -+ return true -+ } -+ return false ++ return openssl.SupportsRSAPKCS1v15Signature(hash) +} + -+type Hash = xcrypto.Hash ++type Hash = openssl.Hash ++type SHAKE = openssl.SHAKE + -+type SHAKE struct { -+ io.Reader -+ hash.Hash -+} ++func NewMD5() hash.Hash { return openssl.NewMD5() } ++func NewSHA1() hash.Hash { return openssl.NewSHA1() } ++func NewSHA224() hash.Hash { return openssl.NewSHA224() } ++func NewSHA256() hash.Hash { return openssl.NewSHA256() } ++func NewSHA384() hash.Hash { return openssl.NewSHA384() } ++func NewSHA512() hash.Hash { return openssl.NewSHA512() } ++func NewSHA512_224() hash.Hash { return openssl.NewSHA512_224() } ++func NewSHA512_256() hash.Hash { return openssl.NewSHA512_256() } ++func NewSHA3_224() *Hash { return openssl.NewSHA3_224() } ++func NewSHA3_256() *Hash { return openssl.NewSHA3_256() } ++func NewSHA3_384() *Hash { return openssl.NewSHA3_384() } ++func NewSHA3_512() *Hash { return openssl.NewSHA3_512() } + -+func (s *SHAKE) MarshalBinary() ([]byte, error) { panic("cryptobackend: not available") } -+func (s *SHAKE) AppendBinary(p []byte) ([]byte, error) { panic("cryptobackend: not available") } -+func (s *SHAKE) UnmarshalBinary(data []byte) error { panic("cryptobackend: not available") } ++func NewSHAKE128() *SHAKE { return openssl.NewSHAKE128() } ++func NewSHAKE256() *SHAKE { return openssl.NewSHAKE256() } ++func NewCSHAKE128(N, S []byte) *SHAKE { return openssl.NewCSHAKE128(N, S) } ++func NewCSHAKE256(N, S []byte) *SHAKE { return openssl.NewCSHAKE256(N, S) } + -+func NewMD5() hash.Hash { return xcrypto.NewMD5() } -+func NewSHA1() hash.Hash { return xcrypto.NewSHA1() } -+func NewSHA224() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA256() hash.Hash { return xcrypto.NewSHA256() } -+func NewSHA384() hash.Hash { return xcrypto.NewSHA384() } -+func NewSHA512() hash.Hash { return xcrypto.NewSHA512() } -+func NewSHA512_224() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA512_256() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA3_224() *Hash { panic("cryptobackend: not available") } -+func NewSHA3_256() *Hash { return xcrypto.NewSHA3_256() } -+func NewSHA3_384() *Hash { return xcrypto.NewSHA3_384() } -+func NewSHA3_512() *Hash { return xcrypto.NewSHA3_512() } ++func MD5(p []byte) (sum [16]byte) { return openssl.MD5(p) } ++func SHA1(p []byte) (sum [20]byte) { return openssl.SHA1(p) } ++func SHA224(p []byte) (sum [28]byte) { return openssl.SHA224(p) } ++func SHA256(p []byte) (sum [32]byte) { return openssl.SHA256(p) } ++func SHA384(p []byte) (sum [48]byte) { return openssl.SHA384(p) } ++func SHA512(p []byte) (sum [64]byte) { return openssl.SHA512(p) } ++func SHA512_224(p []byte) (sum [28]byte) { return openssl.SHA512_224(p) } ++func SHA512_256(p []byte) (sum [32]byte) { return openssl.SHA512_256(p) } ++func SumSHA3_224(p []byte) (sum [28]byte) { return openssl.SumSHA3_224(p) } ++func SumSHA3_256(p []byte) (sum [32]byte) { return openssl.SumSHA3_256(p) } ++func SumSHA3_384(p []byte) (sum [48]byte) { return openssl.SumSHA3_384(p) } ++func SumSHA3_512(p []byte) (sum [64]byte) { return openssl.SumSHA3_512(p) } + -+func NewSHAKE128() *SHAKE { panic("cryptobackend: not available") } -+func NewSHAKE256() *SHAKE { panic("cryptobackend: not available") } -+func NewCSHAKE128(N, S []byte) *SHAKE { panic("cryptobackend: not available") } -+func NewCSHAKE256(N, S []byte) *SHAKE { panic("cryptobackend: not available") } ++func SumSHAKE128(data []byte, length int) (sum []byte) { return openssl.SumSHAKE128(data, length) } ++func SumSHAKE256(data []byte, length int) (sum []byte) { return openssl.SumSHAKE256(data, length) } + -+func MD5(p []byte) (sum [16]byte) { return xcrypto.MD5(p) } -+func SHA1(p []byte) (sum [20]byte) { return xcrypto.SHA1(p) } -+func SHA224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } -+func SHA256(p []byte) (sum [32]byte) { return xcrypto.SHA256(p) } -+func SHA384(p []byte) (sum [48]byte) { return xcrypto.SHA384(p) } -+func SHA512(p []byte) (sum [64]byte) { return xcrypto.SHA512(p) } -+func SHA512_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } -+func SHA512_256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } -+func SumSHA3_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } -+func SumSHA3_256(p []byte) (sum [32]byte) { return xcrypto.SumSHA3_256(p) } -+func SumSHA3_384(p []byte) (sum [48]byte) { return xcrypto.SumSHA3_384(p) } -+func SumSHA3_512(p []byte) (sum [64]byte) { return xcrypto.SumSHA3_512(p) } ++func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { return openssl.NewHMAC(h, key) } + -+func SumSHAKE128(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } -+func SumSHAKE256(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } ++func NewAESCipher(key []byte) (cipher.Block, error) { return openssl.NewAESCipher(key) } ++func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { return openssl.NewGCMTLS(c) } ++func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { return openssl.NewGCMTLS13(c) } + -+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { -+ return xcrypto.NewHMAC(h, key) ++type PublicKeyECDSA = openssl.PublicKeyECDSA ++type PrivateKeyECDSA = openssl.PrivateKeyECDSA ++ ++func GenerateKeyECDSA(curve string) (X, Y, D openssl.BigInt, err error) { ++ return openssl.GenerateKeyECDSA(curve) +} + -+func NewAESCipher(key []byte) (cipher.Block, error) { -+ return xcrypto.NewAESCipher(key) ++func NewPrivateKeyECDSA(curve string, X, Y, D openssl.BigInt) (*openssl.PrivateKeyECDSA, error) { ++ return openssl.NewPrivateKeyECDSA(curve, X, Y, D) +} + -+func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { -+ return xcrypto.NewGCMTLS(c) -+} -+ -+func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { -+ return xcrypto.NewGCMTLS13(c) -+} -+ -+type PublicKeyECDSA = xcrypto.PublicKeyECDSA -+type PrivateKeyECDSA = xcrypto.PrivateKeyECDSA -+ -+func GenerateKeyECDSA(curve string) (X, Y, D xcrypto.BigInt, err error) { -+ return xcrypto.GenerateKeyECDSA(curve) -+} -+ -+func NewPrivateKeyECDSA(curve string, X, Y, D xcrypto.BigInt) (*xcrypto.PrivateKeyECDSA, error) { -+ return xcrypto.NewPrivateKeyECDSA(curve, X, Y, D) -+} -+ -+func NewPublicKeyECDSA(curve string, X, Y xcrypto.BigInt) (*xcrypto.PublicKeyECDSA, error) { -+ return xcrypto.NewPublicKeyECDSA(curve, X, Y) ++func NewPublicKeyECDSA(curve string, X, Y openssl.BigInt) (*openssl.PublicKeyECDSA, error) { ++ return openssl.NewPublicKeyECDSA(curve, X, Y) +} + -+//go:linkname encodeSignature crypto/ecdsa.encodeSignature -+func encodeSignature(r, s []byte) ([]byte, error) -+ -+//go:linkname parseSignature crypto/ecdsa.parseSignature -+func parseSignature(sig []byte) (r, s []byte, err error) -+ -+func SignMarshalECDSA(priv *xcrypto.PrivateKeyECDSA, hash []byte) ([]byte, error) { -+ return xcrypto.SignMarshalECDSA(priv, hash) ++func SignMarshalECDSA(priv *openssl.PrivateKeyECDSA, hash []byte) ([]byte, error) { ++ return openssl.SignMarshalECDSA(priv, hash) +} + -+func VerifyECDSA(pub *xcrypto.PublicKeyECDSA, hash []byte, sig []byte) bool { -+ return xcrypto.VerifyECDSA(pub, hash, sig) ++func VerifyECDSA(pub *openssl.PublicKeyECDSA, hash []byte, sig []byte) bool { ++ return openssl.VerifyECDSA(pub, hash, sig) +} + +func SupportsRSAPrivateKey(bits, primes int) bool { ++ // The built-in OpenSSL 3 providers and OpenSSL 1 do support n-prime RSA keys, ++ // but SCOSSL only supports 2-prime RSA keys. ++ // Only 2-prime RSA keys are FIPS compliant, other n having compatibility ++ // and security issues. Even crypto/rsa deprecated rsa.GenerateMultiPrimeKey as of Go 1.21. ++ // Given the above reasons, we only support what SCOSSL supports. + return primes == 2 && SupportsRSAPublicKey(bits) +} + +func SupportsRSAPublicKey(bits int) bool { -+ return bits >= 1024 && bits%8 == 0 && bits <= 16384 ++ min := 1024 ++ if fips140.Enabled() { ++ // The built-in OpenSSL 3 FIPS provider requires at least 2048 bits for FIPS compliance. ++ min = 2048 ++ } ++ return bits >= min && bits%8 == 0 && bits <= 16384 +} + +func SupportsRSASaltLength(sign bool, salt int) bool { -+ // CommonCrypto doesn't support custom salt length -+ return salt == -1 ++ return true +} + -+type PublicKeyRSA = xcrypto.PublicKeyRSA -+type PrivateKeyRSA = xcrypto.PrivateKeyRSA ++type PublicKeyRSA = openssl.PublicKeyRSA ++type PrivateKeyRSA = openssl.PrivateKeyRSA + -+func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *xcrypto.PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { -+ return xcrypto.DecryptRSAOAEP(h, priv, ciphertext, label) ++func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *openssl.PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { ++ return openssl.DecryptRSAOAEP(h, mgfHash, priv, ciphertext, label) +} + -+func DecryptRSAPKCS1(priv *xcrypto.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ return xcrypto.DecryptRSAPKCS1(priv, ciphertext) ++func DecryptRSAPKCS1(priv *openssl.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ return openssl.DecryptRSAPKCS1(priv, ciphertext) +} + -+func DecryptRSANoPadding(priv *xcrypto.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ return xcrypto.DecryptRSANoPadding(priv, ciphertext) ++func DecryptRSANoPadding(priv *openssl.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ return openssl.DecryptRSANoPadding(priv, ciphertext) +} + -+func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *xcrypto.PublicKeyRSA, msg, label []byte) ([]byte, error) { -+ return xcrypto.EncryptRSAOAEP(h, pub, msg, label) ++func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *openssl.PublicKeyRSA, msg, label []byte) ([]byte, error) { ++ return openssl.EncryptRSAOAEP(h, mgfHash, pub, msg, label) +} + -+func EncryptRSAPKCS1(pub *xcrypto.PublicKeyRSA, msg []byte) ([]byte, error) { -+ return xcrypto.EncryptRSAPKCS1(pub, msg) ++func EncryptRSAPKCS1(pub *openssl.PublicKeyRSA, msg []byte) ([]byte, error) { ++ return openssl.EncryptRSAPKCS1(pub, msg) +} + -+func EncryptRSANoPadding(pub *xcrypto.PublicKeyRSA, msg []byte) ([]byte, error) { -+ return xcrypto.EncryptRSANoPadding(pub, msg) ++func EncryptRSANoPadding(pub *openssl.PublicKeyRSA, msg []byte) ([]byte, error) { ++ return openssl.EncryptRSANoPadding(pub, msg) +} + -+//go:linkname decodeKeyRSA crypto/rsa.decodeKey -+func decodeKeyRSA(data []byte) (N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt, err error) -+ -+//go:linkname encodeKeyRSA crypto/rsa.encodeKey -+func encodeKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt) ([]byte, error) -+ -+//go:linkname encodePublicKeyRSA crypto/rsa.encodePublicKey -+func encodePublicKeyRSA(N, E xcrypto.BigInt) ([]byte, error) -+ -+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt, err error) { -+ data, err := xcrypto.GenerateKeyRSA(bits) -+ if err != nil { -+ return -+ } -+ return decodeKeyRSA(data) ++func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv openssl.BigInt, err error) { ++ return openssl.GenerateKeyRSA(bits) +} + -+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv xcrypto.BigInt) (*xcrypto.PrivateKeyRSA, error) { -+ encoded, err := encodeKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) -+ if err != nil { -+ return nil, err -+ } -+ return xcrypto.NewPrivateKeyRSA(encoded) ++func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv openssl.BigInt) (*openssl.PrivateKeyRSA, error) { ++ return openssl.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) +} + -+func NewPublicKeyRSA(N, E xcrypto.BigInt) (*xcrypto.PublicKeyRSA, error) { -+ encoded, err := encodePublicKeyRSA(N, E) -+ if err != nil { -+ return nil, err -+ } -+ return xcrypto.NewPublicKeyRSA(encoded) ++func NewPublicKeyRSA(N, E openssl.BigInt) (*openssl.PublicKeyRSA, error) { ++ return openssl.NewPublicKeyRSA(N, E) +} + -+func SignRSAPKCS1v15(priv *xcrypto.PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { -+ return xcrypto.SignRSAPKCS1v15(priv, h, hashed) ++func SignRSAPKCS1v15(priv *openssl.PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { ++ return openssl.SignRSAPKCS1v15(priv, h, hashed) +} + -+func SignRSAPSS(priv *xcrypto.PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { -+ return xcrypto.SignRSAPSS(priv, h, hashed, saltLen) ++func SignRSAPSS(priv *openssl.PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { ++ return openssl.SignRSAPSS(priv, h, hashed, saltLen) +} + -+func VerifyRSAPKCS1v15(pub *xcrypto.PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { -+ return xcrypto.VerifyRSAPKCS1v15(pub, h, hashed, sig) ++func VerifyRSAPKCS1v15(pub *openssl.PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { ++ return openssl.VerifyRSAPKCS1v15(pub, h, hashed, sig) +} + -+func VerifyRSAPSS(pub *xcrypto.PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { -+ return xcrypto.VerifyRSAPSS(pub, h, hashed, sig, saltLen) ++func VerifyRSAPSS(pub *openssl.PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { ++ return openssl.VerifyRSAPSS(pub, h, hashed, sig, saltLen) +} + -+type PrivateKeyECDH = xcrypto.PrivateKeyECDH -+type PublicKeyECDH = xcrypto.PublicKeyECDH ++type PublicKeyECDH = openssl.PublicKeyECDH ++type PrivateKeyECDH = openssl.PrivateKeyECDH + -+func ECDH(priv *xcrypto.PrivateKeyECDH, pub *xcrypto.PublicKeyECDH) ([]byte, error) { -+ return xcrypto.ECDH(priv, pub) ++func ECDH(priv *openssl.PrivateKeyECDH, pub *openssl.PublicKeyECDH) ([]byte, error) { ++ return openssl.ECDH(priv, pub) +} + -+func GenerateKeyECDH(curve string) (*xcrypto.PrivateKeyECDH, []byte, error) { -+ return xcrypto.GenerateKeyECDH(curve) ++func GenerateKeyECDH(curve string) (*openssl.PrivateKeyECDH, []byte, error) { ++ return openssl.GenerateKeyECDH(curve) +} + -+func NewPrivateKeyECDH(curve string, bytes []byte) (*xcrypto.PrivateKeyECDH, error) { -+ return xcrypto.NewPrivateKeyECDH(curve, bytes) ++func NewPrivateKeyECDH(curve string, bytes []byte) (*openssl.PrivateKeyECDH, error) { ++ return openssl.NewPrivateKeyECDH(curve, bytes) +} + -+func NewPublicKeyECDH(curve string, bytes []byte) (*xcrypto.PublicKeyECDH, error) { -+ return xcrypto.NewPublicKeyECDH(curve, bytes) ++func NewPublicKeyECDH(curve string, bytes []byte) (*openssl.PublicKeyECDH, error) { ++ return openssl.NewPublicKeyECDH(curve, bytes) +} + +func SupportsTLS13KDF() bool { -+ return false ++ return openssl.SupportsTLS13KDF() +} + +func ExpandTLS13KDF(h func() hash.Hash, pseudorandomKey, label, context []byte, keyLength int) ([]byte, error) { -+ panic("cryptobackend: not available") ++ return openssl.ExpandTLS13KDF(h, pseudorandomKey, label, context, keyLength) +} + +func SupportsHKDF() bool { -+ return true ++ return openssl.SupportsHKDF() +} + +func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) { -+ return xcrypto.ExpandHKDF(h, pseudorandomKey, info, keyLength) ++ return openssl.ExpandHKDFOneShot(h, pseudorandomKey, info, keyLength) +} + +func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) { -+ return xcrypto.ExtractHKDF(h, secret, salt) ++ return openssl.ExtractHKDF(h, secret, salt) +} + +func SupportsPBKDF2() bool { -+ return true ++ return openssl.SupportsPBKDF2() +} + +func PBKDF2(pass, salt []byte, iter, keyLen int, h func() hash.Hash) ([]byte, error) { -+ return xcrypto.PBKDF2(pass, salt, iter, keyLen, h) ++ return openssl.PBKDF2(pass, salt, iter, keyLen, h) +} + +func SupportsTLS1PRF() bool { -+ return false ++ return openssl.SupportsTLS1PRF() +} + +func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error { -+ panic("cryptobackend: not available") ++ return openssl.TLS1PRF(result, secret, label, seed, h) +} + +func SupportsDESCipher() bool { -+ return true ++ return openssl.SupportsDESCipher() +} + +func SupportsTripleDESCipher() bool { -+ return true ++ return openssl.SupportsTripleDESCipher() +} + +func NewDESCipher(key []byte) (cipher.Block, error) { -+ return xcrypto.NewDESCipher(key) ++ return openssl.NewDESCipher(key) +} + +func NewTripleDESCipher(key []byte) (cipher.Block, error) { -+ return xcrypto.NewTripleDESCipher(key) ++ return openssl.NewTripleDESCipher(key) +} + -+func SupportsRC4() bool { return true } ++func SupportsRC4() bool { ++ return openssl.SupportsRC4() ++} + -+type RC4Cipher = xcrypto.RC4Cipher ++type RC4Cipher = openssl.RC4Cipher + -+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return xcrypto.NewRC4Cipher(key) } ++func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return openssl.NewRC4Cipher(key) } + -+func SupportsEd25519() bool { -+ return true -+} ++func SupportsEd25519() bool { return openssl.SupportsEd25519() } + -+type PublicKeyEd25519 = xcrypto.PublicKeyEd25519 -+type PrivateKeyEd25519 = xcrypto.PrivateKeyEd25519 ++type PublicKeyEd25519 = *openssl.PublicKeyEd25519 ++type PrivateKeyEd25519 = *openssl.PrivateKeyEd25519 + +func GenerateKeyEd25519() (PrivateKeyEd25519, error) { -+ return xcrypto.GenerateKeyEd25519(), nil ++ return openssl.GenerateKeyEd25519() ++} ++ ++// Deprecated: use NewPrivateKeyEd25519 instead. ++func NewPrivateKeyEd25119(priv []byte) (PrivateKeyEd25519, error) { ++ return openssl.NewPrivateKeyEd25519(priv) ++} ++ ++// Deprecated: use NewPublicKeyEd25519 instead. ++func NewPublicKeyEd25119(pub []byte) (PublicKeyEd25519, error) { ++ return openssl.NewPublicKeyEd25519(pub) +} + +func NewPrivateKeyEd25519(priv []byte) (PrivateKeyEd25519, error) { -+ return xcrypto.NewPrivateKeyEd25519(priv) ++ return openssl.NewPrivateKeyEd25519(priv) +} + +func NewPublicKeyEd25519(pub []byte) (PublicKeyEd25519, error) { -+ return xcrypto.NewPublicKeyEd25519(pub) ++ return openssl.NewPublicKeyEd25519(pub) +} + +func NewPrivateKeyEd25519FromSeed(seed []byte) (PrivateKeyEd25519, error) { -+ return xcrypto.NewPrivateKeyEd25519FromSeed(seed) ++ return openssl.NewPrivateKeyEd25519FromSeed(seed) +} + +func SignEd25519(priv PrivateKeyEd25519, message []byte) ([]byte, error) { -+ return xcrypto.SignEd25519(priv, message) ++ return openssl.SignEd25519(priv, message) +} + +func VerifyEd25519(pub PublicKeyEd25519, message, sig []byte) error { -+ return xcrypto.VerifyEd25519(pub, message, sig) ++ return openssl.VerifyEd25519(pub, message, sig) +} + ++type PublicKeyDSA = openssl.PublicKeyDSA ++type PrivateKeyDSA = openssl.PrivateKeyDSA ++ +func SupportsDSA(l, n int) bool { -+ return false ++ return openssl.SupportsDSA() +} + -+func GenerateParametersDSA(l, n int) (p, q, g xcrypto.BigInt, err error) { -+ panic("cryptobackend: not available") ++func GenerateParametersDSA(l, n int) (p, q, g openssl.BigInt, err error) { ++ params, err := openssl.GenerateParametersDSA(l, n) ++ return params.P, params.Q, params.G, err +} + -+type PrivateKeyDSA struct{} -+type PublicKeyDSA struct{} -+ -+func GenerateKeyDSA(p, q, g xcrypto.BigInt) (x, y xcrypto.BigInt, err error) { -+ panic("cryptobackend: not available") ++func GenerateKeyDSA(p, q, g openssl.BigInt) (x, y openssl.BigInt, err error) { ++ return openssl.GenerateKeyDSA(openssl.DSAParameters{P: p, Q: q, G: g}) +} + -+func NewPrivateKeyDSA(p, q, g, x, y xcrypto.BigInt) (*PrivateKeyDSA, error) { -+ panic("cryptobackend: not available") ++func NewPrivateKeyDSA(p, q, g, x, y openssl.BigInt) (*openssl.PrivateKeyDSA, error) { ++ return openssl.NewPrivateKeyDSA(openssl.DSAParameters{P: p, Q: q, G: g}, x, y) +} + -+func NewPublicKeyDSA(p, q, g, y xcrypto.BigInt) (*PublicKeyDSA, error) { -+ panic("cryptobackend: not available") ++func NewPublicKeyDSA(p, q, g, y openssl.BigInt) (*openssl.PublicKeyDSA, error) { ++ return openssl.NewPublicKeyDSA(openssl.DSAParameters{P: p, Q: q, G: g}, y) +} + -+func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (xcrypto.BigInt, xcrypto.BigInt, error)) (r, s xcrypto.BigInt, err error) { -+ panic("cryptobackend: not available") -+} ++func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (openssl.BigInt, openssl.BigInt, error)) (r, s openssl.BigInt, err error) { ++ sig, err := openssl.SignDSA(priv, hash) ++ if err != nil { ++ return nil, nil, err ++ } + -+func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s xcrypto.BigInt, encodeSignature func(r, s xcrypto.BigInt) ([]byte, error)) bool { -+ panic("cryptobackend: not available") -+} ++ r, s, err = parseSignature(sig) ++ if err != nil { ++ return nil, nil, err ++ } + -+func SupportsMLKEM768() bool { -+ return xcrypto.SupportsMLKEM() ++ return openssl.BigInt(r), openssl.BigInt(s), nil +} + -+func SupportsMLKEM1024() bool { -+ return xcrypto.SupportsMLKEM() ++func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s openssl.BigInt, encodeSignature func(r, s openssl.BigInt) ([]byte, error)) bool { ++ sig, err := encodeSignature(r, s) ++ if err != nil { ++ return false ++ } ++ ++ return openssl.VerifyDSA(pub, hashed, sig) +} + -+type DecapsulationKeyMLKEM768 = xcrypto.DecapsulationKeyMLKEM768 -+type EncapsulationKeyMLKEM768 = xcrypto.EncapsulationKeyMLKEM768 ++func SupportsMLKEM768() bool { ++ return openssl.SupportsMLKEM768() ++} ++ ++func SupportsMLKEM1024() bool { ++ return openssl.SupportsMLKEM1024() ++} ++ ++type DecapsulationKeyMLKEM768 = openssl.DecapsulationKeyMLKEM768 ++type EncapsulationKeyMLKEM768 = openssl.EncapsulationKeyMLKEM768 + +func GenerateKeyMLKEM768() (DecapsulationKeyMLKEM768, error) { -+ return xcrypto.GenerateKeyMLKEM768() ++ return openssl.GenerateKeyMLKEM768() +} + +func NewDecapsulationKeyMLKEM768(seed []byte) (DecapsulationKeyMLKEM768, error) { -+ return xcrypto.NewDecapsulationKeyMLKEM768(seed) ++ return openssl.NewDecapsulationKeyMLKEM768(seed) +} + +func NewEncapsulationKeyMLKEM768(encapsulationKey []byte) (EncapsulationKeyMLKEM768, error) { -+ return xcrypto.NewEncapsulationKeyMLKEM768(encapsulationKey) ++ return openssl.NewEncapsulationKeyMLKEM768(encapsulationKey) +} + -+type DecapsulationKeyMLKEM1024 = xcrypto.DecapsulationKeyMLKEM1024 -+type EncapsulationKeyMLKEM1024 = xcrypto.EncapsulationKeyMLKEM1024 ++type DecapsulationKeyMLKEM1024 = openssl.DecapsulationKeyMLKEM1024 ++type EncapsulationKeyMLKEM1024 = openssl.EncapsulationKeyMLKEM1024 + +func GenerateKeyMLKEM1024() (DecapsulationKeyMLKEM1024, error) { -+ return xcrypto.GenerateKeyMLKEM1024() ++ return openssl.GenerateKeyMLKEM1024() +} + +func NewDecapsulationKeyMLKEM1024(seed []byte) (DecapsulationKeyMLKEM1024, error) { -+ return xcrypto.NewDecapsulationKeyMLKEM1024(seed) ++ return openssl.NewDecapsulationKeyMLKEM1024(seed) +} + +func NewEncapsulationKeyMLKEM1024(encapsulationKey []byte) (EncapsulationKeyMLKEM1024, error) { -+ return xcrypto.NewEncapsulationKeyMLKEM1024(encapsulationKey) ++ return openssl.NewEncapsulationKeyMLKEM1024(encapsulationKey) +} + +func SupportsChaCha20Poly1305() bool { -+ return true ++ return openssl.SupportsChaCha20Poly1305() +} + +func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) { -+ return xcrypto.NewChaCha20Poly1305(key) ++ return openssl.NewChaCha20Poly1305(key) +} -diff --git a/src/crypto/internal/backend/fips140/cng_windows.go b/src/crypto/internal/backend/fips140/cng_windows.go +diff --git a/src/crypto/internal/backend/backend_test.go b/src/crypto/internal/backend/backend_test.go new file mode 100644 -index 00000000000000..d74cffe462b234 +index 00000000000000..093acd82556330 --- /dev/null -+++ b/src/crypto/internal/backend/fips140/cng_windows.go -@@ -0,0 +1,35 @@ -+// Copyright 2024 The Go Authors. All rights reserved. ++++ b/src/crypto/internal/backend/backend_test.go +@@ -0,0 +1,56 @@ ++// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + -+//go:build goexperiment.systemcrypto -+ -+package fips140 ++package backend + +import ( -+ "internal/syscall/windows/sysdll" -+ "syscall" -+ "unsafe" ++ "testing" +) + -+const backendEnabled = true -+ -+// Don't use github.com/microsoft/go-crypto-winnative here. -+// The fips140 package should have minimal dependencies. -+// Also, don't directly query the system FIPS mode from the registry, -+// there are some no-longer documented legacy entries that can enable FIPS mode, -+// and BCryptGetFipsAlgorithmMode supports them all. -+var ( -+ bcrypt = syscall.MustLoadDLL(sysdll.Add("bcrypt.dll")) ++// Test that Unreachable panics. ++func TestUnreachable(t *testing.T) { ++ defer func() { ++ if Enabled { ++ if err := recover(); err == nil { ++ t.Fatal("expected Unreachable to panic") ++ } ++ } else { ++ if err := recover(); err != nil { ++ t.Fatalf("expected Unreachable to be a no-op") ++ } ++ } ++ }() ++ Unreachable() ++} + -+ bcryptGetFipsAlgorithmMode = bcrypt.MustFindProc("BCryptGetFipsAlgorithmMode") -+) ++// Test that UnreachableExceptTests does not panic (this is a test). ++func TestUnreachableExceptTests(t *testing.T) { ++ UnreachableExceptTests() ++} + -+func systemFIPSMode() bool { -+ var enabled uint32 -+ ret, _, _ := bcryptGetFipsAlgorithmMode.Call(uintptr(unsafe.Pointer(&enabled))) -+ if ret != 0 { -+ return false ++func TestSupportsRSAPrivateKey(t *testing.T) { ++ if !Enabled { ++ t.Skip("BoringCrypto not enabled") ++ } ++ tests := []struct { ++ bitLen int ++ numPrimes int ++ supported bool ++ }{ ++ {2048, 2, true}, ++ {3072, 2, true}, ++ {4096, 2, true}, ++ {2048, 3, false}, ++ {3072, 3, false}, ++ {4096, 3, false}, ++ } ++ for _, test := range tests { ++ t.Run("", func(t *testing.T) { ++ supported := SupportsRSAPrivateKey(test.bitLen, test.numPrimes) ++ if supported != test.supported { ++ t.Errorf("SupportsRSAPrivateKey(%d, %d) = %v; want %v", test.bitLen, test.numPrimes, supported, test.supported) ++ } ++ }) + } -+ return enabled != 0 +} -diff --git a/src/crypto/internal/backend/fips140/darwin_darwin.go b/src/crypto/internal/backend/fips140/darwin_darwin.go +diff --git a/src/crypto/internal/backend/backend_windows.go b/src/crypto/internal/backend/backend_windows.go new file mode 100644 -index 00000000000000..be7c416b531e58 +index 00000000000000..26f0e5d79f0588 --- /dev/null -+++ b/src/crypto/internal/backend/fips140/darwin_darwin.go -@@ -0,0 +1,13 @@ -+// Copyright 2024 The Go Authors. All rights reserved. ++++ b/src/crypto/internal/backend/backend_windows.go +@@ -0,0 +1,438 @@ ++// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build goexperiment.systemcrypto + -+package fips140 ++// Package cng provides access to CNGCrypto implementation functions. ++// Check the variable Enabled to find out whether CNGCrypto is available. ++// If CNGCrypto is not available, the functions in this package all panic. ++package backend + -+const backendEnabled = true ++import ( ++ "crypto" ++ "crypto/cipher" ++ "crypto/internal/backend/fips140" ++ "crypto/internal/boring/sig" ++ "crypto/internal/fips140only" ++ "hash" ++ _ "unsafe" + -+func systemFIPSMode() bool { -+ return false ++ "github.com/microsoft/go-crypto-winnative/cng" ++) ++ ++func init() { ++ // Windows is considered FIPS compliant. ++ if err := fips140.Check(func() bool { return true }); err != nil { ++ panic("cngcrypto: " + err.Error()) ++ } ++ sig.BoringCrypto() ++ fips140only.BackendApprovedHash = FIPSApprovedHash +} -diff --git a/src/crypto/internal/backend/fips140/fips140.go b/src/crypto/internal/backend/fips140/fips140.go -new file mode 100644 -index 00000000000000..1bf7c3b7d63da8 ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/fips140.go -@@ -0,0 +1,70 @@ -+// Copyright 2024 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. + -+package fips140 ++// Enabled controls whether FIPS crypto is enabled. ++const Enabled = true + -+import ( -+ "errors" -+ "internal/godebug" -+ "runtime" -+ "syscall" -+) ++type BigInt = cng.BigInt + -+var fips140GODEBUG = godebug.New("fips140") ++const RandReader = cng.RandReader + -+// Enabled reports whether FIPS 140 mode is enabled by using GODEBUG, GOFIPS, GOLANG_FIPS, -+// the 'requirefips' build tag, or any other platform-specific mechanism. -+func Enabled() bool { -+ return enabled ++func SupportsHash(h crypto.Hash) bool { ++ return cng.SupportsHash(h) +} + -+var enabled bool ++func FIPSApprovedHash(h hash.Hash) bool { ++ return cng.FIPSApprovedHash(h) ++} + -+// message is a human-readable message about how [Enabled] was set. -+var message string ++func SupportsSHAKE(securityBits int) bool { ++ return cng.SupportsSHAKE(securityBits) ++} + -+func init() { -+ // TODO: Decide which environment variable to use. -+ // See https://github.com/microsoft/go/issues/397. -+ var ok bool -+ value := fips140GODEBUG.Value() -+ if value == "on" || value == "only" || value == "debug" { -+ message = "environment variable GODEBUG=fips140=" + value -+ value = "1" -+ } else if value, ok = syscall.Getenv("GOFIPS"); ok { -+ message = "environment variable GOFIPS" -+ } else if value, ok = syscall.Getenv("GOLANG_FIPS"); ok { -+ message = "environment variable GOLANG_FIPS" -+ } else if systemFIPSMode() { -+ message = "system FIPS mode" -+ value = "1" -+ } -+ enabled = value == "1" -+ if isRequireFIPS { -+ if isSkipFIPSCheck { -+ panic("the 'requirefips' build tag is enabled, but it conflicts " + -+ "with the 'ms_skipfipscheck' build tag") -+ } -+ message = "requirefips tag set" -+ enabled = true -+ } ++func SupportsCSHAKE(securityBits int) bool { ++ return cng.SupportsSHAKE(securityBits) +} + -+// Check checks whether fips mode, as returned by fips(), -+// is valid given the current settings. -+func Check(fips func() bool) error { -+ if isSkipFIPSCheck || !enabled { -+ return nil -+ } -+ if !backendEnabled { -+ if runtime.GOOS != "linux" && runtime.GOOS != "windows" && runtime.GOOS != "darwin" { -+ return errors.New("FIPS mode requested (" + message + ") but no crypto backend is supported on " + runtime.GOOS) -+ } -+ return errors.New("FIPS mode requested (" + message + ") but no supported crypto backend is enabled") -+ } -+ if !fips() { -+ return errors.New("FIPS mode requested (" + message + ") but not available") ++func SupportsCurve(curve string) bool { ++ switch curve { ++ case "P-224", "P-256", "P-384", "P-521", "X25519": ++ return true + } -+ return nil ++ return false +} -diff --git a/src/crypto/internal/backend/fips140/isrequirefips.go b/src/crypto/internal/backend/fips140/isrequirefips.go -new file mode 100644 -index 00000000000000..b33d08c84e2dae ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/isrequirefips.go -@@ -0,0 +1,9 @@ -+// Copyright 2024 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. + -+//go:build requirefips ++func SupportsRSAOAEPLabel(label []byte) bool { return true } ++func SupportsRSAPKCS1v15Encryption() bool { return true } + -+package fips140 ++func SupportsRSAPKCS1v15Signature(hash crypto.Hash) bool { ++ // 0 and MD5SHA1 are special cases that are always supported for PKCS1v15 signatures. ++ switch hash { ++ case 0, crypto.MD5SHA1: ++ return true ++ default: ++ return cng.SupportsHash(hash) ++ } ++} + -+const isRequireFIPS = true -\ No newline at end of file -diff --git a/src/crypto/internal/backend/fips140/norequirefips.go b/src/crypto/internal/backend/fips140/norequirefips.go -new file mode 100644 -index 00000000000000..6f01b9a3524dee ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/norequirefips.go -@@ -0,0 +1,9 @@ -+// Copyright 2024 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. ++type Hash = cng.Hash ++type SHAKE = cng.SHAKE + -+//go:build !requirefips ++func NewMD5() hash.Hash { return cng.NewMD5() } ++func NewSHA1() hash.Hash { return cng.NewSHA1() } ++func NewSHA224() hash.Hash { panic("cngcrypto: not available") } ++func NewSHA256() hash.Hash { return cng.NewSHA256() } ++func NewSHA384() hash.Hash { return cng.NewSHA384() } ++func NewSHA512() hash.Hash { return cng.NewSHA512() } ++func NewSHA512_224() hash.Hash { panic("cngcrypto: not available") } ++func NewSHA512_256() hash.Hash { panic("cngcrypto: not available") } ++func NewSHA3_224() *Hash { panic("cngcrypto: not available") } ++func NewSHA3_256() *Hash { return cng.NewSHA3_256() } ++func NewSHA3_384() *Hash { return cng.NewSHA3_384() } ++func NewSHA3_512() *Hash { return cng.NewSHA3_512() } + -+package fips140 ++func NewSHAKE128() *SHAKE { return cng.NewSHAKE128() } ++func NewSHAKE256() *SHAKE { return cng.NewSHAKE256() } ++func NewCSHAKE128(N, S []byte) *SHAKE { return cng.NewCSHAKE128(N, S) } ++func NewCSHAKE256(N, S []byte) *SHAKE { return cng.NewCSHAKE256(N, S) } + -+const isRequireFIPS = false -\ No newline at end of file -diff --git a/src/crypto/internal/backend/fips140/nosystemcrypto.go b/src/crypto/internal/backend/fips140/nosystemcrypto.go -new file mode 100644 -index 00000000000000..289d6594eac54b ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/nosystemcrypto.go -@@ -0,0 +1,13 @@ -+// Copyright 2024 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. ++func MD5(p []byte) (sum [16]byte) { return cng.MD5(p) } ++func SHA1(p []byte) (sum [20]byte) { return cng.SHA1(p) } ++func SHA224(p []byte) (sum [28]byte) { panic("cngcrypto: not available") } ++func SHA256(p []byte) (sum [32]byte) { return cng.SHA256(p) } ++func SHA384(p []byte) (sum [48]byte) { return cng.SHA384(p) } ++func SHA512(p []byte) (sum [64]byte) { return cng.SHA512(p) } ++func SHA512_224(p []byte) (sum [28]byte) { panic("cngcrypto: not available") } ++func SHA512_256(p []byte) (sum [32]byte) { panic("cngcrypto: not available") } ++func SumSHA3_224(p []byte) (sum [28]byte) { panic("cngcrypto: not available") } ++func SumSHA3_256(p []byte) (sum [32]byte) { return cng.SumSHA3_256(p) } ++func SumSHA3_384(p []byte) (sum [48]byte) { return cng.SumSHA3_384(p) } ++func SumSHA3_512(p []byte) (sum [64]byte) { return cng.SumSHA3_512(p) } + -+//go:build !goexperiment.systemcrypto ++func SumSHAKE128(data []byte, length int) (sum []byte) { return cng.SumSHAKE128(data, length) } ++func SumSHAKE256(data []byte, length int) (sum []byte) { return cng.SumSHAKE256(data, length) } + -+package fips140 ++func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { ++ return cng.NewHMAC(h, key) ++} + -+const backendEnabled = false ++func NewAESCipher(key []byte) (cipher.Block, error) { ++ return cng.NewAESCipher(key) ++} + -+func systemFIPSMode() bool { -+ return false ++func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { ++ return cng.NewGCMTLS(c) +} -diff --git a/src/crypto/internal/backend/fips140/openssl_linux.go b/src/crypto/internal/backend/fips140/openssl_linux.go -new file mode 100644 -index 00000000000000..95c93093d0b707 ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/openssl_linux.go -@@ -0,0 +1,59 @@ -+// Copyright 2024 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. + -+//go:build goexperiment.systemcrypto ++func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { ++ return cng.NewGCMTLS13(c) ++} + -+package fips140 ++type PublicKeyECDSA = cng.PublicKeyECDSA ++type PrivateKeyECDSA = cng.PrivateKeyECDSA + -+import ( -+ _ "crypto/internal/backend/internal/opensslsetup" -+ "syscall" ++func GenerateKeyECDSA(curve string) (X, Y, D cng.BigInt, err error) { ++ return cng.GenerateKeyECDSA(curve) ++} + -+ "github.com/golang-fips/openssl/v2/osslsetup" -+) ++func NewPrivateKeyECDSA(curve string, X, Y, D cng.BigInt) (*cng.PrivateKeyECDSA, error) { ++ return cng.NewPrivateKeyECDSA(curve, X, Y, D) ++} + -+const backendEnabled = true ++func NewPublicKeyECDSA(curve string, X, Y cng.BigInt) (*cng.PublicKeyECDSA, error) { ++ return cng.NewPublicKeyECDSA(curve, X, Y) ++} + -+// systemFIPSMode reports whether the system is in FIPS mode. -+// It first checks the kernel, and if that is not available, it checks the -+// OpenSSL library. -+func systemFIPSMode() bool { -+ if kernelFIPSMode() { -+ return true ++//go:linkname encodeSignature crypto/ecdsa.encodeSignature ++func encodeSignature(r, s []byte) ([]byte, error) ++ ++//go:linkname parseSignature crypto/ecdsa.parseSignature ++func parseSignature(sig []byte) (r, s []byte, err error) ++ ++func SignMarshalECDSA(priv *cng.PrivateKeyECDSA, hash []byte) ([]byte, error) { ++ r, s, err := cng.SignECDSA(priv, hash) ++ if err != nil { ++ return nil, err + } -+ return osslsetup.FIPS() ++ return encodeSignature(r, s) +} + -+// kernelFIPSMode reports whether the kernel is in FIPS mode. -+func kernelFIPSMode() bool { -+ var fd int -+ for { -+ var err error -+ fd, err = syscall.Open("/proc/sys/crypto/fips_enabled", syscall.O_RDONLY, 0) -+ if err == nil { -+ break -+ } -+ switch err { -+ case syscall.EINTR: -+ continue -+ case syscall.ENOENT: -+ return false -+ default: -+ // If there is an error reading we could either panic or assume FIPS is not enabled. -+ // Panicking would be too disruptive for apps that don't require FIPS. -+ // If an app wants to be 100% sure that is running in FIPS mode -+ // it should use fips140.Enabled() or GODEBUG=fips140=1. -+ return false -+ } -+ } -+ defer syscall.Close(fd) -+ var tmp [1]byte -+ n, err := syscall.Read(fd, tmp[:]) -+ if n != 1 || err != nil { -+ // We return false instead of panicing for the same reason as before. ++func VerifyECDSA(pub *cng.PublicKeyECDSA, hash []byte, sig []byte) bool { ++ rBytes, sBytes, err := parseSignature(sig) ++ if err != nil { + return false + } -+ // fips_enabled can be either '0' or '1'. -+ return tmp[0] == '1' ++ return cng.VerifyECDSA(pub, hash, cng.BigInt(rBytes), cng.BigInt(sBytes)) +} -diff --git a/src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go b/src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go -new file mode 100644 -index 00000000000000..dad6bcea9451e2 ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go -@@ -0,0 +1,15 @@ -+// Copyright 2025 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+//go:build requirefips && !goexperiment.systemcrypto + -+package fips140 ++func SignECDSA(priv *cng.PrivateKeyECDSA, hash []byte) (r, s cng.BigInt, err error) { ++ return cng.SignECDSA(priv, hash) ++} + -+func init() { -+ ` -+ The requirefips tag is enabled, but no crypto backend is enabled. -+ A crypto backend is required to enable FIPS mode. -+ For more information, visit https://github.com/microsoft/go/tree/microsoft/main/eng/doc/fips -+ ` ++func VerifyECDSARaw(pub *cng.PublicKeyECDSA, hash []byte, r, s cng.BigInt) bool { ++ return cng.VerifyECDSA(pub, hash, r, s) +} -diff --git a/src/crypto/internal/backend/fips140/skipfipscheck_off.go b/src/crypto/internal/backend/fips140/skipfipscheck_off.go -new file mode 100644 -index 00000000000000..f60b10dfa3aaf3 ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/skipfipscheck_off.go -@@ -0,0 +1,9 @@ -+// Copyright 2025 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. + -+//go:build !ms_skipfipscheck ++func SupportsRSAPrivateKey(bits, primes int) bool { ++ return primes == 2 && SupportsRSAPublicKey(bits) ++} + -+package fips140 ++func SupportsRSAPublicKey(bits int) bool { ++ return bits >= 512 && bits%8 == 0 && bits <= 16384 ++} + -+const isSkipFIPSCheck = false -diff --git a/src/crypto/internal/backend/fips140/skipfipscheck_on.go b/src/crypto/internal/backend/fips140/skipfipscheck_on.go -new file mode 100644 -index 00000000000000..d3d39fd77f98db ---- /dev/null -+++ b/src/crypto/internal/backend/fips140/skipfipscheck_on.go -@@ -0,0 +1,9 @@ -+// Copyright 2025 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. ++func SupportsRSASaltLength(sign bool, salt int) bool { ++ if sign { ++ return true ++ } ++ return salt != 0 // rsa.PSSSaltLengthAuto ++} + -+//go:build ms_skipfipscheck ++type PublicKeyRSA = cng.PublicKeyRSA ++type PrivateKeyRSA = cng.PrivateKeyRSA + -+package fips140 ++func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *cng.PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { ++ return cng.DecryptRSAOAEP(h, priv, ciphertext, label) ++} + -+const isSkipFIPSCheck = true -diff --git a/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go -new file mode 100644 -index 00000000000000..ef97d994841717 ---- /dev/null -+++ b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go -@@ -0,0 +1,68 @@ -+// Copyright 2025 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. ++func DecryptRSAPKCS1(priv *cng.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ return cng.DecryptRSAPKCS1(priv, ciphertext) ++} + -+//go:build goexperiment.systemcrypto ++func DecryptRSANoPadding(priv *cng.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ return cng.DecryptRSANoPadding(priv, ciphertext) ++} + -+// opensslsetup is a package that initializes the OpenSSL library. -+// It doesn't export any symbol, but blank importing it has the -+// side effect of initializing the OpenSSL library. -+package opensslsetup ++func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *cng.PublicKeyRSA, msg, label []byte) ([]byte, error) { ++ return cng.EncryptRSAOAEP(h, pub, msg, label) ++} + -+import ( -+ "syscall" ++func EncryptRSAPKCS1(pub *cng.PublicKeyRSA, msg []byte) ([]byte, error) { ++ return cng.EncryptRSAPKCS1(pub, msg) ++} + -+ "github.com/golang-fips/openssl/v2/osslsetup" -+) ++func EncryptRSANoPadding(pub *cng.PublicKeyRSA, msg []byte) ([]byte, error) { ++ return cng.EncryptRSANoPadding(pub, msg) ++} + -+// knownVersions is a list of supported and well-known libcrypto.so suffixes in decreasing version order. -+// FreeBSD library version numbering does not directly align to the version of osslsetup. -+// Its preferred search order is 11 -> 111. -+var knownVersions = [...]string{"3", "1.1", "11", "111"} ++func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv cng.BigInt, err error) { ++ return cng.GenerateKeyRSA(bits) ++} + -+const lcryptoPrefix = "libcrypto.so." ++func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv cng.BigInt) (*cng.PrivateKeyRSA, error) { ++ return cng.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) ++} + -+func init() { -+ lib := library() -+ if err := osslsetup.Init(lib); err != nil { -+ panic("opensslcrypto: can't initialize OpenSSL " + lib + ": " + err.Error()) -+ } ++func NewPublicKeyRSA(N, E cng.BigInt) (*cng.PublicKeyRSA, error) { ++ return cng.NewPublicKeyRSA(N, E) +} + -+// library returns the name of the OpenSSL library to use. -+// It first checks the environment variable GO_OPENSSL_VERSION_OVERRIDE. -+// If that is not set, it searches a well-known list of library names. -+// If no library is found, it returns "libcrypto.so". -+func library() string { -+ if version, _ := syscall.Getenv("GO_OPENSSL_VERSION_OVERRIDE"); version != "" { -+ return lcryptoPrefix + version -+ } -+ if lib := searchKnownLibrary(); lib != "" { -+ return lib -+ } -+ return lcryptoPrefix[:len(lcryptoPrefix)-1] // no version found, try without version suffix ++func SignRSAPKCS1v15(priv *cng.PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { ++ return cng.SignRSAPKCS1v15(priv, h, hashed) +} + -+// checkVersion is a variable that holds the osslsetup.CheckVersion function. -+// It is initialized in the init function to allow overriding in tests. -+var checkVersion = osslsetup.CheckVersion -+ -+// searchKnownLibrary returns the name of the highest available FIPS-enabled version of OpenSSL -+// using the known library suffixes. -+// If no FIPS-enabled version is found, it returns the name of the highest available version. -+// If no version is found, it returns an empty string. -+func searchKnownLibrary() string { -+ var lcryptoFallback string -+ for _, v := range knownVersions { -+ lcryptoCandidate := lcryptoPrefix + v -+ if exists, fips := checkVersion(lcryptoCandidate); exists { -+ if fips { -+ return lcryptoCandidate -+ } -+ if lcryptoFallback == "" { -+ lcryptoFallback = lcryptoCandidate -+ } -+ } -+ } -+ return lcryptoFallback ++func SignRSAPSS(priv *cng.PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { ++ return cng.SignRSAPSS(priv, h, hashed, saltLen) +} -diff --git a/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go -new file mode 100644 -index 00000000000000..7276cc2b871b85 ---- /dev/null -+++ b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go -@@ -0,0 +1,92 @@ -+// Copyright 2025 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. + -+//go:build goexperiment.systemcrypto && cgo ++func VerifyRSAPKCS1v15(pub *cng.PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { ++ return cng.VerifyRSAPKCS1v15(pub, h, hashed, sig) ++} + -+package opensslsetup ++func VerifyRSAPSS(pub *cng.PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { ++ return cng.VerifyRSAPSS(pub, h, hashed, sig, saltLen) ++} + -+import "testing" ++type PrivateKeyECDH = cng.PrivateKeyECDH ++type PublicKeyECDH = cng.PublicKeyECDH + -+func mockCheckVersion(t *testing.T, fn func(string) (bool, bool)) { -+ original := checkVersion -+ t.Cleanup(func() { -+ checkVersion = original -+ }) -+ checkVersion = fn ++func ECDH(priv *cng.PrivateKeyECDH, pub *cng.PublicKeyECDH) ([]byte, error) { ++ return cng.ECDH(priv, pub) +} + -+func assertLibrary(t *testing.T, expected string) { -+ if result := library(); result != expected { -+ t.Errorf("expected %s, got %s", expected, result) -+ } ++func GenerateKeyECDH(curve string) (*cng.PrivateKeyECDH, []byte, error) { ++ return cng.GenerateKeyECDH(curve) +} + -+func TestLibraryWithEnvOverride(t *testing.T) { -+ t.Setenv("GO_OPENSSL_VERSION_OVERRIDE", "1.1") -+ mockCheckVersion(t, func(s string) (bool, bool) { return false, false }) -+ assertLibrary(t, "libcrypto.so.1.1") ++func NewPrivateKeyECDH(curve string, bytes []byte) (*cng.PrivateKeyECDH, error) { ++ return cng.NewPrivateKeyECDH(curve, bytes) +} + -+func TestLibraryWithKnownVersion(t *testing.T) { -+ t.Setenv("GO_OPENSSL_VERSION_OVERRIDE", "") ++func NewPublicKeyECDH(curve string, bytes []byte) (*cng.PublicKeyECDH, error) { ++ return cng.NewPublicKeyECDH(curve, bytes) ++} + -+ const maxLib = "libcrypto.so.3" ++func SupportsTLS13KDF() bool { ++ return false ++} + -+ t.Run("AllExistsNoneFIPS", func(t *testing.T) { -+ mockCheckVersion(t, func(s string) (bool, bool) { -+ return true, false -+ }) -+ for _, v := range knownVersions { -+ t.Run(v, func(t *testing.T) { -+ assertLibrary(t, maxLib) -+ }) -+ } -+ }) ++func ExpandTLS13KDF(h func() hash.Hash, pseudorandomKey, label, context []byte, keyLength int) ([]byte, error) { ++ panic("cryptobackend: not available") ++} + -+ t.Run("OnlyOneExists", func(t *testing.T) { -+ for _, v := range knownVersions { -+ t.Run(v, func(t *testing.T) { -+ expected := "libcrypto.so." + v -+ mockCheckVersion(t, func(s string) (bool, bool) { -+ if s == expected { -+ return true, false -+ } -+ return false, false -+ }) -+ assertLibrary(t, expected) -+ }) -+ } -+ }) ++func SupportsHKDF() bool { ++ return cng.SupportsHKDF() ++} + -+ t.Run("AllExistsOnlyOneFIPS", func(t *testing.T) { -+ fipsLib := "libcrypto.so.1.1" -+ mockCheckVersion(t, func(s string) (bool, bool) { -+ return true, s == fipsLib -+ }) -+ for _, v := range knownVersions { -+ t.Run(v, func(t *testing.T) { -+ assertLibrary(t, fipsLib) -+ }) -+ } -+ }) ++func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) { ++ return cng.ExpandHKDF(h, pseudorandomKey, info, keyLength) ++} + -+ t.Run("AllExistsAndAreFIPS", func(t *testing.T) { -+ mockCheckVersion(t, func(s string) (bool, bool) { -+ return true, true -+ }) -+ for _, v := range knownVersions { -+ t.Run(v, func(t *testing.T) { -+ assertLibrary(t, maxLib) -+ }) -+ } -+ }) ++func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) { ++ return cng.ExtractHKDF(h, secret, salt) +} + -+func TestLibraryNoVersionFound(t *testing.T) { -+ t.Setenv("GO_OPENSSL_VERSION_OVERRIDE", "") -+ mockCheckVersion(t, func(string) (bool, bool) { -+ return false, false -+ }) -+ assertLibrary(t, "libcrypto.so") ++func SupportsPBKDF2() bool { return true } ++ ++func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) ([]byte, error) { ++ return cng.PBKDF2(password, salt, iter, keyLen, h) +} -diff --git a/src/crypto/internal/backend/internal/opensslsetup/stub.go b/src/crypto/internal/backend/internal/opensslsetup/stub.go -new file mode 100644 -index 00000000000000..19fd29e19e7b96 ---- /dev/null -+++ b/src/crypto/internal/backend/internal/opensslsetup/stub.go -@@ -0,0 +1,8 @@ -+// Copyright 2025 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. + -+// Placeholder to allow the opensslsetup package to be imported -+// without cgo enabled or without goexperiment.systemcrypto on linux. ++func SupportsTLS1PRF() bool { ++ return true ++} + -+package opensslsetup -diff --git a/src/crypto/internal/backend/nobackend.go b/src/crypto/internal/backend/nobackend.go -new file mode 100644 -index 00000000000000..cdc768b1e4b57d ---- /dev/null -+++ b/src/crypto/internal/backend/nobackend.go -@@ -0,0 +1,376 @@ -+// Copyright 2017 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. ++func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error { ++ return cng.TLS1PRF(result, secret, label, seed, h) ++} + -+//go:build !goexperiment.systemcrypto ++func SupportsDESCipher() bool { ++ return true ++} + -+package backend ++func SupportsTripleDESCipher() bool { ++ return true ++} + -+import ( -+ "crypto" -+ "crypto/cipher" -+ "crypto/internal/backend/fips140" -+ "hash" -+ "io" -+) ++func NewDESCipher(key []byte) (cipher.Block, error) { ++ return cng.NewDESCipher(key) ++} + -+func init() { -+ if err := fips140.Check(func() bool { return false }); err != nil { -+ panic(err) -+ } ++func NewTripleDESCipher(key []byte) (cipher.Block, error) { ++ return cng.NewTripleDESCipher(key) +} + -+const Enabled = false ++func SupportsRC4() bool { return true } + -+type BigInt = []uint ++type RC4Cipher = cng.RC4Cipher + -+type randReader int ++func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return cng.NewRC4Cipher(key) } + -+func (randReader) Read(b []byte) (int, error) { panic("cryptobackend: not available") } ++func SupportsEd25519() bool { return false } + -+const RandReader = randReader(0) ++type PublicKeyEd25519 struct{} + -+func SupportsHash(h crypto.Hash) bool { panic("cryptobackend: not available") } -+func FIPSApprovedHash(h hash.Hash) bool { panic("cryptobackend: not available") } ++func (k PublicKeyEd25519) Bytes() ([]byte, error) { ++ panic("cryptobackend: not available") ++} + -+func SupportsSHAKE(securityBits int) bool { panic("cryptobackend: not available") } -+func SupportsCSHAKE(securityBits int) bool { panic("cryptobackend: not available") } ++type PrivateKeyEd25519 struct{} + -+func SupportsCurve(curve string) bool { panic("cryptobackend: not available") } -+func SupportsRSAOAEPLabel(label []byte) bool { panic("cryptobackend: not available") } -+func SupportsRSAPKCS1v15Encryption() bool { panic("cryptobackend: not available") } -+func SupportsRSAPKCS1v15Signature(hash crypto.Hash) bool { panic("cryptobackend: not available") } ++func (k PrivateKeyEd25519) Bytes() ([]byte, error) { ++ panic("cryptobackend: not available") ++} + -+type Hash struct { -+ hash.Cloner ++func GenerateKeyEd25519() (PrivateKeyEd25519, error) { ++ panic("cryptobackend: not available") +} + -+func (d *Hash) MarshalBinary() ([]byte, error) { panic("cryptobackend: not available") } -+func (d *Hash) AppendBinary(p []byte) ([]byte, error) { panic("cryptobackend: not available") } -+func (d *Hash) UnmarshalBinary(data []byte) error { panic("cryptobackend: not available") } ++func NewPrivateKeyEd25519(priv []byte) (PrivateKeyEd25519, error) { ++ panic("cryptobackend: not available") ++} + -+type SHAKE struct { -+ io.Reader -+ hash.Hash ++func NewPublicKeyEd25519(pub []byte) (PublicKeyEd25519, error) { ++ panic("cryptobackend: not available") +} + -+func (s *SHAKE) MarshalBinary() ([]byte, error) { panic("cryptobackend: not available") } -+func (s *SHAKE) AppendBinary(p []byte) ([]byte, error) { panic("cryptobackend: not available") } -+func (s *SHAKE) UnmarshalBinary(data []byte) error { panic("cryptobackend: not available") } ++func NewPrivateKeyEd25519FromSeed(seed []byte) (PrivateKeyEd25519, error) { ++ panic("cryptobackend: not available") ++} + -+func NewMD5() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA1() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA224() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA256() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA384() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA512() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA512_224() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA512_256() hash.Hash { panic("cryptobackend: not available") } -+func NewSHA3_224() *Hash { panic("cryptobackend: not available") } -+func NewSHA3_256() *Hash { panic("cryptobackend: not available") } -+func NewSHA3_384() *Hash { panic("cryptobackend: not available") } -+func NewSHA3_512() *Hash { panic("cryptobackend: not available") } -+ -+func NewSHAKE128() *SHAKE { panic("cryptobackend: not available") } -+func NewSHAKE256() *SHAKE { panic("cryptobackend: not available") } -+func NewCSHAKE128(N, S []byte) *SHAKE { panic("cryptobackend: not available") } -+func NewCSHAKE256(N, S []byte) *SHAKE { panic("cryptobackend: not available") } -+ -+func MD5(p []byte) (sum [16]byte) { panic("cryptobackend: not available") } -+func SHA1(p []byte) (sum [20]byte) { panic("cryptobackend: not available") } -+func SHA224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } -+func SHA256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } -+func SHA384(p []byte) (sum [48]byte) { panic("cryptobackend: not available") } -+func SHA512(p []byte) (sum [64]byte) { panic("cryptobackend: not available") } -+func SHA512_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } -+func SHA512_256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } -+func SumSHA3_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } -+func SumSHA3_256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } -+func SumSHA3_384(p []byte) (sum [48]byte) { panic("cryptobackend: not available") } -+func SumSHA3_512(p []byte) (sum [64]byte) { panic("cryptobackend: not available") } -+ -+func SumSHAKE128(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } -+func SumSHAKE256(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } -+ -+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("cryptobackend: not available") } -+ -+func NewAESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") } -+func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { panic("cryptobackend: not available") } -+func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { panic("cryptobackend: not available") } -+ -+type PublicKeyECDSA struct{ _ int } -+type PrivateKeyECDSA struct{ _ int } -+ -+func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) { -+ panic("cryptobackend: not available") -+} -+func NewPrivateKeyECDSA(curve string, X, Y, D BigInt) (*PrivateKeyECDSA, error) { -+ panic("cryptobackend: not available") -+} -+func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) { -+ panic("cryptobackend: not available") -+} -+func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { ++func SignEd25519(priv PrivateKeyEd25519, message []byte) ([]byte, error) { + panic("cryptobackend: not available") +} -+func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool { ++ ++func VerifyEd25519(pub PublicKeyEd25519, message, sig []byte) error { + panic("cryptobackend: not available") +} -+func SupportsRSAPrivateKey(bits, primes int) bool { panic("cryptobackend: not available") } -+func SupportsRSAPublicKey(bits int) bool { panic("cryptobackend: not available") } -+func SupportsRSASaltLength(sign bool, salt int) bool { panic("cryptobackend: not available") } + -+type PublicKeyRSA struct{ _ int } -+type PrivateKeyRSA struct{ _ int } ++type PrivateKeyDSA = cng.PrivateKeyDSA ++type PublicKeyDSA = cng.PublicKeyDSA + -+func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { -+ panic("cryptobackend: not available") -+} -+func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ panic("cryptobackend: not available") -+} -+func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ panic("cryptobackend: not available") -+} -+func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { -+ panic("cryptobackend: not available") -+} -+func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { -+ panic("cryptobackend: not available") ++func SupportsDSA(l, n int) bool { ++ // These are the only N values supported by CNG ++ return n == 160 || n == 256 +} -+func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { -+ panic("cryptobackend: not available") ++ ++func GenerateParametersDSA(l, n int) (p, q, g cng.BigInt, err error) { ++ params, err := cng.GenerateParametersDSA(l) ++ if err != nil { ++ return nil, nil, nil, err ++ } ++ return params.P, params.Q, params.G, nil +} -+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { -+ panic("cryptobackend: not available") ++ ++func GenerateKeyDSA(p, q, g cng.BigInt) (x, y cng.BigInt, err error) { ++ return cng.GenerateKeyDSA(cng.DSAParameters{P: p, Q: q, G: g}) +} -+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) { -+ panic("cryptobackend: not available") ++ ++func NewPrivateKeyDSA(p, q, g, x, y cng.BigInt) (*cng.PrivateKeyDSA, error) { ++ return cng.NewPrivateKeyDSA(cng.DSAParameters{P: p, Q: q, G: g}, x, y) +} -+func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { -+ panic("cryptobackend: not available") ++ ++func NewPublicKeyDSA(p, q, g, y cng.BigInt) (*cng.PublicKeyDSA, error) { ++ return cng.NewPublicKeyDSA(cng.DSAParameters{P: p, Q: q, G: g}, y) +} -+func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { -+ panic("cryptobackend: not available") ++ ++func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (cng.BigInt, cng.BigInt, error)) (r, s cng.BigInt, err error) { ++ return cng.SignDSA(priv, hash) +} -+func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { -+ panic("cryptobackend: not available") ++ ++func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s cng.BigInt, encodeSignature func(r, s cng.BigInt) ([]byte, error)) bool { ++ return cng.VerifyDSA(pub, hashed, r, s) +} -+func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { -+ panic("cryptobackend: not available") ++ ++func SupportsMLKEM768() bool { ++ return cng.SupportsMLKEM() +} -+func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { -+ panic("cryptobackend: not available") ++ ++func SupportsMLKEM1024() bool { ++ return cng.SupportsMLKEM() +} + -+type PublicKeyECDH struct{} -+type PrivateKeyECDH struct{} ++type DecapsulationKeyMLKEM768 = cng.DecapsulationKeyMLKEM768 ++type EncapsulationKeyMLKEM768 = cng.EncapsulationKeyMLKEM768 + -+func ECDH(*PrivateKeyECDH, *PublicKeyECDH) ([]byte, error) { panic("cryptobackend: not available") } -+func GenerateKeyECDH(string) (*PrivateKeyECDH, []byte, error) { panic("cryptobackend: not available") } -+func NewPrivateKeyECDH(string, []byte) (*PrivateKeyECDH, error) { -+ panic("cryptobackend: not available") ++func GenerateKeyMLKEM768() (DecapsulationKeyMLKEM768, error) { ++ return cng.GenerateKeyMLKEM768() +} -+func NewPublicKeyECDH(string, []byte) (*PublicKeyECDH, error) { panic("cryptobackend: not available") } -+func (*PublicKeyECDH) Bytes() []byte { panic("cryptobackend: not available") } -+func (*PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { panic("cryptobackend: not available") } + -+func SupportsTLS13KDF() bool { panic("cryptobackend: not available") } ++func NewDecapsulationKeyMLKEM768(seed []byte) (DecapsulationKeyMLKEM768, error) { ++ return cng.NewDecapsulationKeyMLKEM768(seed) ++} + -+func ExpandTLS13KDF(h func() hash.Hash, pseudorandomKey, label, context []byte, keyLength int) ([]byte, error) { -+ panic("cryptobackend: not available") ++func NewEncapsulationKeyMLKEM768(encapsulationKey []byte) (EncapsulationKeyMLKEM768, error) { ++ return cng.NewEncapsulationKeyMLKEM768(encapsulationKey) +} + -+func SupportsHKDF() bool { panic("cryptobackend: not available") } ++type DecapsulationKeyMLKEM1024 = cng.DecapsulationKeyMLKEM1024 ++type EncapsulationKeyMLKEM1024 = cng.EncapsulationKeyMLKEM1024 + -+func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) { -+ panic("cryptobackend: not available") ++func GenerateKeyMLKEM1024() (DecapsulationKeyMLKEM1024, error) { ++ return cng.GenerateKeyMLKEM1024() +} + -+func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) { -+ panic("cryptobackend: not available") ++func NewDecapsulationKeyMLKEM1024(seed []byte) (DecapsulationKeyMLKEM1024, error) { ++ return cng.NewDecapsulationKeyMLKEM1024(seed) +} + -+func SupportsPBKDF2() bool { panic("cryptobackend: not available") } -+ -+func PBKDF2(password, salt []byte, iter, keyLen int, fh func() hash.Hash) ([]byte, error) { -+ panic("cryptobackend: not available") ++func NewEncapsulationKeyMLKEM1024(encapsulationKey []byte) (EncapsulationKeyMLKEM1024, error) { ++ return cng.NewEncapsulationKeyMLKEM1024(encapsulationKey) +} + -+func SupportsTLS1PRF() bool { panic("cryptobackend: not available") } ++func SupportsChaCha20Poly1305() bool { ++ return cng.SupportsChaCha20Poly1305() ++} + -+func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error { -+ panic("cryptobackend: not available") ++func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) { ++ return cng.NewChaCha20Poly1305(key) +} +diff --git a/src/crypto/internal/backend/bbig/big.go b/src/crypto/internal/backend/bbig/big.go +new file mode 100644 +index 00000000000000..20251a290dc2e0 +--- /dev/null ++++ b/src/crypto/internal/backend/bbig/big.go +@@ -0,0 +1,17 @@ ++// Copyright 2022 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+func SupportsDESCipher() bool { panic("cryptobackend: not available") } ++//go:build !goexperiment.systemcrypto + -+func SupportsTripleDESCipher() bool { panic("cryptobackend: not available") } ++package bbig + -+func NewDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") } ++import "math/big" + -+func NewTripleDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") } ++func Enc(b *big.Int) []uint { ++ return nil ++} + -+func SupportsRC4() bool { panic("cryptobackend: not available") } ++func Dec(b []uint) *big.Int { ++ return nil ++} +diff --git a/src/crypto/internal/backend/bbig/big_darwin.go b/src/crypto/internal/backend/bbig/big_darwin.go +new file mode 100644 +index 00000000000000..889f2ff7c703d8 +--- /dev/null ++++ b/src/crypto/internal/backend/bbig/big_darwin.go +@@ -0,0 +1,12 @@ ++// Copyright 2022 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+type RC4Cipher struct{} ++//go:build goexperiment.systemcrypto + -+func (c *RC4Cipher) Reset() { panic("cryptobackend: not available") } -+func (c *RC4Cipher) XORKeyStream(dst, src []byte) { panic("cryptobackend: not available") } ++package bbig + -+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { panic("cryptobackend: not available") } ++import "github.com/microsoft/go-crypto-darwin/bbig" + -+func SupportsEd25519() bool { panic("cryptobackend: not available") } ++var Enc = bbig.Enc ++var Dec = bbig.Dec +diff --git a/src/crypto/internal/backend/bbig/big_linux.go b/src/crypto/internal/backend/bbig/big_linux.go +new file mode 100644 +index 00000000000000..8a133422f20fa0 +--- /dev/null ++++ b/src/crypto/internal/backend/bbig/big_linux.go +@@ -0,0 +1,12 @@ ++// Copyright 2022 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+type PublicKeyEd25519 struct{} ++//go:build goexperiment.systemcrypto + -+func (k PublicKeyEd25519) Bytes() ([]byte, error) { -+ panic("cryptobackend: not available") -+} ++package bbig + -+type PrivateKeyEd25519 struct{} ++import "github.com/golang-fips/openssl/v2/bbig" + -+func (k PrivateKeyEd25519) Bytes() ([]byte, error) { -+ panic("cryptobackend: not available") -+} ++var Enc = bbig.Enc ++var Dec = bbig.Dec +diff --git a/src/crypto/internal/backend/bbig/big_windows.go b/src/crypto/internal/backend/bbig/big_windows.go +new file mode 100644 +index 00000000000000..f2c21a88bff471 +--- /dev/null ++++ b/src/crypto/internal/backend/bbig/big_windows.go +@@ -0,0 +1,12 @@ ++// Copyright 2022 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+func GenerateKeyEd25519() (PrivateKeyEd25519, error) { -+ panic("cryptobackend: not available") -+} ++//go:build goexperiment.systemcrypto + -+func NewPrivateKeyEd25519(priv []byte) (PrivateKeyEd25519, error) { -+ panic("cryptobackend: not available") -+} ++package bbig + -+func NewPublicKeyEd25519(pub []byte) (PublicKeyEd25519, error) { -+ panic("cryptobackend: not available") -+} ++import "github.com/microsoft/go-crypto-winnative/cng/bbig" + -+func NewPrivateKeyEd25519FromSeed(seed []byte) (PrivateKeyEd25519, error) { -+ panic("cryptobackend: not available") ++var Enc = bbig.Enc ++var Dec = bbig.Dec +diff --git a/src/crypto/internal/backend/common.go b/src/crypto/internal/backend/common.go +new file mode 100644 +index 00000000000000..a9682181ffa154 +--- /dev/null ++++ b/src/crypto/internal/backend/common.go +@@ -0,0 +1,46 @@ ++// Copyright 2022 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++package backend ++ ++import ( ++ "crypto/internal/boring/sig" ++ "runtime" ++) ++ ++// Unreachable marks code that should be unreachable ++// when backend is in use. ++func Unreachable() { ++ if Enabled { ++ panic("cryptobackend: invalid code execution") ++ } else { ++ // Code that's unreachable is exactly the code ++ // we want to detect for reporting standard Go crypto. ++ sig.StandardCrypto() ++ } ++} ++ ++// Provided by runtime.crypto_backend_runtime_arg0 to avoid os import. ++func runtime_arg0() string ++ ++func hasSuffix(s, t string) bool { ++ return len(s) > len(t) && s[len(s)-len(t):] == t ++} ++ ++// UnreachableExceptTests marks code that should be unreachable ++// when backend is in use. It panics. ++func UnreachableExceptTests() { ++ // runtime_arg0 is not supported on windows. ++ // We are going through the same code patch on linux, ++ // so if we are unintentionally calling an 'unreachable' function, ++ // we will catch it there. ++ if Enabled && runtime.GOOS != "windows" { ++ name := runtime_arg0() ++ // If ran on Windows we'd need to allow _test.exe and .test.exe as well. ++ if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") { ++ println("cryptobackend: unexpected code execution in", name) ++ panic("cryptobackend: invalid code execution") ++ } ++ } ++} +diff --git a/src/crypto/internal/backend/fips140/fips140.go b/src/crypto/internal/backend/fips140/fips140.go +new file mode 100644 +index 00000000000000..1bf7c3b7d63da8 +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/fips140.go +@@ -0,0 +1,70 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++package fips140 ++ ++import ( ++ "errors" ++ "internal/godebug" ++ "runtime" ++ "syscall" ++) ++ ++var fips140GODEBUG = godebug.New("fips140") ++ ++// Enabled reports whether FIPS 140 mode is enabled by using GODEBUG, GOFIPS, GOLANG_FIPS, ++// the 'requirefips' build tag, or any other platform-specific mechanism. ++func Enabled() bool { ++ return enabled ++} ++ ++var enabled bool ++ ++// message is a human-readable message about how [Enabled] was set. ++var message string ++ ++func init() { ++ // TODO: Decide which environment variable to use. ++ // See https://github.com/microsoft/go/issues/397. ++ var ok bool ++ value := fips140GODEBUG.Value() ++ if value == "on" || value == "only" || value == "debug" { ++ message = "environment variable GODEBUG=fips140=" + value ++ value = "1" ++ } else if value, ok = syscall.Getenv("GOFIPS"); ok { ++ message = "environment variable GOFIPS" ++ } else if value, ok = syscall.Getenv("GOLANG_FIPS"); ok { ++ message = "environment variable GOLANG_FIPS" ++ } else if systemFIPSMode() { ++ message = "system FIPS mode" ++ value = "1" ++ } ++ enabled = value == "1" ++ if isRequireFIPS { ++ if isSkipFIPSCheck { ++ panic("the 'requirefips' build tag is enabled, but it conflicts " + ++ "with the 'ms_skipfipscheck' build tag") ++ } ++ message = "requirefips tag set" ++ enabled = true ++ } ++} ++ ++// Check checks whether fips mode, as returned by fips(), ++// is valid given the current settings. ++func Check(fips func() bool) error { ++ if isSkipFIPSCheck || !enabled { ++ return nil ++ } ++ if !backendEnabled { ++ if runtime.GOOS != "linux" && runtime.GOOS != "windows" && runtime.GOOS != "darwin" { ++ return errors.New("FIPS mode requested (" + message + ") but no crypto backend is supported on " + runtime.GOOS) ++ } ++ return errors.New("FIPS mode requested (" + message + ") but no supported crypto backend is enabled") ++ } ++ if !fips() { ++ return errors.New("FIPS mode requested (" + message + ") but not available") ++ } ++ return nil ++} +diff --git a/src/crypto/internal/backend/fips140/isrequirefips.go b/src/crypto/internal/backend/fips140/isrequirefips.go +new file mode 100644 +index 00000000000000..b33d08c84e2dae +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/isrequirefips.go +@@ -0,0 +1,9 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build requirefips ++ ++package fips140 ++ ++const isRequireFIPS = true +\ No newline at end of file +diff --git a/src/crypto/internal/backend/fips140/norequirefips.go b/src/crypto/internal/backend/fips140/norequirefips.go +new file mode 100644 +index 00000000000000..6f01b9a3524dee +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/norequirefips.go +@@ -0,0 +1,9 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build !requirefips ++ ++package fips140 ++ ++const isRequireFIPS = false +\ No newline at end of file +diff --git a/src/crypto/internal/backend/fips140/nosystemcrypto.go b/src/crypto/internal/backend/fips140/nosystemcrypto.go +new file mode 100644 +index 00000000000000..289d6594eac54b +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/nosystemcrypto.go +@@ -0,0 +1,13 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build !goexperiment.systemcrypto ++ ++package fips140 ++ ++const backendEnabled = false ++ ++func systemFIPSMode() bool { ++ return false ++} +diff --git a/src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go b/src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go +new file mode 100644 +index 00000000000000..dad6bcea9451e2 +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/requirefips_nosystemcrypto.go +@@ -0,0 +1,15 @@ ++// Copyright 2025 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build requirefips && !goexperiment.systemcrypto ++ ++package fips140 ++ ++func init() { ++ ` ++ The requirefips tag is enabled, but no crypto backend is enabled. ++ A crypto backend is required to enable FIPS mode. ++ For more information, visit https://github.com/microsoft/go/tree/microsoft/main/eng/doc/fips ++ ` ++} +diff --git a/src/crypto/internal/backend/fips140/skipfipscheck_off.go b/src/crypto/internal/backend/fips140/skipfipscheck_off.go +new file mode 100644 +index 00000000000000..f60b10dfa3aaf3 +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/skipfipscheck_off.go +@@ -0,0 +1,9 @@ ++// Copyright 2025 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build !ms_skipfipscheck ++ ++package fips140 ++ ++const isSkipFIPSCheck = false +diff --git a/src/crypto/internal/backend/fips140/skipfipscheck_on.go b/src/crypto/internal/backend/fips140/skipfipscheck_on.go +new file mode 100644 +index 00000000000000..d3d39fd77f98db +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/skipfipscheck_on.go +@@ -0,0 +1,9 @@ ++// Copyright 2025 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build ms_skipfipscheck ++ ++package fips140 ++ ++const isSkipFIPSCheck = true +diff --git a/src/crypto/internal/backend/fips140/systemfips_darwin.go b/src/crypto/internal/backend/fips140/systemfips_darwin.go +new file mode 100644 +index 00000000000000..606a2db4dd685f +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/systemfips_darwin.go +@@ -0,0 +1,13 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build goexperiment.systemcrypto ++ ++package fips140 ++ ++const backendEnabled = true ++ ++func systemFIPSMode() bool { ++ return false ++} +diff --git a/src/crypto/internal/backend/fips140/systemfips_linux.go b/src/crypto/internal/backend/fips140/systemfips_linux.go +new file mode 100644 +index 00000000000000..19cafc156fbc5d +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/systemfips_linux.go +@@ -0,0 +1,59 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build goexperiment.systemcrypto ++ ++package fips140 ++ ++import ( ++ _ "crypto/internal/backend/internal/opensslsetup" ++ "syscall" ++ ++ "github.com/golang-fips/openssl/v2/osslsetup" ++) ++ ++const backendEnabled = true ++ ++// systemFIPSMode reports whether the system is in FIPS mode. ++// It first checks the kernel, and if that is not available, it checks the ++// OpenSSL library. ++func systemFIPSMode() bool { ++ if kernelFIPSMode() { ++ return true ++ } ++ return osslsetup.FIPS() ++} ++ ++// kernelFIPSMode reports whether the kernel is in FIPS mode. ++func kernelFIPSMode() bool { ++ var fd int ++ for { ++ var err error ++ fd, err = syscall.Open("/proc/sys/crypto/fips_enabled", syscall.O_RDONLY, 0) ++ if err == nil { ++ break ++ } ++ switch err { ++ case syscall.EINTR: ++ continue ++ case syscall.ENOENT: ++ return false ++ default: ++ // If there is an error reading we could either panic or assume FIPS is not enabled. ++ // Panicking would be too disruptive for apps that don't require FIPS. ++ // If an app wants to be 100% sure that is running in FIPS mode ++ // it should use fips140.Enabled() or GODEBUG=fips140=1. ++ return false ++ } ++ } ++ defer syscall.Close(fd) ++ var tmp [1]byte ++ n, err := syscall.Read(fd, tmp[:]) ++ if n != 1 || err != nil { ++ // We return false instead of panicing for the same reason as before. ++ return false ++ } ++ // fips_enabled can be either '0' or '1'. ++ return tmp[0] == '1' +} +diff --git a/src/crypto/internal/backend/fips140/systemfips_windows.go b/src/crypto/internal/backend/fips140/systemfips_windows.go +new file mode 100644 +index 00000000000000..a705e7bc4fc536 +--- /dev/null ++++ b/src/crypto/internal/backend/fips140/systemfips_windows.go +@@ -0,0 +1,35 @@ ++// Copyright 2024 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+func SignEd25519(priv PrivateKeyEd25519, message []byte) ([]byte, error) { -+ panic("cryptobackend: not available") -+} ++//go:build goexperiment.systemcrypto + -+func VerifyEd25519(pub PublicKeyEd25519, message, sig []byte) error { -+ panic("cryptobackend: not available") -+} ++package fips140 + -+func SupportsDSA(l, n int) bool { -+ panic("cryptobackend: not available") -+} ++import ( ++ "internal/syscall/windows/sysdll" ++ "syscall" ++ "unsafe" ++) + -+func GenerateParametersDSA(l, n int) (p, q, g BigInt, err error) { -+ panic("cryptobackend: not available") -+} ++const backendEnabled = true + -+type PublicKeyDSA struct{ _ int } -+type PrivateKeyDSA struct{ _ int } ++// Don't use github.com/microsoft/go-crypto-winnative here. ++// The fips140 package should have minimal dependencies. ++// Also, don't directly query the system FIPS mode from the registry, ++// there are some no-longer documented legacy entries that can enable FIPS mode, ++// and BCryptGetFipsAlgorithmMode supports them all. ++var ( ++ bcrypt = syscall.MustLoadDLL(sysdll.Add("bcrypt.dll")) + -+func GenerateKeyDSA(p, q, g BigInt) (x, y BigInt, err error) { -+ panic("cryptobackend: not available") -+} ++ bcryptGetFipsAlgorithmMode = bcrypt.MustFindProc("BCryptGetFipsAlgorithmMode") ++) + -+func NewPrivateKeyDSA(p, q, g, x, y BigInt) (*PrivateKeyDSA, error) { -+ panic("cryptobackend: not available") ++func systemFIPSMode() bool { ++ var enabled uint32 ++ ret, _, _ := bcryptGetFipsAlgorithmMode.Call(uintptr(unsafe.Pointer(&enabled))) ++ if ret != 0 { ++ return false ++ } ++ return enabled != 0 +} +diff --git a/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go +new file mode 100644 +index 00000000000000..968cdf35985f80 +--- /dev/null ++++ b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux.go +@@ -0,0 +1,68 @@ ++// Copyright 2025 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+func NewPublicKeyDSA(p, q, g, y BigInt) (*PublicKeyDSA, error) { -+ panic("cryptobackend: not available") -+} ++//go:build goexperiment.systemcrypto + -+func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (BigInt, BigInt, error)) (r, s BigInt, err error) { -+ panic("cryptobackend: not available") -+} ++// opensslsetup is a package that initializes the OpenSSL library. ++// It doesn't export any symbol, but blank importing it has the ++// side effect of initializing the OpenSSL library. ++package opensslsetup + -+func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s BigInt, encodeSignature func(r, s BigInt) ([]byte, error)) bool { -+ panic("cryptobackend: not available") -+} ++import ( ++ "syscall" + -+func SupportsMLKEM768() bool { -+ panic("cryptobackend: not available") -+} ++ "github.com/golang-fips/openssl/v2/osslsetup" ++) + -+func SupportsMLKEM1024() bool { -+ panic("cryptobackend: not available") -+} ++// knownVersions is a list of supported and well-known libcrypto.so suffixes in decreasing version order. ++// FreeBSD library version numbering does not directly align to the version of osslsetup. ++// Its preferred search order is 11 -> 111. ++var knownVersions = [...]string{"3", "1.1", "11", "111"} + -+type DecapsulationKeyMLKEM768 struct{} -+type EncapsulationKeyMLKEM768 struct{} ++const lcryptoPrefix = "libcrypto.so." + -+func GenerateKeyMLKEM768() (DecapsulationKeyMLKEM768, error) { -+ panic("cryptobackend: not available") ++func init() { ++ lib := library() ++ if err := osslsetup.Init(lib); err != nil { ++ panic("opensslcrypto: can't initialize OpenSSL " + lib + ": " + err.Error()) ++ } +} + -+func NewDecapsulationKeyMLKEM768(seed []byte) (DecapsulationKeyMLKEM768, error) { -+ panic("cryptobackend: not available") ++// library returns the name of the OpenSSL library to use. ++// It first checks the environment variable GO_OPENSSL_VERSION_OVERRIDE. ++// If that is not set, it searches a well-known list of library names. ++// If no library is found, it returns "libcrypto.so". ++func library() string { ++ if version, _ := syscall.Getenv("GO_OPENSSL_VERSION_OVERRIDE"); version != "" { ++ return lcryptoPrefix + version ++ } ++ if lib := searchKnownLibrary(); lib != "" { ++ return lib ++ } ++ return lcryptoPrefix[:len(lcryptoPrefix)-1] // no version found, try without version suffix +} + -+func NewEncapsulationKeyMLKEM768(encapsulationKey []byte) (EncapsulationKeyMLKEM768, error) { -+ panic("cryptobackend: not available") -+} ++// checkVersion is a variable that holds the osslsetup.CheckVersion function. ++// It is initialized in the init function to allow overriding in tests. ++var checkVersion = osslsetup.CheckVersion + -+func (dk DecapsulationKeyMLKEM768) Bytes() []byte { -+ panic("cryptobackend: not available") ++// searchKnownLibrary returns the name of the highest available FIPS-enabled version of OpenSSL ++// using the known library suffixes. ++// If no FIPS-enabled version is found, it returns the name of the highest available version. ++// If no version is found, it returns an empty string. ++func searchKnownLibrary() string { ++ var lcryptoFallback string ++ for _, v := range knownVersions { ++ lcryptoCandidate := lcryptoPrefix + v ++ if exists, fips := checkVersion(lcryptoCandidate); exists { ++ if fips { ++ return lcryptoCandidate ++ } ++ if lcryptoFallback == "" { ++ lcryptoFallback = lcryptoCandidate ++ } ++ } ++ } ++ return lcryptoFallback +} +diff --git a/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go +new file mode 100644 +index 00000000000000..2e45358029f484 +--- /dev/null ++++ b/src/crypto/internal/backend/internal/opensslsetup/opensslsetup_linux_test.go +@@ -0,0 +1,92 @@ ++// Copyright 2025 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+func (dk DecapsulationKeyMLKEM768) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) { -+ panic("cryptobackend: not available") -+} ++//go:build goexperiment.systemcrypto && cgo + -+func (dk DecapsulationKeyMLKEM768) EncapsulationKey() EncapsulationKeyMLKEM768 { -+ panic("cryptobackend: not available") -+} ++package opensslsetup + -+func (ek EncapsulationKeyMLKEM768) Bytes() []byte { -+ panic("cryptobackend: not available") -+} ++import "testing" + -+func (ek EncapsulationKeyMLKEM768) Encapsulate() (sharedKey, ciphertext []byte) { -+ panic("cryptobackend: not available") ++func mockCheckVersion(t *testing.T, fn func(string) (bool, bool)) { ++ original := checkVersion ++ t.Cleanup(func() { ++ checkVersion = original ++ }) ++ checkVersion = fn +} + -+type DecapsulationKeyMLKEM1024 struct{} -+type EncapsulationKeyMLKEM1024 struct{} -+ -+func GenerateKeyMLKEM1024() (DecapsulationKeyMLKEM1024, error) { -+ panic("cryptobackend: not available") ++func assertLibrary(t *testing.T, expected string) { ++ if result := library(); result != expected { ++ t.Errorf("expected %s, got %s", expected, result) ++ } +} + -+func NewDecapsulationKeyMLKEM1024(seed []byte) (DecapsulationKeyMLKEM1024, error) { -+ panic("cryptobackend: not available") ++func TestLibraryWithEnvOverride(t *testing.T) { ++ t.Setenv("GO_OPENSSL_VERSION_OVERRIDE", "1.1") ++ mockCheckVersion(t, func(s string) (bool, bool) { return false, false }) ++ assertLibrary(t, "libcrypto.so.1.1") +} + -+func NewEncapsulationKeyMLKEM1024(encapsulationKey []byte) (EncapsulationKeyMLKEM1024, error) { -+ panic("cryptobackend: not available") -+} ++func TestLibraryWithKnownVersion(t *testing.T) { ++ t.Setenv("GO_OPENSSL_VERSION_OVERRIDE", "") + -+func (dk DecapsulationKeyMLKEM1024) Bytes() []byte { -+ panic("cryptobackend: not available") -+} ++ const maxLib = "libcrypto.so.3" + -+func (dk DecapsulationKeyMLKEM1024) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) { -+ panic("cryptobackend: not available") -+} ++ t.Run("AllExistsNoneFIPS", func(t *testing.T) { ++ mockCheckVersion(t, func(s string) (bool, bool) { ++ return true, false ++ }) ++ for _, v := range knownVersions { ++ t.Run(v, func(t *testing.T) { ++ assertLibrary(t, maxLib) ++ }) ++ } ++ }) + -+func (dk DecapsulationKeyMLKEM1024) EncapsulationKey() EncapsulationKeyMLKEM1024 { -+ panic("cryptobackend: not available") -+} ++ t.Run("OnlyOneExists", func(t *testing.T) { ++ for _, v := range knownVersions { ++ t.Run(v, func(t *testing.T) { ++ expected := "libcrypto.so." + v ++ mockCheckVersion(t, func(s string) (bool, bool) { ++ if s == expected { ++ return true, false ++ } ++ return false, false ++ }) ++ assertLibrary(t, expected) ++ }) ++ } ++ }) + -+func (ek EncapsulationKeyMLKEM1024) Bytes() []byte { -+ panic("cryptobackend: not available") ++ t.Run("AllExistsOnlyOneFIPS", func(t *testing.T) { ++ fipsLib := "libcrypto.so.1.1" ++ mockCheckVersion(t, func(s string) (bool, bool) { ++ return true, s == fipsLib ++ }) ++ for _, v := range knownVersions { ++ t.Run(v, func(t *testing.T) { ++ assertLibrary(t, fipsLib) ++ }) ++ } ++ }) ++ ++ t.Run("AllExistsAndAreFIPS", func(t *testing.T) { ++ mockCheckVersion(t, func(s string) (bool, bool) { ++ return true, true ++ }) ++ for _, v := range knownVersions { ++ t.Run(v, func(t *testing.T) { ++ assertLibrary(t, maxLib) ++ }) ++ } ++ }) +} + -+func (ek EncapsulationKeyMLKEM1024) Encapsulate() (sharedKey, ciphertext []byte) { -+ panic("cryptobackend: not available") ++func TestLibraryNoVersionFound(t *testing.T) { ++ t.Setenv("GO_OPENSSL_VERSION_OVERRIDE", "") ++ mockCheckVersion(t, func(string) (bool, bool) { ++ return false, false ++ }) ++ assertLibrary(t, "libcrypto.so") +} +diff --git a/src/crypto/internal/backend/internal/opensslsetup/stub.go b/src/crypto/internal/backend/internal/opensslsetup/stub.go +new file mode 100644 +index 00000000000000..19fd29e19e7b96 +--- /dev/null ++++ b/src/crypto/internal/backend/internal/opensslsetup/stub.go +@@ -0,0 +1,8 @@ ++// Copyright 2025 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. + -+func SupportsChaCha20Poly1305() bool { -+ return false -+} ++// Placeholder to allow the opensslsetup package to be imported ++// without cgo enabled or without goexperiment.systemcrypto on linux. + -+func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) { -+ panic("cryptobackend: not available") -+} -diff --git a/src/crypto/internal/backend/openssl_linux.go b/src/crypto/internal/backend/openssl_linux.go ++package opensslsetup +diff --git a/src/crypto/internal/backend/nobackend.go b/src/crypto/internal/backend/nobackend.go new file mode 100644 -index 00000000000000..ccac6ce8ad0b35 +index 00000000000000..cdc768b1e4b57d --- /dev/null -+++ b/src/crypto/internal/backend/openssl_linux.go -@@ -0,0 +1,430 @@ ++++ b/src/crypto/internal/backend/nobackend.go +@@ -0,0 +1,376 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + -+//go:build goexperiment.systemcrypto ++//go:build !goexperiment.systemcrypto + -+// Package openssl provides access to OpenSSLCrypto implementation functions. -+// Check the variable Enabled to find out whether OpenSSLCrypto is available. -+// If OpenSSLCrypto is not available, the functions in this package all panic. +package backend + +import ( + "crypto" + "crypto/cipher" + "crypto/internal/backend/fips140" -+ _ "crypto/internal/backend/internal/opensslsetup" -+ "crypto/internal/boring/sig" -+ "crypto/internal/fips140only" + "hash" -+ -+ "github.com/golang-fips/openssl/v2" ++ "io" +) + -+// Enabled controls whether FIPS crypto is enabled. -+const Enabled = true -+ -+type BigInt = openssl.BigInt -+ +func init() { -+ // Some distributions, e.g. Azure Linux 3, don't set the `fips=yes` property when running in FIPS mode, -+ // but they configure OpenSSL to use a FIPS-compliant provider (in the case of Azure Linux 3, the SCOSSL provider). -+ // In this cases, openssl.FIPS would return `false` and openssl.FIPSCapable would return `true`. -+ // We don't care about the `fips=yes` property as long as the provider is FIPS-compliant, so use -+ // openssl.FIPSCapable to determine whether FIPS mode is enabled. -+ if err := fips140.Check(func() bool { return openssl.FIPSCapable() }); err != nil { -+ // This path can be reached for the following reasons: -+ // - In OpenSSL 1, the active engine doesn't support FIPS mode. -+ // - In OpenSSL 1, the active engine supports FIPS mode, but it is not enabled. -+ // - In OpenSSL 3, the provider used by default doesn't match the `fips=yes` query. -+ panic("opensslcrypto: " + err.Error() + ": " + openssl.VersionText()) ++ if err := fips140.Check(func() bool { return false }); err != nil { ++ panic(err) + } -+ sig.BoringCrypto() -+ fips140only.BackendApprovedHash = FIPSApprovedHash +} + -+const RandReader = openssl.RandReader ++const Enabled = false + -+func SupportsHash(h crypto.Hash) bool { -+ return openssl.SupportsHash(h) -+} ++type BigInt = []uint + -+func FIPSApprovedHash(h hash.Hash) bool { -+ return openssl.FIPSApprovedHash(h) -+} ++type randReader int + -+func SupportsSHAKE(securityBits int) bool { -+ return openssl.SupportsSHAKE(securityBits) -+} ++func (randReader) Read(b []byte) (int, error) { panic("cryptobackend: not available") } + -+func SupportsCSHAKE(securityBits int) bool { -+ return openssl.SupportsCSHAKE(securityBits) -+} ++const RandReader = randReader(0) + -+func SupportsCurve(curve string) bool { -+ return openssl.SupportsCurve(curve) -+} ++func SupportsHash(h crypto.Hash) bool { panic("cryptobackend: not available") } ++func FIPSApprovedHash(h hash.Hash) bool { panic("cryptobackend: not available") } + -+func SupportsRSAOAEPLabel(label []byte) bool { return true } ++func SupportsSHAKE(securityBits int) bool { panic("cryptobackend: not available") } ++func SupportsCSHAKE(securityBits int) bool { panic("cryptobackend: not available") } + -+func SupportsRSAPKCS1v15Encryption() bool { -+ return openssl.SupportsRSAPKCS1v15Encryption() -+} ++func SupportsCurve(curve string) bool { panic("cryptobackend: not available") } ++func SupportsRSAOAEPLabel(label []byte) bool { panic("cryptobackend: not available") } ++func SupportsRSAPKCS1v15Encryption() bool { panic("cryptobackend: not available") } ++func SupportsRSAPKCS1v15Signature(hash crypto.Hash) bool { panic("cryptobackend: not available") } + -+func SupportsRSAPKCS1v15Signature(hash crypto.Hash) bool { -+ return openssl.SupportsRSAPKCS1v15Signature(hash) ++type Hash struct { ++ hash.Cloner +} + -+type Hash = openssl.Hash -+type SHAKE = openssl.SHAKE -+ -+func NewMD5() hash.Hash { return openssl.NewMD5() } -+func NewSHA1() hash.Hash { return openssl.NewSHA1() } -+func NewSHA224() hash.Hash { return openssl.NewSHA224() } -+func NewSHA256() hash.Hash { return openssl.NewSHA256() } -+func NewSHA384() hash.Hash { return openssl.NewSHA384() } -+func NewSHA512() hash.Hash { return openssl.NewSHA512() } -+func NewSHA512_224() hash.Hash { return openssl.NewSHA512_224() } -+func NewSHA512_256() hash.Hash { return openssl.NewSHA512_256() } -+func NewSHA3_224() *Hash { return openssl.NewSHA3_224() } -+func NewSHA3_256() *Hash { return openssl.NewSHA3_256() } -+func NewSHA3_384() *Hash { return openssl.NewSHA3_384() } -+func NewSHA3_512() *Hash { return openssl.NewSHA3_512() } -+ -+func NewSHAKE128() *SHAKE { return openssl.NewSHAKE128() } -+func NewSHAKE256() *SHAKE { return openssl.NewSHAKE256() } -+func NewCSHAKE128(N, S []byte) *SHAKE { return openssl.NewCSHAKE128(N, S) } -+func NewCSHAKE256(N, S []byte) *SHAKE { return openssl.NewCSHAKE256(N, S) } ++func (d *Hash) MarshalBinary() ([]byte, error) { panic("cryptobackend: not available") } ++func (d *Hash) AppendBinary(p []byte) ([]byte, error) { panic("cryptobackend: not available") } ++func (d *Hash) UnmarshalBinary(data []byte) error { panic("cryptobackend: not available") } + -+func MD5(p []byte) (sum [16]byte) { return openssl.MD5(p) } -+func SHA1(p []byte) (sum [20]byte) { return openssl.SHA1(p) } -+func SHA224(p []byte) (sum [28]byte) { return openssl.SHA224(p) } -+func SHA256(p []byte) (sum [32]byte) { return openssl.SHA256(p) } -+func SHA384(p []byte) (sum [48]byte) { return openssl.SHA384(p) } -+func SHA512(p []byte) (sum [64]byte) { return openssl.SHA512(p) } -+func SHA512_224(p []byte) (sum [28]byte) { return openssl.SHA512_224(p) } -+func SHA512_256(p []byte) (sum [32]byte) { return openssl.SHA512_256(p) } -+func SumSHA3_224(p []byte) (sum [28]byte) { return openssl.SumSHA3_224(p) } -+func SumSHA3_256(p []byte) (sum [32]byte) { return openssl.SumSHA3_256(p) } -+func SumSHA3_384(p []byte) (sum [48]byte) { return openssl.SumSHA3_384(p) } -+func SumSHA3_512(p []byte) (sum [64]byte) { return openssl.SumSHA3_512(p) } ++type SHAKE struct { ++ io.Reader ++ hash.Hash ++} + -+func SumSHAKE128(data []byte, length int) (sum []byte) { return openssl.SumSHAKE128(data, length) } -+func SumSHAKE256(data []byte, length int) (sum []byte) { return openssl.SumSHAKE256(data, length) } ++func (s *SHAKE) MarshalBinary() ([]byte, error) { panic("cryptobackend: not available") } ++func (s *SHAKE) AppendBinary(p []byte) ([]byte, error) { panic("cryptobackend: not available") } ++func (s *SHAKE) UnmarshalBinary(data []byte) error { panic("cryptobackend: not available") } + -+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { return openssl.NewHMAC(h, key) } ++func NewMD5() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA1() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA224() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA256() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA384() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA512() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA512_224() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA512_256() hash.Hash { panic("cryptobackend: not available") } ++func NewSHA3_224() *Hash { panic("cryptobackend: not available") } ++func NewSHA3_256() *Hash { panic("cryptobackend: not available") } ++func NewSHA3_384() *Hash { panic("cryptobackend: not available") } ++func NewSHA3_512() *Hash { panic("cryptobackend: not available") } + -+func NewAESCipher(key []byte) (cipher.Block, error) { return openssl.NewAESCipher(key) } -+func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { return openssl.NewGCMTLS(c) } -+func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { return openssl.NewGCMTLS13(c) } ++func NewSHAKE128() *SHAKE { panic("cryptobackend: not available") } ++func NewSHAKE256() *SHAKE { panic("cryptobackend: not available") } ++func NewCSHAKE128(N, S []byte) *SHAKE { panic("cryptobackend: not available") } ++func NewCSHAKE256(N, S []byte) *SHAKE { panic("cryptobackend: not available") } + -+type PublicKeyECDSA = openssl.PublicKeyECDSA -+type PrivateKeyECDSA = openssl.PrivateKeyECDSA ++func MD5(p []byte) (sum [16]byte) { panic("cryptobackend: not available") } ++func SHA1(p []byte) (sum [20]byte) { panic("cryptobackend: not available") } ++func SHA224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } ++func SHA256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } ++func SHA384(p []byte) (sum [48]byte) { panic("cryptobackend: not available") } ++func SHA512(p []byte) (sum [64]byte) { panic("cryptobackend: not available") } ++func SHA512_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } ++func SHA512_256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } ++func SumSHA3_224(p []byte) (sum [28]byte) { panic("cryptobackend: not available") } ++func SumSHA3_256(p []byte) (sum [32]byte) { panic("cryptobackend: not available") } ++func SumSHA3_384(p []byte) (sum [48]byte) { panic("cryptobackend: not available") } ++func SumSHA3_512(p []byte) (sum [64]byte) { panic("cryptobackend: not available") } + -+func GenerateKeyECDSA(curve string) (X, Y, D openssl.BigInt, err error) { -+ return openssl.GenerateKeyECDSA(curve) -+} ++func SumSHAKE128(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } ++func SumSHAKE256(data []byte, length int) (sum []byte) { panic("cryptobackend: not available") } + -+func NewPrivateKeyECDSA(curve string, X, Y, D openssl.BigInt) (*openssl.PrivateKeyECDSA, error) { -+ return openssl.NewPrivateKeyECDSA(curve, X, Y, D) -+} ++func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("cryptobackend: not available") } + -+func NewPublicKeyECDSA(curve string, X, Y openssl.BigInt) (*openssl.PublicKeyECDSA, error) { -+ return openssl.NewPublicKeyECDSA(curve, X, Y) -+} ++func NewAESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") } ++func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { panic("cryptobackend: not available") } ++func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) { panic("cryptobackend: not available") } + -+func SignMarshalECDSA(priv *openssl.PrivateKeyECDSA, hash []byte) ([]byte, error) { -+ return openssl.SignMarshalECDSA(priv, hash) -+} ++type PublicKeyECDSA struct{ _ int } ++type PrivateKeyECDSA struct{ _ int } + -+func VerifyECDSA(pub *openssl.PublicKeyECDSA, hash []byte, sig []byte) bool { -+ return openssl.VerifyECDSA(pub, hash, sig) ++func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) { ++ panic("cryptobackend: not available") +} -+ -+func SupportsRSAPrivateKey(bits, primes int) bool { -+ // The built-in OpenSSL 3 providers and OpenSSL 1 do support n-prime RSA keys, -+ // but SCOSSL only supports 2-prime RSA keys. -+ // Only 2-prime RSA keys are FIPS compliant, other n having compatibility -+ // and security issues. Even crypto/rsa deprecated rsa.GenerateMultiPrimeKey as of Go 1.21. -+ // Given the above reasons, we only support what SCOSSL supports. -+ return primes == 2 && SupportsRSAPublicKey(bits) ++func NewPrivateKeyECDSA(curve string, X, Y, D BigInt) (*PrivateKeyECDSA, error) { ++ panic("cryptobackend: not available") +} -+ -+func SupportsRSAPublicKey(bits int) bool { -+ min := 1024 -+ if fips140.Enabled() { -+ // The built-in OpenSSL 3 FIPS provider requires at least 2048 bits for FIPS compliance. -+ min = 2048 -+ } -+ return bits >= min && bits%8 == 0 && bits <= 16384 ++func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) { ++ panic("cryptobackend: not available") +} -+ -+func SupportsRSASaltLength(sign bool, salt int) bool { -+ return true ++func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+type PublicKeyRSA = openssl.PublicKeyRSA -+type PrivateKeyRSA = openssl.PrivateKeyRSA -+ -+func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *openssl.PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { -+ return openssl.DecryptRSAOAEP(h, mgfHash, priv, ciphertext, label) ++func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool { ++ panic("cryptobackend: not available") +} ++func SupportsRSAPrivateKey(bits, primes int) bool { panic("cryptobackend: not available") } ++func SupportsRSAPublicKey(bits int) bool { panic("cryptobackend: not available") } ++func SupportsRSASaltLength(sign bool, salt int) bool { panic("cryptobackend: not available") } + -+func DecryptRSAPKCS1(priv *openssl.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ return openssl.DecryptRSAPKCS1(priv, ciphertext) -+} ++type PublicKeyRSA struct{ _ int } ++type PrivateKeyRSA struct{ _ int } + -+func DecryptRSANoPadding(priv *openssl.PrivateKeyRSA, ciphertext []byte) ([]byte, error) { -+ return openssl.DecryptRSANoPadding(priv, ciphertext) ++func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *openssl.PublicKeyRSA, msg, label []byte) ([]byte, error) { -+ return openssl.EncryptRSAOAEP(h, mgfHash, pub, msg, label) ++func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func EncryptRSAPKCS1(pub *openssl.PublicKeyRSA, msg []byte) ([]byte, error) { -+ return openssl.EncryptRSAPKCS1(pub, msg) ++func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func EncryptRSANoPadding(pub *openssl.PublicKeyRSA, msg []byte) ([]byte, error) { -+ return openssl.EncryptRSANoPadding(pub, msg) ++func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv openssl.BigInt, err error) { -+ return openssl.GenerateKeyRSA(bits) ++func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv openssl.BigInt) (*openssl.PrivateKeyRSA, error) { -+ return openssl.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv) ++func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func NewPublicKeyRSA(N, E openssl.BigInt) (*openssl.PublicKeyRSA, error) { -+ return openssl.NewPublicKeyRSA(N, E) ++func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { ++ panic("cryptobackend: not available") +} -+ -+func SignRSAPKCS1v15(priv *openssl.PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { -+ return openssl.SignRSAPKCS1v15(priv, h, hashed) ++func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) { ++ panic("cryptobackend: not available") +} -+ -+func SignRSAPSS(priv *openssl.PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { -+ return openssl.SignRSAPSS(priv, h, hashed, saltLen) ++func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { ++ panic("cryptobackend: not available") +} -+ -+func VerifyRSAPKCS1v15(pub *openssl.PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { -+ return openssl.VerifyRSAPKCS1v15(pub, h, hashed, sig) ++func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+func VerifyRSAPSS(pub *openssl.PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { -+ return openssl.VerifyRSAPSS(pub, h, hashed, sig, saltLen) ++func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { ++ panic("cryptobackend: not available") +} -+ -+type PublicKeyECDH = openssl.PublicKeyECDH -+type PrivateKeyECDH = openssl.PrivateKeyECDH -+ -+func ECDH(priv *openssl.PrivateKeyECDH, pub *openssl.PublicKeyECDH) ([]byte, error) { -+ return openssl.ECDH(priv, pub) ++func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { ++ panic("cryptobackend: not available") +} -+ -+func GenerateKeyECDH(curve string) (*openssl.PrivateKeyECDH, []byte, error) { -+ return openssl.GenerateKeyECDH(curve) ++func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { ++ panic("cryptobackend: not available") +} + -+func NewPrivateKeyECDH(curve string, bytes []byte) (*openssl.PrivateKeyECDH, error) { -+ return openssl.NewPrivateKeyECDH(curve, bytes) -+} ++type PublicKeyECDH struct{} ++type PrivateKeyECDH struct{} + -+func NewPublicKeyECDH(curve string, bytes []byte) (*openssl.PublicKeyECDH, error) { -+ return openssl.NewPublicKeyECDH(curve, bytes) ++func ECDH(*PrivateKeyECDH, *PublicKeyECDH) ([]byte, error) { panic("cryptobackend: not available") } ++func GenerateKeyECDH(string) (*PrivateKeyECDH, []byte, error) { panic("cryptobackend: not available") } ++func NewPrivateKeyECDH(string, []byte) (*PrivateKeyECDH, error) { ++ panic("cryptobackend: not available") +} ++func NewPublicKeyECDH(string, []byte) (*PublicKeyECDH, error) { panic("cryptobackend: not available") } ++func (*PublicKeyECDH) Bytes() []byte { panic("cryptobackend: not available") } ++func (*PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { panic("cryptobackend: not available") } + -+func SupportsTLS13KDF() bool { -+ return openssl.SupportsTLS13KDF() -+} ++func SupportsTLS13KDF() bool { panic("cryptobackend: not available") } + +func ExpandTLS13KDF(h func() hash.Hash, pseudorandomKey, label, context []byte, keyLength int) ([]byte, error) { -+ return openssl.ExpandTLS13KDF(h, pseudorandomKey, label, context, keyLength) ++ panic("cryptobackend: not available") +} + -+func SupportsHKDF() bool { -+ return openssl.SupportsHKDF() -+} ++func SupportsHKDF() bool { panic("cryptobackend: not available") } + +func ExpandHKDF(h func() hash.Hash, pseudorandomKey, info []byte, keyLength int) ([]byte, error) { -+ return openssl.ExpandHKDFOneShot(h, pseudorandomKey, info, keyLength) ++ panic("cryptobackend: not available") +} + +func ExtractHKDF(h func() hash.Hash, secret, salt []byte) ([]byte, error) { -+ return openssl.ExtractHKDF(h, secret, salt) ++ panic("cryptobackend: not available") +} + -+func SupportsPBKDF2() bool { -+ return openssl.SupportsPBKDF2() -+} ++func SupportsPBKDF2() bool { panic("cryptobackend: not available") } + -+func PBKDF2(pass, salt []byte, iter, keyLen int, h func() hash.Hash) ([]byte, error) { -+ return openssl.PBKDF2(pass, salt, iter, keyLen, h) ++func PBKDF2(password, salt []byte, iter, keyLen int, fh func() hash.Hash) ([]byte, error) { ++ panic("cryptobackend: not available") +} + -+func SupportsTLS1PRF() bool { -+ return openssl.SupportsTLS1PRF() -+} ++func SupportsTLS1PRF() bool { panic("cryptobackend: not available") } + +func TLS1PRF(result, secret, label, seed []byte, h func() hash.Hash) error { -+ return openssl.TLS1PRF(result, secret, label, seed, h) ++ panic("cryptobackend: not available") +} + -+func SupportsDESCipher() bool { -+ return openssl.SupportsDESCipher() -+} ++func SupportsDESCipher() bool { panic("cryptobackend: not available") } + -+func SupportsTripleDESCipher() bool { -+ return openssl.SupportsTripleDESCipher() -+} ++func SupportsTripleDESCipher() bool { panic("cryptobackend: not available") } + -+func NewDESCipher(key []byte) (cipher.Block, error) { -+ return openssl.NewDESCipher(key) -+} ++func NewDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") } + -+func NewTripleDESCipher(key []byte) (cipher.Block, error) { -+ return openssl.NewTripleDESCipher(key) -+} ++func NewTripleDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") } + -+func SupportsRC4() bool { -+ return openssl.SupportsRC4() -+} ++func SupportsRC4() bool { panic("cryptobackend: not available") } + -+type RC4Cipher = openssl.RC4Cipher ++type RC4Cipher struct{} + -+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return openssl.NewRC4Cipher(key) } ++func (c *RC4Cipher) Reset() { panic("cryptobackend: not available") } ++func (c *RC4Cipher) XORKeyStream(dst, src []byte) { panic("cryptobackend: not available") } + -+func SupportsEd25519() bool { return openssl.SupportsEd25519() } ++func NewRC4Cipher(key []byte) (*RC4Cipher, error) { panic("cryptobackend: not available") } + -+type PublicKeyEd25519 = *openssl.PublicKeyEd25519 -+type PrivateKeyEd25519 = *openssl.PrivateKeyEd25519 ++func SupportsEd25519() bool { panic("cryptobackend: not available") } + -+func GenerateKeyEd25519() (PrivateKeyEd25519, error) { -+ return openssl.GenerateKeyEd25519() ++type PublicKeyEd25519 struct{} ++ ++func (k PublicKeyEd25519) Bytes() ([]byte, error) { ++ panic("cryptobackend: not available") +} + -+// Deprecated: use NewPrivateKeyEd25519 instead. -+func NewPrivateKeyEd25119(priv []byte) (PrivateKeyEd25519, error) { -+ return openssl.NewPrivateKeyEd25519(priv) ++type PrivateKeyEd25519 struct{} ++ ++func (k PrivateKeyEd25519) Bytes() ([]byte, error) { ++ panic("cryptobackend: not available") +} + -+// Deprecated: use NewPublicKeyEd25519 instead. -+func NewPublicKeyEd25119(pub []byte) (PublicKeyEd25519, error) { -+ return openssl.NewPublicKeyEd25519(pub) ++func GenerateKeyEd25519() (PrivateKeyEd25519, error) { ++ panic("cryptobackend: not available") +} + +func NewPrivateKeyEd25519(priv []byte) (PrivateKeyEd25519, error) { -+ return openssl.NewPrivateKeyEd25519(priv) ++ panic("cryptobackend: not available") +} + +func NewPublicKeyEd25519(pub []byte) (PublicKeyEd25519, error) { -+ return openssl.NewPublicKeyEd25519(pub) ++ panic("cryptobackend: not available") +} + +func NewPrivateKeyEd25519FromSeed(seed []byte) (PrivateKeyEd25519, error) { -+ return openssl.NewPrivateKeyEd25519FromSeed(seed) ++ panic("cryptobackend: not available") +} + +func SignEd25519(priv PrivateKeyEd25519, message []byte) ([]byte, error) { -+ return openssl.SignEd25519(priv, message) ++ panic("cryptobackend: not available") +} + +func VerifyEd25519(pub PublicKeyEd25519, message, sig []byte) error { -+ return openssl.VerifyEd25519(pub, message, sig) ++ panic("cryptobackend: not available") +} + -+type PublicKeyDSA = openssl.PublicKeyDSA -+type PrivateKeyDSA = openssl.PrivateKeyDSA -+ +func SupportsDSA(l, n int) bool { -+ return openssl.SupportsDSA() ++ panic("cryptobackend: not available") +} + -+func GenerateParametersDSA(l, n int) (p, q, g openssl.BigInt, err error) { -+ params, err := openssl.GenerateParametersDSA(l, n) -+ return params.P, params.Q, params.G, err ++func GenerateParametersDSA(l, n int) (p, q, g BigInt, err error) { ++ panic("cryptobackend: not available") +} + -+func GenerateKeyDSA(p, q, g openssl.BigInt) (x, y openssl.BigInt, err error) { -+ return openssl.GenerateKeyDSA(openssl.DSAParameters{P: p, Q: q, G: g}) -+} ++type PublicKeyDSA struct{ _ int } ++type PrivateKeyDSA struct{ _ int } + -+func NewPrivateKeyDSA(p, q, g, x, y openssl.BigInt) (*openssl.PrivateKeyDSA, error) { -+ return openssl.NewPrivateKeyDSA(openssl.DSAParameters{P: p, Q: q, G: g}, x, y) ++func GenerateKeyDSA(p, q, g BigInt) (x, y BigInt, err error) { ++ panic("cryptobackend: not available") +} + -+func NewPublicKeyDSA(p, q, g, y openssl.BigInt) (*openssl.PublicKeyDSA, error) { -+ return openssl.NewPublicKeyDSA(openssl.DSAParameters{P: p, Q: q, G: g}, y) ++func NewPrivateKeyDSA(p, q, g, x, y BigInt) (*PrivateKeyDSA, error) { ++ panic("cryptobackend: not available") +} + -+func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (openssl.BigInt, openssl.BigInt, error)) (r, s openssl.BigInt, err error) { -+ sig, err := openssl.SignDSA(priv, hash) -+ if err != nil { -+ return nil, nil, err -+ } -+ -+ r, s, err = parseSignature(sig) -+ if err != nil { -+ return nil, nil, err -+ } -+ -+ return openssl.BigInt(r), openssl.BigInt(s), nil ++func NewPublicKeyDSA(p, q, g, y BigInt) (*PublicKeyDSA, error) { ++ panic("cryptobackend: not available") +} + -+func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s openssl.BigInt, encodeSignature func(r, s openssl.BigInt) ([]byte, error)) bool { -+ sig, err := encodeSignature(r, s) -+ if err != nil { -+ return false -+ } ++func SignDSA(priv *PrivateKeyDSA, hash []byte, parseSignature func([]byte) (BigInt, BigInt, error)) (r, s BigInt, err error) { ++ panic("cryptobackend: not available") ++} + -+ return openssl.VerifyDSA(pub, hashed, sig) ++func VerifyDSA(pub *PublicKeyDSA, hashed []byte, r, s BigInt, encodeSignature func(r, s BigInt) ([]byte, error)) bool { ++ panic("cryptobackend: not available") +} + +func SupportsMLKEM768() bool { -+ return openssl.SupportsMLKEM768() ++ panic("cryptobackend: not available") +} + +func SupportsMLKEM1024() bool { -+ return openssl.SupportsMLKEM1024() ++ panic("cryptobackend: not available") +} + -+type DecapsulationKeyMLKEM768 = openssl.DecapsulationKeyMLKEM768 -+type EncapsulationKeyMLKEM768 = openssl.EncapsulationKeyMLKEM768 ++type DecapsulationKeyMLKEM768 struct{} ++type EncapsulationKeyMLKEM768 struct{} + +func GenerateKeyMLKEM768() (DecapsulationKeyMLKEM768, error) { -+ return openssl.GenerateKeyMLKEM768() ++ panic("cryptobackend: not available") +} + +func NewDecapsulationKeyMLKEM768(seed []byte) (DecapsulationKeyMLKEM768, error) { -+ return openssl.NewDecapsulationKeyMLKEM768(seed) ++ panic("cryptobackend: not available") +} + +func NewEncapsulationKeyMLKEM768(encapsulationKey []byte) (EncapsulationKeyMLKEM768, error) { -+ return openssl.NewEncapsulationKeyMLKEM768(encapsulationKey) ++ panic("cryptobackend: not available") +} + -+type DecapsulationKeyMLKEM1024 = openssl.DecapsulationKeyMLKEM1024 -+type EncapsulationKeyMLKEM1024 = openssl.EncapsulationKeyMLKEM1024 ++func (dk DecapsulationKeyMLKEM768) Bytes() []byte { ++ panic("cryptobackend: not available") ++} ++ ++func (dk DecapsulationKeyMLKEM768) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) { ++ panic("cryptobackend: not available") ++} ++ ++func (dk DecapsulationKeyMLKEM768) EncapsulationKey() EncapsulationKeyMLKEM768 { ++ panic("cryptobackend: not available") ++} ++ ++func (ek EncapsulationKeyMLKEM768) Bytes() []byte { ++ panic("cryptobackend: not available") ++} ++ ++func (ek EncapsulationKeyMLKEM768) Encapsulate() (sharedKey, ciphertext []byte) { ++ panic("cryptobackend: not available") ++} ++ ++type DecapsulationKeyMLKEM1024 struct{} ++type EncapsulationKeyMLKEM1024 struct{} + +func GenerateKeyMLKEM1024() (DecapsulationKeyMLKEM1024, error) { -+ return openssl.GenerateKeyMLKEM1024() ++ panic("cryptobackend: not available") +} + +func NewDecapsulationKeyMLKEM1024(seed []byte) (DecapsulationKeyMLKEM1024, error) { -+ return openssl.NewDecapsulationKeyMLKEM1024(seed) ++ panic("cryptobackend: not available") +} + +func NewEncapsulationKeyMLKEM1024(encapsulationKey []byte) (EncapsulationKeyMLKEM1024, error) { -+ return openssl.NewEncapsulationKeyMLKEM1024(encapsulationKey) ++ panic("cryptobackend: not available") ++} ++ ++func (dk DecapsulationKeyMLKEM1024) Bytes() []byte { ++ panic("cryptobackend: not available") ++} ++ ++func (dk DecapsulationKeyMLKEM1024) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) { ++ panic("cryptobackend: not available") ++} ++ ++func (dk DecapsulationKeyMLKEM1024) EncapsulationKey() EncapsulationKeyMLKEM1024 { ++ panic("cryptobackend: not available") ++} ++ ++func (ek EncapsulationKeyMLKEM1024) Bytes() []byte { ++ panic("cryptobackend: not available") ++} ++ ++func (ek EncapsulationKeyMLKEM1024) Encapsulate() (sharedKey, ciphertext []byte) { ++ panic("cryptobackend: not available") +} + +func SupportsChaCha20Poly1305() bool { -+ return openssl.SupportsChaCha20Poly1305() ++ return false +} + +func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) { -+ return openssl.NewChaCha20Poly1305(key) ++ panic("cryptobackend: not available") +} diff --git a/src/crypto/internal/backend/stub.s b/src/crypto/internal/backend/stub.s new file mode 100644 @@ -3138,7 +3138,7 @@ index 00000000000000..5e4b436554d44d +// (because the implementation might be here). diff --git a/src/crypto/systemcrypto_nocgo_linux.go b/src/crypto/systemcrypto_nocgo_linux.go new file mode 100644 -index 00000000000000..1461a5f75b3b06 +index 00000000000000..7500bd3a86472b --- /dev/null +++ b/src/crypto/systemcrypto_nocgo_linux.go @@ -0,0 +1,18 @@ diff --git a/patches/0004-Use-crypto-backends.patch b/patches/0004-Use-crypto-backends.patch index 246e933bf0..0b7842f8f7 100644 --- a/patches/0004-Use-crypto-backends.patch +++ b/patches/0004-Use-crypto-backends.patch @@ -67,13 +67,13 @@ Subject: [PATCH] Use crypto backends src/crypto/rc4/rc4.go | 18 ++ src/crypto/rsa/boring.go | 13 +- src/crypto/rsa/boring_test.go | 2 +- - src/crypto/rsa/darwin_darwin.go | 71 +++++++ src/crypto/rsa/fips.go | 84 ++++---- src/crypto/rsa/notboring.go | 4 +- src/crypto/rsa/pkcs1v15.go | 10 +- src/crypto/rsa/pkcs1v15_test.go | 5 + src/crypto/rsa/pss_test.go | 14 +- src/crypto/rsa/rsa.go | 29 +-- + src/crypto/rsa/rsa_darwin.go | 71 +++++++ src/crypto/rsa/rsa_test.go | 7 +- src/crypto/sha1/sha1.go | 11 +- src/crypto/sha1/sha1_test.go | 11 +- @@ -109,7 +109,7 @@ Subject: [PATCH] Use crypto backends create mode 100644 src/crypto/ecdsa/badlinkname.go create mode 100644 src/crypto/ed25519/boring.go create mode 100644 src/crypto/ed25519/notboring.go - create mode 100644 src/crypto/rsa/darwin_darwin.go + create mode 100644 src/crypto/rsa/rsa_darwin.go create mode 100644 src/crypto/tls/internal/tls13/doc.go create mode 100644 src/crypto/tls/internal/tls13/tls13.go create mode 100644 src/hash/boring_test.go @@ -2564,83 +2564,6 @@ index 838fcc1244bdbe..d89f732345e8a3 100644 // Note: Can run these tests against the non-BoringCrypto // version of the code by using "CGO_ENABLED=0 go test". -diff --git a/src/crypto/rsa/darwin_darwin.go b/src/crypto/rsa/darwin_darwin.go -new file mode 100644 -index 00000000000000..bff8ac449c9a3b ---- /dev/null -+++ b/src/crypto/rsa/darwin_darwin.go -@@ -0,0 +1,71 @@ -+// Copyright 2017 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+//go:build goexperiment.systemcrypto -+ -+package rsa -+ -+import ( -+ "crypto/internal/backend" -+ "crypto/internal/backend/bbig" -+ "errors" -+ "math/big" -+ _ "unsafe" -+ -+ "golang.org/x/crypto/cryptobyte" -+ "golang.org/x/crypto/cryptobyte/asn1" -+) -+ -+//go:linkname decodeKey -+func decodeKey(data []byte) (N, E, D, P, Q, Dp, Dq, Qinv backend.BigInt, err error) { -+ bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv backend.BigInt, err error) { -+ return nil, nil, nil, nil, nil, nil, nil, nil, e -+ } -+ input := cryptobyte.String(data) -+ var version int -+ n, e, d, p, q, dp, dq, qinv := new(big.Int), new(big.Int), new(big.Int), new(big.Int), -+ new(big.Int), new(big.Int), new(big.Int), new(big.Int) -+ // Parse the ASN.1 sequence -+ if !input.ReadASN1(&input, asn1.SEQUENCE) { -+ return bad(errors.New("invalid ASN.1 structure: not a sequence")) -+ } -+ if !input.ReadASN1Integer(&version) || version != 0 { -+ return bad(errors.New("invalid ASN.1 structure: unsupported version")) -+ } -+ if !input.ReadASN1Integer(n) || !input.ReadASN1Integer(e) || -+ !input.ReadASN1Integer(d) || !input.ReadASN1Integer(p) || -+ !input.ReadASN1Integer(q) || !input.ReadASN1Integer(dp) || -+ !input.ReadASN1Integer(dq) || !input.ReadASN1Integer(qinv) { -+ return bad(errors.New("invalid ASN.1 structure")) -+ } -+ return bbig.Enc(n), bbig.Enc(e), bbig.Enc(d), bbig.Enc(p), bbig.Enc(q), -+ bbig.Enc(dp), bbig.Enc(dq), bbig.Enc(qinv), nil -+} -+ -+//go:linkname encodeKey -+func encodeKey(N, E, D, P, Q, Dp, Dq, Qinv backend.BigInt) ([]byte, error) { -+ builder := cryptobyte.NewBuilder(nil) -+ builder.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { -+ b.AddASN1Int64(0) // Add version as int64 -+ b.AddASN1BigInt(bbig.Dec(N)) // Add modulus -+ b.AddASN1BigInt(bbig.Dec(E)) // Add public exponent -+ b.AddASN1BigInt(bbig.Dec(D)) // Add private exponent -+ b.AddASN1BigInt(bbig.Dec(P)) // Add prime1 -+ b.AddASN1BigInt(bbig.Dec(Q)) // Add prime2 -+ b.AddASN1BigInt(bbig.Dec(Dp)) // Add exponent1 -+ b.AddASN1BigInt(bbig.Dec(Dq)) // Add exponent2 -+ b.AddASN1BigInt(bbig.Dec(Qinv)) // Add coefficient -+ }) -+ return builder.Bytes() -+} -+ -+//go:linkname encodePublicKey -+func encodePublicKey(N, E backend.BigInt) ([]byte, error) { -+ builder := cryptobyte.NewBuilder(nil) -+ builder.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { -+ b.AddASN1BigInt(bbig.Dec(N)) // Add modulus -+ b.AddASN1BigInt(bbig.Dec(E)) // Add public exponent -+ }) -+ return builder.Bytes() -+} diff --git a/src/crypto/rsa/fips.go b/src/crypto/rsa/fips.go index fb2395886b053b..18334e731f9349 100644 --- a/src/crypto/rsa/fips.go @@ -3020,6 +2943,83 @@ index b94b129867727b..149dd4321f8d72 100644 if fips140only.Enforced() && !fips140only.ApprovedRandomReader(random) { return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") } +diff --git a/src/crypto/rsa/rsa_darwin.go b/src/crypto/rsa/rsa_darwin.go +new file mode 100644 +index 00000000000000..b549c6e3b17484 +--- /dev/null ++++ b/src/crypto/rsa/rsa_darwin.go +@@ -0,0 +1,71 @@ ++// Copyright 2017 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build goexperiment.systemcrypto ++ ++package rsa ++ ++import ( ++ "crypto/internal/backend" ++ "crypto/internal/backend/bbig" ++ "errors" ++ "math/big" ++ _ "unsafe" ++ ++ "golang.org/x/crypto/cryptobyte" ++ "golang.org/x/crypto/cryptobyte/asn1" ++) ++ ++//go:linkname decodeKey ++func decodeKey(data []byte) (N, E, D, P, Q, Dp, Dq, Qinv backend.BigInt, err error) { ++ bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv backend.BigInt, err error) { ++ return nil, nil, nil, nil, nil, nil, nil, nil, e ++ } ++ input := cryptobyte.String(data) ++ var version int ++ n, e, d, p, q, dp, dq, qinv := new(big.Int), new(big.Int), new(big.Int), new(big.Int), ++ new(big.Int), new(big.Int), new(big.Int), new(big.Int) ++ // Parse the ASN.1 sequence ++ if !input.ReadASN1(&input, asn1.SEQUENCE) { ++ return bad(errors.New("invalid ASN.1 structure: not a sequence")) ++ } ++ if !input.ReadASN1Integer(&version) || version != 0 { ++ return bad(errors.New("invalid ASN.1 structure: unsupported version")) ++ } ++ if !input.ReadASN1Integer(n) || !input.ReadASN1Integer(e) || ++ !input.ReadASN1Integer(d) || !input.ReadASN1Integer(p) || ++ !input.ReadASN1Integer(q) || !input.ReadASN1Integer(dp) || ++ !input.ReadASN1Integer(dq) || !input.ReadASN1Integer(qinv) { ++ return bad(errors.New("invalid ASN.1 structure")) ++ } ++ return bbig.Enc(n), bbig.Enc(e), bbig.Enc(d), bbig.Enc(p), bbig.Enc(q), ++ bbig.Enc(dp), bbig.Enc(dq), bbig.Enc(qinv), nil ++} ++ ++//go:linkname encodeKey ++func encodeKey(N, E, D, P, Q, Dp, Dq, Qinv backend.BigInt) ([]byte, error) { ++ builder := cryptobyte.NewBuilder(nil) ++ builder.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { ++ b.AddASN1Int64(0) // Add version as int64 ++ b.AddASN1BigInt(bbig.Dec(N)) // Add modulus ++ b.AddASN1BigInt(bbig.Dec(E)) // Add public exponent ++ b.AddASN1BigInt(bbig.Dec(D)) // Add private exponent ++ b.AddASN1BigInt(bbig.Dec(P)) // Add prime1 ++ b.AddASN1BigInt(bbig.Dec(Q)) // Add prime2 ++ b.AddASN1BigInt(bbig.Dec(Dp)) // Add exponent1 ++ b.AddASN1BigInt(bbig.Dec(Dq)) // Add exponent2 ++ b.AddASN1BigInt(bbig.Dec(Qinv)) // Add coefficient ++ }) ++ return builder.Bytes() ++} ++ ++//go:linkname encodePublicKey ++func encodePublicKey(N, E backend.BigInt) ([]byte, error) { ++ builder := cryptobyte.NewBuilder(nil) ++ builder.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { ++ b.AddASN1BigInt(bbig.Dec(N)) // Add modulus ++ b.AddASN1BigInt(bbig.Dec(E)) // Add public exponent ++ }) ++ return builder.Bytes() ++} diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 124fba1e8a4faa..af6d8e9291af62 100644 --- a/src/crypto/rsa/rsa_test.go