From 1482a539beae92f68fa36ef9fafeec4a39272115 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 8 Oct 2026 12:36:31 +0200 Subject: [PATCH] crypto: move Ed25519 fallback to cryptobackend Move Ed25519 native dispatch, key handling, and lazy Go fallbacks into cryptobackend. Keep the standard-library integration close to upstream and use core aliases for Go-only builds. Preserve mutable key encodings, deterministic crypto.Signer behavior, and allocation tests. Keep provider capability checks and propagate native operation errors without retrying through Go. Updates #2489. --- cryptobackend/ed25519/ed25519_darwin.go | 20 +- cryptobackend/ed25519/ed25519_msgostd.go | 239 +++++++ .../ed25519/ed25519_nobackend_msgostd.go | 62 ++ cryptobackend/ed25519/ed25519_nomsgostd.go | 41 ++ cryptobackend/ed25519/ed25519_openssl.go | 23 +- cryptobackend/ed25519/ed25519_windows.go | 26 +- cryptobackend/ed25519/init.go | 7 - cryptobackend/ed25519/key.go | 110 ++++ cryptobackend/ed25519/nobackend.go | 26 +- .../0001-Vendor-external-dependencies.patch | 604 ++++++++++++++++-- patches/0002-Add-crypto-backends.patch | 298 ++------- 11 files changed, 1120 insertions(+), 336 deletions(-) create mode 100644 cryptobackend/ed25519/ed25519_msgostd.go create mode 100644 cryptobackend/ed25519/ed25519_nobackend_msgostd.go create mode 100644 cryptobackend/ed25519/ed25519_nomsgostd.go delete mode 100644 cryptobackend/ed25519/init.go create mode 100644 cryptobackend/ed25519/key.go diff --git a/cryptobackend/ed25519/ed25519_darwin.go b/cryptobackend/ed25519/ed25519_darwin.go index 339ad263058..531f32a908d 100644 --- a/cryptobackend/ed25519/ed25519_darwin.go +++ b/cryptobackend/ed25519/ed25519_darwin.go @@ -8,17 +8,19 @@ package ed25519 import "github.com/microsoft/go-crypto-darwin/xcrypto" -type PrivateKey = xcrypto.PrivateKeyEd25519 -type PublicKey = xcrypto.PublicKeyEd25519 +type backendPrivateKey = xcrypto.PrivateKeyEd25519 +type backendPublicKey = xcrypto.PublicKeyEd25519 -func Supports() bool { return true } -func GenerateKey() (PrivateKey, error) { return xcrypto.GenerateKeyEd25519(), nil } -func NewPrivateKey(priv []byte) (PrivateKey, error) { return xcrypto.NewPrivateKeyEd25519(priv) } -func NewPublicKey(pub []byte) (PublicKey, error) { return xcrypto.NewPublicKeyEd25519(pub) } -func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { +func Supports() bool { return true } +func generateKey() (backendPrivateKey, error) { return xcrypto.GenerateKeyEd25519(), nil } +func newPrivateKey(priv []byte) (backendPrivateKey, error) { return xcrypto.NewPrivateKeyEd25519(priv) } +func newPublicKey(pub []byte) (backendPublicKey, error) { return xcrypto.NewPublicKeyEd25519(pub) } +func newPrivateKeyFromSeed(seed []byte) (backendPrivateKey, error) { return xcrypto.NewPrivateKeyEd25519FromSeed(seed) } -func Sign(priv PrivateKey, message []byte) ([]byte, error) { return xcrypto.SignEd25519(priv, message) } -func Verify(pub PublicKey, message, sig []byte) error { +func sign(priv backendPrivateKey, message []byte) ([]byte, error) { + return xcrypto.SignEd25519(priv, message) +} +func verify(pub backendPublicKey, message, sig []byte) error { return xcrypto.VerifyEd25519(pub, message, sig) } diff --git a/cryptobackend/ed25519/ed25519_msgostd.go b/cryptobackend/ed25519/ed25519_msgostd.go new file mode 100644 index 00000000000..de40c80c45f --- /dev/null +++ b/cryptobackend/ed25519/ed25519_msgostd.go @@ -0,0 +1,239 @@ +// Copyright 2026 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 && !windows && (msgostd || cmd_go_bootstrap) + +package ed25519 + +import ( + "crypto/internal/boring/bcache" + fallback "crypto/internal/fips140/ed25519" + "crypto/internal/fips140/edwards25519" + "crypto/internal/rand" + cryptorand "crypto/rand" + "crypto/subtle" + "errors" + "strconv" +) + +type fipsPrivateKey = fallback.PrivateKey +type fipsPublicKey = fallback.PublicKey + +func GenerateKey() (key *PrivateKey, err error) { + var k PrivateKey + err = generate(&k) + if err == nil { + key = &k + } + return +} + +func generate(k *PrivateKey) error { + if supportsBackend() && rand.IsDefaultReader(cryptorand.Reader) { + key, err := generateKey() + if err != nil { + return err + } + return initBackendPrivateKey(k, key) + } + key, err := fallback.GenerateKey() + if err != nil { + return err + } + k.fips, k.encoding = key, [64]byte(key.Bytes()) + return nil +} + +func NewPrivateKeyFromSeed(seed []byte) (key *PrivateKey, err error) { + var k PrivateKey + err = newPrivateFromSeed(&k, seed) + if err == nil { + key = &k + } + return +} + +func newPrivateFromSeed(k *PrivateKey, seed []byte) error { + if len(seed) != 32 { + return errors.New("ed25519: bad seed length: " + strconv.Itoa(len(seed))) + } + if supportsBackend() { + key, err := newPrivateKeyFromSeed(seed) + if err != nil { + return err + } + return initBackendPrivateKey(k, key) + } + key, err := fallback.NewPrivateKeyFromSeed(seed) + if err != nil { + return err + } + k.fips, k.encoding = key, [64]byte(key.Bytes()) + return nil +} + +func NewPrivateKey(encoding []byte) (*PrivateKey, error) { + if len(encoding) != 64 { + return nil, errors.New("ed25519: bad private key length: " + strconv.Itoa(len(encoding))) + } + if supportsBackend() { + key, err := newPrivateKey(encoding) + if err != nil { + return nil, err + } + k := new(PrivateKey) + if err := initBackendPrivateKey(k, key); err != nil { + return nil, err + } + // Native importers derive the public suffix from the seed. Go signing + // uses the supplied suffix, even when it does not match that seed. + if subtle.ConstantTimeCompare(encoding, k.encoding[:]) == 1 { + return k, nil + } + } + key, err := fallback.NewPrivateKey(encoding) + if err != nil { + return nil, err + } + return &PrivateKey{fips: key, encoding: [64]byte(encoding)}, nil +} + +func initBackendPrivateKey(k *PrivateKey, key backendPrivateKey) error { + encoding, err := key.Bytes() + if err != nil { + return err + } + if len(encoding) != 64 { + return errors.New("ed25519: invalid backend private key length") + } + k.backend = key + copy(k.encoding[:], encoding) + return nil +} + +// Preserve the native public-key cache's GC-based eviction. Each cached key +// holds its own immutable encoding, so input mutations invalidate the entry. +var publicKeyCache bcache.Cache[byte, PublicKey] + +func init() { + if supportsBackend() { + publicKeyCache.Register() + } +} + +func NewPublicKey(encoding []byte) (key *PublicKey, err error) { + var k PublicKey + err = importPublicKey(&k, encoding) + if err == nil { + key = &k + } + return +} + +func importPublicKey(k *PublicKey, encoding []byte) error { + if len(encoding) != 32 { + return errors.New("ed25519: bad public key length: " + strconv.Itoa(len(encoding))) + } + if supportsBackend() && testMalleability() { + p := &encoding[0] + if cached := publicKeyCache.Get(p); cached != nil && subtle.ConstantTimeCompare(encoding, cached.backend.encoding[:]) == 1 { + *k = *cached + return nil + } + cached, err := importBackendPublicKey(encoding) + if err != nil { + return err + } + publicKeyCache.Put(p, cached) + *k = *cached + return nil + } + key, err := fallback.NewPublicKey(encoding) + if err != nil { + return err + } + k.fips = *key + return nil +} + +func importBackendPublicKey(encoding []byte) (*PublicKey, error) { + // Preserve the Go point validation before accepting a native key. + var point edwards25519.Point + if _, err := point.SetBytes(encoding); err != nil { + return nil, errors.New("ed25519: bad public key") + } + key, err := newPublicKey(encoding) + if err != nil { + return nil, err + } + s := &struct { + PublicKey + state backendPublicKeyState + }{state: backendPublicKeyState{key: key, encoding: [32]byte(encoding)}} + s.backend = &s.state + return &s.PublicKey, nil +} + +func newGoPrivateKey(encoding *[64]byte) *fipsPrivateKey { + key, err := fallback.NewPrivateKey(encoding[:]) + if err != nil { + panic(err) + } + return key +} + +func newGoPublicKey(encoding *[32]byte) *fipsPublicKey { + key, err := fallback.NewPublicKey(encoding[:]) + if err != nil { + panic(err) + } + return key +} + +func Sign(priv *PrivateKey, message []byte) []byte { + signature := make([]byte, 64) + signInto(signature, priv, message) + return signature +} + +func signInto(signature []byte, priv *PrivateKey, message []byte) { + if priv.backend != nil { + sig, err := sign(priv.backend, message) + if err != nil { + panic(err) + } + copy(signature, sig) + return + } + copy(signature, fallback.Sign(priv.fips, message)) +} + +// SignDeterministic uses the Go implementation. PrivateKey.Sign uses this path +// because some native providers randomize otherwise valid Ed25519 signatures. +func SignDeterministic(priv *PrivateKey, message []byte) []byte { + return fallback.Sign(priv.goKey(), message) +} + +func SignPH(priv *PrivateKey, message []byte, context string) ([]byte, error) { + return fallback.SignPH(priv.goKey(), message, context) +} + +func SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) { + return fallback.SignCtx(priv.goKey(), message, context) +} + +func Verify(pub *PublicKey, message, signature []byte) error { + if pub.backend != nil { + return verify(pub.backend.key, message, signature) + } + return fallback.Verify(pub.goKey(), message, signature) +} + +func VerifyPH(pub *PublicKey, message, signature []byte, context string) error { + return fallback.VerifyPH(pub.goKey(), message, signature, context) +} + +func VerifyCtx(pub *PublicKey, message, signature []byte, context string) error { + return fallback.VerifyCtx(pub.goKey(), message, signature, context) +} diff --git a/cryptobackend/ed25519/ed25519_nobackend_msgostd.go b/cryptobackend/ed25519/ed25519_nobackend_msgostd.go new file mode 100644 index 00000000000..6ac567b9202 --- /dev/null +++ b/cryptobackend/ed25519/ed25519_nobackend_msgostd.go @@ -0,0 +1,62 @@ +// Copyright 2026 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 (windows || !goexperiment.systemcrypto) && (msgostd || cmd_go_bootstrap) + +package ed25519 + +import ( + fallback "crypto/internal/fips140/ed25519" + + _ "github.com/microsoft/go/cryptobackend" +) + +// CNG does not implement Ed25519. Like Go-only builds, Windows uses the core +// types directly to avoid wrapping unsupported native operations. +type PrivateKey = fallback.PrivateKey +type PublicKey = fallback.PublicKey + +// PrivateKeyBytes returns the key encoding for read-only cache comparisons. +// A static call keeps the core encoder inlineable through the Go-only type alias. +func PrivateKeyBytes(k *PrivateKey) []byte { return k.Bytes() } + +// Keep these forwarding calls small enough to inline before the compiler +// expands the core constructors, so their returned keys can stay on the stack. +func generateGoKey(f func() (*PrivateKey, error)) (*PrivateKey, error) { return f() } +func newGoKey[K any](f func([]byte) (*K, error), encoding []byte) (*K, error) { + return f(encoding) +} +func signGoVariant(f func(*PrivateKey, []byte, string) ([]byte, error), key *PrivateKey, message []byte, context string) ([]byte, error) { + return f(key, message, context) +} + +func GenerateKey() (*PrivateKey, error) { return generateGoKey(fallback.GenerateKey) } +func NewPrivateKey(encoding []byte) (*PrivateKey, error) { + return newGoKey(fallback.NewPrivateKey, encoding) +} +func NewPrivateKeyFromSeed(seed []byte) (*PrivateKey, error) { + return newGoKey(fallback.NewPrivateKeyFromSeed, seed) +} +func NewPublicKey(encoding []byte) (*PublicKey, error) { + return newGoKey(fallback.NewPublicKey, encoding) +} +func Sign(priv *PrivateKey, message []byte) []byte { return fallback.Sign(priv, message) } +func SignDeterministic(priv *PrivateKey, message []byte) []byte { + return fallback.Sign(priv, message) +} +func SignPH(priv *PrivateKey, message []byte, context string) ([]byte, error) { + return signGoVariant(fallback.SignPH, priv, message, context) +} +func SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) { + return signGoVariant(fallback.SignCtx, priv, message, context) +} +func Verify(pub *PublicKey, message, signature []byte) error { + return fallback.Verify(pub, message, signature) +} +func VerifyPH(pub *PublicKey, message, signature []byte, context string) error { + return fallback.VerifyPH(pub, message, signature, context) +} +func VerifyCtx(pub *PublicKey, message, signature []byte, context string) error { + return fallback.VerifyCtx(pub, message, signature, context) +} diff --git a/cryptobackend/ed25519/ed25519_nomsgostd.go b/cryptobackend/ed25519/ed25519_nomsgostd.go new file mode 100644 index 00000000000..d7c5352253c --- /dev/null +++ b/cryptobackend/ed25519/ed25519_nomsgostd.go @@ -0,0 +1,41 @@ +// Copyright 2026 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 !msgostd && !cmd_go_bootstrap + +package ed25519 + +// Standalone builds and source importers cannot import standard-library internals. +type fipsPrivateKey struct{} +type fipsPublicKey struct{} + +func (*fipsPublicKey) Bytes() []byte { panic("cryptobackend: not available") } + +func GenerateKey() (*PrivateKey, error) { panic("cryptobackend: not available") } +func NewPrivateKey([]byte) (*PrivateKey, error) { + panic("cryptobackend: not available") +} +func NewPrivateKeyFromSeed([]byte) (*PrivateKey, error) { + panic("cryptobackend: not available") +} +func NewPublicKey([]byte) (*PublicKey, error) { panic("cryptobackend: not available") } +func Sign(*PrivateKey, []byte) []byte { panic("cryptobackend: not available") } +func SignDeterministic(*PrivateKey, []byte) []byte { + panic("cryptobackend: not available") +} +func SignPH(*PrivateKey, []byte, string) ([]byte, error) { + panic("cryptobackend: not available") +} +func SignCtx(*PrivateKey, []byte, string) ([]byte, error) { + panic("cryptobackend: not available") +} +func Verify(*PublicKey, []byte, []byte) error { panic("cryptobackend: not available") } +func VerifyPH(*PublicKey, []byte, []byte, string) error { + panic("cryptobackend: not available") +} +func VerifyCtx(*PublicKey, []byte, []byte, string) error { + panic("cryptobackend: not available") +} +func newGoPrivateKey(*[64]byte) *fipsPrivateKey { panic("cryptobackend: not available") } +func newGoPublicKey(*[32]byte) *fipsPublicKey { panic("cryptobackend: not available") } diff --git a/cryptobackend/ed25519/ed25519_openssl.go b/cryptobackend/ed25519/ed25519_openssl.go index 38a71066a5f..d88b5e9418e 100644 --- a/cryptobackend/ed25519/ed25519_openssl.go +++ b/cryptobackend/ed25519/ed25519_openssl.go @@ -8,17 +8,22 @@ package ed25519 import "github.com/microsoft/go-crypto-openssl/openssl" -type PrivateKey = *openssl.PrivateKeyEd25519 -type PublicKey = *openssl.PublicKeyEd25519 +type backendPrivateKey = *openssl.PrivateKeyEd25519 +type backendPublicKey = *openssl.PublicKeyEd25519 -func Supports() bool { return openssl.SupportsEd25519() } -func GenerateKey() (PrivateKey, error) { return openssl.GenerateKeyEd25519() } -func NewPrivateKey(priv []byte) (PrivateKey, error) { return openssl.NewPrivateKeyEd25519(priv) } -func NewPublicKey(pub []byte) (PublicKey, error) { return openssl.NewPublicKeyEd25519(pub) } -func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { +func Supports() bool { return openssl.SupportsEd25519() } +func generateKey() (backendPrivateKey, error) { return openssl.GenerateKeyEd25519() } +func newPrivateKey(priv []byte) (backendPrivateKey, error) { return openssl.NewPrivateKeyEd25519(priv) } +func newPublicKey(pub []byte) (backendPublicKey, error) { return openssl.NewPublicKeyEd25519(pub) } +func newPrivateKeyFromSeed(seed []byte) (backendPrivateKey, error) { return openssl.NewPrivateKeyEd25519FromSeed(seed) } -func Sign(priv PrivateKey, message []byte) ([]byte, error) { return openssl.SignEd25519(priv, message) } -func Verify(pub PublicKey, message, sig []byte) error { +func sign(priv backendPrivateKey, message []byte) ([]byte, error) { + return signBackend(openssl.SignEd25519, priv, message) +} +func signBackend(f func(backendPrivateKey, []byte) ([]byte, error), priv backendPrivateKey, message []byte) ([]byte, error) { + return f(priv, message) +} +func verify(pub backendPublicKey, message, sig []byte) error { return openssl.VerifyEd25519(pub, message, sig) } diff --git a/cryptobackend/ed25519/ed25519_windows.go b/cryptobackend/ed25519/ed25519_windows.go index 7802098b6a9..e8e290f8366 100644 --- a/cryptobackend/ed25519/ed25519_windows.go +++ b/cryptobackend/ed25519/ed25519_windows.go @@ -6,16 +6,20 @@ package ed25519 -type PrivateKey struct{} -type PublicKey struct{} +type backendPrivateKey = *unavailablePrivateKey +type backendPublicKey = *unavailablePublicKey +type unavailablePrivateKey struct{} +type unavailablePublicKey struct{} -func (k PrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } -func (k PublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } +func (*unavailablePrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } +func (*unavailablePublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } -func Supports() bool { return false } -func GenerateKey() (PrivateKey, error) { panic("cryptobackend: not available") } -func NewPrivateKey(priv []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -func NewPublicKey(pub []byte) (PublicKey, error) { panic("cryptobackend: not available") } -func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -func Sign(priv PrivateKey, message []byte) ([]byte, error) { panic("cryptobackend: not available") } -func Verify(pub PublicKey, message, sig []byte) error { panic("cryptobackend: not available") } +func Supports() bool { return false } +func generateKey() (backendPrivateKey, error) { panic("cryptobackend: not available") } +func newPrivateKey([]byte) (backendPrivateKey, error) { panic("cryptobackend: not available") } +func newPublicKey([]byte) (backendPublicKey, error) { panic("cryptobackend: not available") } +func newPrivateKeyFromSeed([]byte) (backendPrivateKey, error) { + panic("cryptobackend: not available") +} +func sign(backendPrivateKey, []byte) ([]byte, error) { panic("cryptobackend: not available") } +func verify(backendPublicKey, []byte, []byte) error { panic("cryptobackend: not available") } diff --git a/cryptobackend/ed25519/init.go b/cryptobackend/ed25519/init.go deleted file mode 100644 index b8321dff37e..00000000000 --- a/cryptobackend/ed25519/init.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2026 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 ed25519 - -import _ "github.com/microsoft/go/cryptobackend" diff --git a/cryptobackend/ed25519/key.go b/cryptobackend/ed25519/key.go new file mode 100644 index 00000000000..2f8d70b88f1 --- /dev/null +++ b/cryptobackend/ed25519/key.go @@ -0,0 +1,110 @@ +// Copyright 2026 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 && !windows) || (!msgostd && !cmd_go_bootstrap) + +package ed25519 + +import ( + "sync" + + backend "github.com/microsoft/go/cryptobackend" +) + +// PrivateKey owns an immutable key snapshot. It must not be copied after use. +// The standard-library private-key cache retains pointers to these keys. +type PrivateKey struct { + fips *fipsPrivateKey + backend backendPrivateKey + encoding [64]byte + goKeyOnce sync.Once +} + +// PublicKey owns a public-key snapshot and lazily reconstructs its Go key. +// Copies share the native key's reconstruction state. +type PublicKey struct { + fips fipsPublicKey + backend *backendPublicKeyState +} + +type backendPublicKeyState struct { + key backendPublicKey + encoding [32]byte + goKeyOnce sync.Once + goKey *fipsPublicKey +} + +// Bytes returns a copy of the private key encoding, including its public suffix. +func (k *PrivateKey) Bytes() []byte { + encoding := k.encoding + return encoding[:] +} + +// PrivateKeyBytes returns the owned snapshot for read-only cache comparisons. +func PrivateKeyBytes(k *PrivateKey) []byte { return k.encoding[:] } + +// Seed returns a copy of the private key seed. +func (k *PrivateKey) Seed() []byte { + seed := [32]byte(k.encoding[:32]) + return seed[:] +} + +// PublicKey returns a copy of the public key encoding. +func (k *PrivateKey) PublicKey() []byte { + pub := [32]byte(k.encoding[32:]) + return pub[:] +} + +// Bytes returns a copy of the public key encoding. +func (k *PublicKey) Bytes() []byte { + if k.backend != nil { + encoding := k.backend.encoding + return encoding[:] + } + return k.fips.Bytes() +} + +// goKey caches the Go key needed for prehash and context signing. +func (k *PrivateKey) goKey() *fipsPrivateKey { + if k.backend == nil { + return k.fips + } + k.goKeyOnce.Do(func() { + k.fips = newGoPrivateKey(&k.encoding) + }) + return k.fips +} + +func (k *PublicKey) goKey() *fipsPublicKey { + if k.backend == nil { + return &k.fips + } + s := k.backend + s.goKeyOnce.Do(func() { + s.goKey = newGoPublicKey(&s.encoding) + }) + return s.goKey +} + +func supportsBackend() bool { return backend.Enabled && Supports() } + +// Old OpenSSL versions accept non-canonical signature scalars. Keep native +// verification disabled if the provider does not reject this malleable vector. +var testMalleability = sync.OnceValue(func() bool { + msg := []byte{0x54, 0x65, 0x73, 0x74} + sig := []byte{ + 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a, + 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b, + 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67, + 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, + 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, + 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d, + } + pub, err := newPublicKey([]byte{ + 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5, + 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34, + 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa, + }) + return err == nil && verify(pub, msg, sig) != nil +}) diff --git a/cryptobackend/ed25519/nobackend.go b/cryptobackend/ed25519/nobackend.go index a666c8143e8..e97bfa8da2a 100644 --- a/cryptobackend/ed25519/nobackend.go +++ b/cryptobackend/ed25519/nobackend.go @@ -6,16 +6,20 @@ package ed25519 -type PrivateKey struct{} -type PublicKey struct{} +type backendPrivateKey = *unavailablePrivateKey +type backendPublicKey = *unavailablePublicKey +type unavailablePrivateKey struct{} +type unavailablePublicKey struct{} -func (k PrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } -func (k PublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } +func (*unavailablePrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } +func (*unavailablePublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } -func Supports() bool { panic("cryptobackend: not available") } -func GenerateKey() (PrivateKey, error) { panic("cryptobackend: not available") } -func NewPrivateKey(priv []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -func NewPublicKey(pub []byte) (PublicKey, error) { panic("cryptobackend: not available") } -func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -func Sign(priv PrivateKey, message []byte) ([]byte, error) { panic("cryptobackend: not available") } -func Verify(pub PublicKey, message, sig []byte) error { panic("cryptobackend: not available") } +func Supports() bool { panic("cryptobackend: not available") } +func generateKey() (backendPrivateKey, error) { panic("cryptobackend: not available") } +func newPrivateKey([]byte) (backendPrivateKey, error) { panic("cryptobackend: not available") } +func newPublicKey([]byte) (backendPublicKey, error) { panic("cryptobackend: not available") } +func newPrivateKeyFromSeed([]byte) (backendPrivateKey, error) { + panic("cryptobackend: not available") +} +func sign(backendPrivateKey, []byte) ([]byte, error) { panic("cryptobackend: not available") } +func verify(backendPublicKey, []byte, []byte) error { panic("cryptobackend: not available") } diff --git a/patches/0001-Vendor-external-dependencies.patch b/patches/0001-Vendor-external-dependencies.patch index cf35f91f7d8..f8c87859cd5 100644 --- a/patches/0001-Vendor-external-dependencies.patch +++ b/patches/0001-Vendor-external-dependencies.patch @@ -316,11 +316,14 @@ Use a 'go' that was recently built by the current branch to ensure stable result .../microsoft/go/cryptobackend/ecdsa/key.go | 88 + .../go/cryptobackend/ecdsa/nobackend.go | 27 + .../go/cryptobackend/ecdsa/signature.go | 50 + - .../cryptobackend/ed25519/ed25519_darwin.go | 24 + - .../cryptobackend/ed25519/ed25519_openssl.go | 24 + - .../cryptobackend/ed25519/ed25519_windows.go | 21 + - .../go/cryptobackend/ed25519/init.go | 7 + - .../go/cryptobackend/ed25519/nobackend.go | 21 + + .../cryptobackend/ed25519/ed25519_darwin.go | 26 + + .../cryptobackend/ed25519/ed25519_msgostd.go | 239 ++ + .../ed25519/ed25519_nobackend_msgostd.go | 62 + + .../ed25519/ed25519_nomsgostd.go | 41 + + .../cryptobackend/ed25519/ed25519_openssl.go | 29 + + .../cryptobackend/ed25519/ed25519_windows.go | 25 + + .../microsoft/go/cryptobackend/ed25519/key.go | 110 + + .../go/cryptobackend/ed25519/nobackend.go | 25 + .../go/cryptobackend/fips140/fips140.go | 15 + .../microsoft/go/cryptobackend/hkdf/hkdf.go | 39 + .../go/cryptobackend/hkdf/hkdf_darwin.go | 26 + @@ -448,7 +451,7 @@ Use a 'go' that was recently built by the current branch to ensure stable result .../go/cryptobackend/tls13/tls13_openssl.go | 18 + .../go/cryptobackend/tls13/tls13_windows.go | 14 + src/vendor/modules.txt | 53 + - 440 files changed, 42449 insertions(+), 7 deletions(-) + 443 files changed, 42909 insertions(+), 7 deletions(-) create mode 100644 src/cmd/internal/telemetry/counter/deps_ignore.go create mode 100644 src/cmd/vendor/github.com/microsoft/go-infra/telemetry/LICENSE create mode 100644 src/cmd/vendor/github.com/microsoft/go-infra/telemetry/README.md @@ -751,9 +754,12 @@ Use a 'go' that was recently built by the current branch to ensure stable result create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ecdsa/nobackend.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ecdsa/signature.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_darwin.go + create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_msgostd.go + create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nobackend_msgostd.go + create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nomsgostd.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_openssl.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_windows.go - create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/init.go + create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/key.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/ed25519/nobackend.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/fips140/fips140.go create mode 100644 src/vendor/github.com/microsoft/go/cryptobackend/hkdf/hkdf.go @@ -42139,10 +42145,10 @@ index 00000000000000..01d419b1971920 +} diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_darwin.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_darwin.go new file mode 100644 -index 00000000000000..339ad263058c45 +index 00000000000000..531f32a908dbce --- /dev/null +++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_darwin.go -@@ -0,0 +1,24 @@ +@@ -0,0 +1,26 @@ +// 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. @@ -42153,26 +42159,388 @@ index 00000000000000..339ad263058c45 + +import "github.com/microsoft/go-crypto-darwin/xcrypto" + -+type PrivateKey = xcrypto.PrivateKeyEd25519 -+type PublicKey = xcrypto.PublicKeyEd25519 ++type backendPrivateKey = xcrypto.PrivateKeyEd25519 ++type backendPublicKey = xcrypto.PublicKeyEd25519 + -+func Supports() bool { return true } -+func GenerateKey() (PrivateKey, error) { return xcrypto.GenerateKeyEd25519(), nil } -+func NewPrivateKey(priv []byte) (PrivateKey, error) { return xcrypto.NewPrivateKeyEd25519(priv) } -+func NewPublicKey(pub []byte) (PublicKey, error) { return xcrypto.NewPublicKeyEd25519(pub) } -+func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { ++func Supports() bool { return true } ++func generateKey() (backendPrivateKey, error) { return xcrypto.GenerateKeyEd25519(), nil } ++func newPrivateKey(priv []byte) (backendPrivateKey, error) { return xcrypto.NewPrivateKeyEd25519(priv) } ++func newPublicKey(pub []byte) (backendPublicKey, error) { return xcrypto.NewPublicKeyEd25519(pub) } ++func newPrivateKeyFromSeed(seed []byte) (backendPrivateKey, error) { + return xcrypto.NewPrivateKeyEd25519FromSeed(seed) +} -+func Sign(priv PrivateKey, message []byte) ([]byte, error) { return xcrypto.SignEd25519(priv, message) } -+func Verify(pub PublicKey, message, sig []byte) error { ++func sign(priv backendPrivateKey, message []byte) ([]byte, error) { ++ return xcrypto.SignEd25519(priv, message) ++} ++func verify(pub backendPublicKey, message, sig []byte) error { + return xcrypto.VerifyEd25519(pub, message, sig) +} +diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_msgostd.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_msgostd.go +new file mode 100644 +index 00000000000000..de40c80c45fdf2 +--- /dev/null ++++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_msgostd.go +@@ -0,0 +1,239 @@ ++// Copyright 2026 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 && !windows && (msgostd || cmd_go_bootstrap) ++ ++package ed25519 ++ ++import ( ++ "crypto/internal/boring/bcache" ++ fallback "crypto/internal/fips140/ed25519" ++ "crypto/internal/fips140/edwards25519" ++ "crypto/internal/rand" ++ cryptorand "crypto/rand" ++ "crypto/subtle" ++ "errors" ++ "strconv" ++) ++ ++type fipsPrivateKey = fallback.PrivateKey ++type fipsPublicKey = fallback.PublicKey ++ ++func GenerateKey() (key *PrivateKey, err error) { ++ var k PrivateKey ++ err = generate(&k) ++ if err == nil { ++ key = &k ++ } ++ return ++} ++ ++func generate(k *PrivateKey) error { ++ if supportsBackend() && rand.IsDefaultReader(cryptorand.Reader) { ++ key, err := generateKey() ++ if err != nil { ++ return err ++ } ++ return initBackendPrivateKey(k, key) ++ } ++ key, err := fallback.GenerateKey() ++ if err != nil { ++ return err ++ } ++ k.fips, k.encoding = key, [64]byte(key.Bytes()) ++ return nil ++} ++ ++func NewPrivateKeyFromSeed(seed []byte) (key *PrivateKey, err error) { ++ var k PrivateKey ++ err = newPrivateFromSeed(&k, seed) ++ if err == nil { ++ key = &k ++ } ++ return ++} ++ ++func newPrivateFromSeed(k *PrivateKey, seed []byte) error { ++ if len(seed) != 32 { ++ return errors.New("ed25519: bad seed length: " + strconv.Itoa(len(seed))) ++ } ++ if supportsBackend() { ++ key, err := newPrivateKeyFromSeed(seed) ++ if err != nil { ++ return err ++ } ++ return initBackendPrivateKey(k, key) ++ } ++ key, err := fallback.NewPrivateKeyFromSeed(seed) ++ if err != nil { ++ return err ++ } ++ k.fips, k.encoding = key, [64]byte(key.Bytes()) ++ return nil ++} ++ ++func NewPrivateKey(encoding []byte) (*PrivateKey, error) { ++ if len(encoding) != 64 { ++ return nil, errors.New("ed25519: bad private key length: " + strconv.Itoa(len(encoding))) ++ } ++ if supportsBackend() { ++ key, err := newPrivateKey(encoding) ++ if err != nil { ++ return nil, err ++ } ++ k := new(PrivateKey) ++ if err := initBackendPrivateKey(k, key); err != nil { ++ return nil, err ++ } ++ // Native importers derive the public suffix from the seed. Go signing ++ // uses the supplied suffix, even when it does not match that seed. ++ if subtle.ConstantTimeCompare(encoding, k.encoding[:]) == 1 { ++ return k, nil ++ } ++ } ++ key, err := fallback.NewPrivateKey(encoding) ++ if err != nil { ++ return nil, err ++ } ++ return &PrivateKey{fips: key, encoding: [64]byte(encoding)}, nil ++} ++ ++func initBackendPrivateKey(k *PrivateKey, key backendPrivateKey) error { ++ encoding, err := key.Bytes() ++ if err != nil { ++ return err ++ } ++ if len(encoding) != 64 { ++ return errors.New("ed25519: invalid backend private key length") ++ } ++ k.backend = key ++ copy(k.encoding[:], encoding) ++ return nil ++} ++ ++// Preserve the native public-key cache's GC-based eviction. Each cached key ++// holds its own immutable encoding, so input mutations invalidate the entry. ++var publicKeyCache bcache.Cache[byte, PublicKey] ++ ++func init() { ++ if supportsBackend() { ++ publicKeyCache.Register() ++ } ++} ++ ++func NewPublicKey(encoding []byte) (key *PublicKey, err error) { ++ var k PublicKey ++ err = importPublicKey(&k, encoding) ++ if err == nil { ++ key = &k ++ } ++ return ++} ++ ++func importPublicKey(k *PublicKey, encoding []byte) error { ++ if len(encoding) != 32 { ++ return errors.New("ed25519: bad public key length: " + strconv.Itoa(len(encoding))) ++ } ++ if supportsBackend() && testMalleability() { ++ p := &encoding[0] ++ if cached := publicKeyCache.Get(p); cached != nil && subtle.ConstantTimeCompare(encoding, cached.backend.encoding[:]) == 1 { ++ *k = *cached ++ return nil ++ } ++ cached, err := importBackendPublicKey(encoding) ++ if err != nil { ++ return err ++ } ++ publicKeyCache.Put(p, cached) ++ *k = *cached ++ return nil ++ } ++ key, err := fallback.NewPublicKey(encoding) ++ if err != nil { ++ return err ++ } ++ k.fips = *key ++ return nil ++} ++ ++func importBackendPublicKey(encoding []byte) (*PublicKey, error) { ++ // Preserve the Go point validation before accepting a native key. ++ var point edwards25519.Point ++ if _, err := point.SetBytes(encoding); err != nil { ++ return nil, errors.New("ed25519: bad public key") ++ } ++ key, err := newPublicKey(encoding) ++ if err != nil { ++ return nil, err ++ } ++ s := &struct { ++ PublicKey ++ state backendPublicKeyState ++ }{state: backendPublicKeyState{key: key, encoding: [32]byte(encoding)}} ++ s.backend = &s.state ++ return &s.PublicKey, nil ++} ++ ++func newGoPrivateKey(encoding *[64]byte) *fipsPrivateKey { ++ key, err := fallback.NewPrivateKey(encoding[:]) ++ if err != nil { ++ panic(err) ++ } ++ return key ++} ++ ++func newGoPublicKey(encoding *[32]byte) *fipsPublicKey { ++ key, err := fallback.NewPublicKey(encoding[:]) ++ if err != nil { ++ panic(err) ++ } ++ return key ++} ++ ++func Sign(priv *PrivateKey, message []byte) []byte { ++ signature := make([]byte, 64) ++ signInto(signature, priv, message) ++ return signature ++} ++ ++func signInto(signature []byte, priv *PrivateKey, message []byte) { ++ if priv.backend != nil { ++ sig, err := sign(priv.backend, message) ++ if err != nil { ++ panic(err) ++ } ++ copy(signature, sig) ++ return ++ } ++ copy(signature, fallback.Sign(priv.fips, message)) ++} ++ ++// SignDeterministic uses the Go implementation. PrivateKey.Sign uses this path ++// because some native providers randomize otherwise valid Ed25519 signatures. ++func SignDeterministic(priv *PrivateKey, message []byte) []byte { ++ return fallback.Sign(priv.goKey(), message) ++} ++ ++func SignPH(priv *PrivateKey, message []byte, context string) ([]byte, error) { ++ return fallback.SignPH(priv.goKey(), message, context) ++} ++ ++func SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) { ++ return fallback.SignCtx(priv.goKey(), message, context) ++} ++ ++func Verify(pub *PublicKey, message, signature []byte) error { ++ if pub.backend != nil { ++ return verify(pub.backend.key, message, signature) ++ } ++ return fallback.Verify(pub.goKey(), message, signature) ++} ++ ++func VerifyPH(pub *PublicKey, message, signature []byte, context string) error { ++ return fallback.VerifyPH(pub.goKey(), message, signature, context) ++} ++ ++func VerifyCtx(pub *PublicKey, message, signature []byte, context string) error { ++ return fallback.VerifyCtx(pub.goKey(), message, signature, context) ++} +diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nobackend_msgostd.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nobackend_msgostd.go +new file mode 100644 +index 00000000000000..6ac567b9202f2b +--- /dev/null ++++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nobackend_msgostd.go +@@ -0,0 +1,62 @@ ++// Copyright 2026 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 (windows || !goexperiment.systemcrypto) && (msgostd || cmd_go_bootstrap) ++ ++package ed25519 ++ ++import ( ++ fallback "crypto/internal/fips140/ed25519" ++ ++ _ "github.com/microsoft/go/cryptobackend" ++) ++ ++// CNG does not implement Ed25519. Like Go-only builds, Windows uses the core ++// types directly to avoid wrapping unsupported native operations. ++type PrivateKey = fallback.PrivateKey ++type PublicKey = fallback.PublicKey ++ ++// PrivateKeyBytes returns the key encoding for read-only cache comparisons. ++// A static call keeps the core encoder inlineable through the Go-only type alias. ++func PrivateKeyBytes(k *PrivateKey) []byte { return k.Bytes() } ++ ++// Keep these forwarding calls small enough to inline before the compiler ++// expands the core constructors, so their returned keys can stay on the stack. ++func generateGoKey(f func() (*PrivateKey, error)) (*PrivateKey, error) { return f() } ++func newGoKey[K any](f func([]byte) (*K, error), encoding []byte) (*K, error) { ++ return f(encoding) ++} ++func signGoVariant(f func(*PrivateKey, []byte, string) ([]byte, error), key *PrivateKey, message []byte, context string) ([]byte, error) { ++ return f(key, message, context) ++} ++ ++func GenerateKey() (*PrivateKey, error) { return generateGoKey(fallback.GenerateKey) } ++func NewPrivateKey(encoding []byte) (*PrivateKey, error) { ++ return newGoKey(fallback.NewPrivateKey, encoding) ++} ++func NewPrivateKeyFromSeed(seed []byte) (*PrivateKey, error) { ++ return newGoKey(fallback.NewPrivateKeyFromSeed, seed) ++} ++func NewPublicKey(encoding []byte) (*PublicKey, error) { ++ return newGoKey(fallback.NewPublicKey, encoding) ++} ++func Sign(priv *PrivateKey, message []byte) []byte { return fallback.Sign(priv, message) } ++func SignDeterministic(priv *PrivateKey, message []byte) []byte { ++ return fallback.Sign(priv, message) ++} ++func SignPH(priv *PrivateKey, message []byte, context string) ([]byte, error) { ++ return signGoVariant(fallback.SignPH, priv, message, context) ++} ++func SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) { ++ return signGoVariant(fallback.SignCtx, priv, message, context) ++} ++func Verify(pub *PublicKey, message, signature []byte) error { ++ return fallback.Verify(pub, message, signature) ++} ++func VerifyPH(pub *PublicKey, message, signature []byte, context string) error { ++ return fallback.VerifyPH(pub, message, signature, context) ++} ++func VerifyCtx(pub *PublicKey, message, signature []byte, context string) error { ++ return fallback.VerifyCtx(pub, message, signature, context) ++} +diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nomsgostd.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nomsgostd.go +new file mode 100644 +index 00000000000000..d7c5352253c822 +--- /dev/null ++++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_nomsgostd.go +@@ -0,0 +1,41 @@ ++// Copyright 2026 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 !msgostd && !cmd_go_bootstrap ++ ++package ed25519 ++ ++// Standalone builds and source importers cannot import standard-library internals. ++type fipsPrivateKey struct{} ++type fipsPublicKey struct{} ++ ++func (*fipsPublicKey) Bytes() []byte { panic("cryptobackend: not available") } ++ ++func GenerateKey() (*PrivateKey, error) { panic("cryptobackend: not available") } ++func NewPrivateKey([]byte) (*PrivateKey, error) { ++ panic("cryptobackend: not available") ++} ++func NewPrivateKeyFromSeed([]byte) (*PrivateKey, error) { ++ panic("cryptobackend: not available") ++} ++func NewPublicKey([]byte) (*PublicKey, error) { panic("cryptobackend: not available") } ++func Sign(*PrivateKey, []byte) []byte { panic("cryptobackend: not available") } ++func SignDeterministic(*PrivateKey, []byte) []byte { ++ panic("cryptobackend: not available") ++} ++func SignPH(*PrivateKey, []byte, string) ([]byte, error) { ++ panic("cryptobackend: not available") ++} ++func SignCtx(*PrivateKey, []byte, string) ([]byte, error) { ++ panic("cryptobackend: not available") ++} ++func Verify(*PublicKey, []byte, []byte) error { panic("cryptobackend: not available") } ++func VerifyPH(*PublicKey, []byte, []byte, string) error { ++ panic("cryptobackend: not available") ++} ++func VerifyCtx(*PublicKey, []byte, []byte, string) error { ++ panic("cryptobackend: not available") ++} ++func newGoPrivateKey(*[64]byte) *fipsPrivateKey { panic("cryptobackend: not available") } ++func newGoPublicKey(*[32]byte) *fipsPublicKey { panic("cryptobackend: not available") } diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_openssl.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_openssl.go new file mode 100644 -index 00000000000000..38a71066a5fe99 +index 00000000000000..d88b5e9418eb87 --- /dev/null +++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_openssl.go -@@ -0,0 +1,24 @@ +@@ -0,0 +1,29 @@ +// 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. @@ -42183,26 +42551,31 @@ index 00000000000000..38a71066a5fe99 + +import "github.com/microsoft/go-crypto-openssl/openssl" + -+type PrivateKey = *openssl.PrivateKeyEd25519 -+type PublicKey = *openssl.PublicKeyEd25519 ++type backendPrivateKey = *openssl.PrivateKeyEd25519 ++type backendPublicKey = *openssl.PublicKeyEd25519 + -+func Supports() bool { return openssl.SupportsEd25519() } -+func GenerateKey() (PrivateKey, error) { return openssl.GenerateKeyEd25519() } -+func NewPrivateKey(priv []byte) (PrivateKey, error) { return openssl.NewPrivateKeyEd25519(priv) } -+func NewPublicKey(pub []byte) (PublicKey, error) { return openssl.NewPublicKeyEd25519(pub) } -+func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { ++func Supports() bool { return openssl.SupportsEd25519() } ++func generateKey() (backendPrivateKey, error) { return openssl.GenerateKeyEd25519() } ++func newPrivateKey(priv []byte) (backendPrivateKey, error) { return openssl.NewPrivateKeyEd25519(priv) } ++func newPublicKey(pub []byte) (backendPublicKey, error) { return openssl.NewPublicKeyEd25519(pub) } ++func newPrivateKeyFromSeed(seed []byte) (backendPrivateKey, error) { + return openssl.NewPrivateKeyEd25519FromSeed(seed) +} -+func Sign(priv PrivateKey, message []byte) ([]byte, error) { return openssl.SignEd25519(priv, message) } -+func Verify(pub PublicKey, message, sig []byte) error { ++func sign(priv backendPrivateKey, message []byte) ([]byte, error) { ++ return signBackend(openssl.SignEd25519, priv, message) ++} ++func signBackend(f func(backendPrivateKey, []byte) ([]byte, error), priv backendPrivateKey, message []byte) ([]byte, error) { ++ return f(priv, message) ++} ++func verify(pub backendPublicKey, message, sig []byte) error { + return openssl.VerifyEd25519(pub, message, sig) +} diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_windows.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_windows.go new file mode 100644 -index 00000000000000..7802098b6a9c56 +index 00000000000000..e8e290f836679a --- /dev/null +++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/ed25519_windows.go -@@ -0,0 +1,21 @@ +@@ -0,0 +1,25 @@ +// 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. @@ -42211,38 +42584,145 @@ index 00000000000000..7802098b6a9c56 + +package ed25519 + -+type PrivateKey struct{} -+type PublicKey struct{} ++type backendPrivateKey = *unavailablePrivateKey ++type backendPublicKey = *unavailablePublicKey ++type unavailablePrivateKey struct{} ++type unavailablePublicKey struct{} + -+func (k PrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } -+func (k PublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } ++func (*unavailablePrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } ++func (*unavailablePublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } + -+func Supports() bool { return false } -+func GenerateKey() (PrivateKey, error) { panic("cryptobackend: not available") } -+func NewPrivateKey(priv []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -+func NewPublicKey(pub []byte) (PublicKey, error) { panic("cryptobackend: not available") } -+func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -+func Sign(priv PrivateKey, message []byte) ([]byte, error) { panic("cryptobackend: not available") } -+func Verify(pub PublicKey, message, sig []byte) error { panic("cryptobackend: not available") } -diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/init.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/init.go ++func Supports() bool { return false } ++func generateKey() (backendPrivateKey, error) { panic("cryptobackend: not available") } ++func newPrivateKey([]byte) (backendPrivateKey, error) { panic("cryptobackend: not available") } ++func newPublicKey([]byte) (backendPublicKey, error) { panic("cryptobackend: not available") } ++func newPrivateKeyFromSeed([]byte) (backendPrivateKey, error) { ++ panic("cryptobackend: not available") ++} ++func sign(backendPrivateKey, []byte) ([]byte, error) { panic("cryptobackend: not available") } ++func verify(backendPublicKey, []byte, []byte) error { panic("cryptobackend: not available") } +diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/key.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/key.go new file mode 100644 -index 00000000000000..b8321dff37e05e +index 00000000000000..2f8d70b88f1ee1 --- /dev/null -+++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/init.go -@@ -0,0 +1,7 @@ ++++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/key.go +@@ -0,0 +1,110 @@ +// Copyright 2026 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 && !windows) || (!msgostd && !cmd_go_bootstrap) ++ +package ed25519 + -+import _ "github.com/microsoft/go/cryptobackend" ++import ( ++ "sync" ++ ++ backend "github.com/microsoft/go/cryptobackend" ++) ++ ++// PrivateKey owns an immutable key snapshot. It must not be copied after use. ++// The standard-library private-key cache retains pointers to these keys. ++type PrivateKey struct { ++ fips *fipsPrivateKey ++ backend backendPrivateKey ++ encoding [64]byte ++ goKeyOnce sync.Once ++} ++ ++// PublicKey owns a public-key snapshot and lazily reconstructs its Go key. ++// Copies share the native key's reconstruction state. ++type PublicKey struct { ++ fips fipsPublicKey ++ backend *backendPublicKeyState ++} ++ ++type backendPublicKeyState struct { ++ key backendPublicKey ++ encoding [32]byte ++ goKeyOnce sync.Once ++ goKey *fipsPublicKey ++} ++ ++// Bytes returns a copy of the private key encoding, including its public suffix. ++func (k *PrivateKey) Bytes() []byte { ++ encoding := k.encoding ++ return encoding[:] ++} ++ ++// PrivateKeyBytes returns the owned snapshot for read-only cache comparisons. ++func PrivateKeyBytes(k *PrivateKey) []byte { return k.encoding[:] } ++ ++// Seed returns a copy of the private key seed. ++func (k *PrivateKey) Seed() []byte { ++ seed := [32]byte(k.encoding[:32]) ++ return seed[:] ++} ++ ++// PublicKey returns a copy of the public key encoding. ++func (k *PrivateKey) PublicKey() []byte { ++ pub := [32]byte(k.encoding[32:]) ++ return pub[:] ++} ++ ++// Bytes returns a copy of the public key encoding. ++func (k *PublicKey) Bytes() []byte { ++ if k.backend != nil { ++ encoding := k.backend.encoding ++ return encoding[:] ++ } ++ return k.fips.Bytes() ++} ++ ++// goKey caches the Go key needed for prehash and context signing. ++func (k *PrivateKey) goKey() *fipsPrivateKey { ++ if k.backend == nil { ++ return k.fips ++ } ++ k.goKeyOnce.Do(func() { ++ k.fips = newGoPrivateKey(&k.encoding) ++ }) ++ return k.fips ++} ++ ++func (k *PublicKey) goKey() *fipsPublicKey { ++ if k.backend == nil { ++ return &k.fips ++ } ++ s := k.backend ++ s.goKeyOnce.Do(func() { ++ s.goKey = newGoPublicKey(&s.encoding) ++ }) ++ return s.goKey ++} ++ ++func supportsBackend() bool { return backend.Enabled && Supports() } ++ ++// Old OpenSSL versions accept non-canonical signature scalars. Keep native ++// verification disabled if the provider does not reject this malleable vector. ++var testMalleability = sync.OnceValue(func() bool { ++ msg := []byte{0x54, 0x65, 0x73, 0x74} ++ sig := []byte{ ++ 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a, ++ 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b, ++ 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67, ++ 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, ++ 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, ++ 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d, ++ } ++ pub, err := newPublicKey([]byte{ ++ 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5, ++ 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34, ++ 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa, ++ }) ++ return err == nil && verify(pub, msg, sig) != nil ++}) diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/nobackend.go b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/nobackend.go new file mode 100644 -index 00000000000000..a666c8143e84d8 +index 00000000000000..e97bfa8da2ad61 --- /dev/null +++ b/src/vendor/github.com/microsoft/go/cryptobackend/ed25519/nobackend.go -@@ -0,0 +1,21 @@ +@@ -0,0 +1,25 @@ +// 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. @@ -42251,19 +42731,23 @@ index 00000000000000..a666c8143e84d8 + +package ed25519 + -+type PrivateKey struct{} -+type PublicKey struct{} ++type backendPrivateKey = *unavailablePrivateKey ++type backendPublicKey = *unavailablePublicKey ++type unavailablePrivateKey struct{} ++type unavailablePublicKey struct{} + -+func (k PrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } -+func (k PublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } ++func (*unavailablePrivateKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } ++func (*unavailablePublicKey) Bytes() ([]byte, error) { panic("cryptobackend: not available") } + -+func Supports() bool { panic("cryptobackend: not available") } -+func GenerateKey() (PrivateKey, error) { panic("cryptobackend: not available") } -+func NewPrivateKey(priv []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -+func NewPublicKey(pub []byte) (PublicKey, error) { panic("cryptobackend: not available") } -+func NewPrivateKeyFromSeed(seed []byte) (PrivateKey, error) { panic("cryptobackend: not available") } -+func Sign(priv PrivateKey, message []byte) ([]byte, error) { panic("cryptobackend: not available") } -+func Verify(pub PublicKey, message, sig []byte) error { panic("cryptobackend: not available") } ++func Supports() bool { panic("cryptobackend: not available") } ++func generateKey() (backendPrivateKey, error) { panic("cryptobackend: not available") } ++func newPrivateKey([]byte) (backendPrivateKey, error) { panic("cryptobackend: not available") } ++func newPublicKey([]byte) (backendPublicKey, error) { panic("cryptobackend: not available") } ++func newPrivateKeyFromSeed([]byte) (backendPrivateKey, error) { ++ panic("cryptobackend: not available") ++} ++func sign(backendPrivateKey, []byte) ([]byte, error) { panic("cryptobackend: not available") } ++func verify(backendPublicKey, []byte, []byte) error { panic("cryptobackend: not available") } diff --git a/src/vendor/github.com/microsoft/go/cryptobackend/fips140/fips140.go b/src/vendor/github.com/microsoft/go/cryptobackend/fips140/fips140.go new file mode 100644 index 00000000000000..2b98ef4138312e diff --git a/patches/0002-Add-crypto-backends.patch b/patches/0002-Add-crypto-backends.patch index 4ed43e46869..1207c3561c7 100644 --- a/patches/0002-Add-crypto-backends.patch +++ b/patches/0002-Add-crypto-backends.patch @@ -56,10 +56,8 @@ Subject: [PATCH] Add crypto backends src/crypto/ecdh/nist.go | 3 +- src/crypto/ecdh/x25519.go | 43 +-- src/crypto/ecdsa/ecdsa.go | 19 +- - src/crypto/ed25519/boring.go | 73 +++++ - src/crypto/ed25519/ed25519.go | 73 +++++ - src/crypto/ed25519/ed25519_test.go | 14 +- - src/crypto/ed25519/notboring.go | 16 + + src/crypto/ed25519/ed25519.go | 12 +- + src/crypto/ed25519/ed25519_test.go | 18 +- src/crypto/fips140/enforcement_test.go | 4 + src/crypto/fips140/fips140.go | 3 +- src/crypto/hkdf/hkdf.go | 9 +- @@ -133,12 +131,10 @@ Subject: [PATCH] Add crypto backends src/os/exec/exec_test.go | 9 + src/runtime/runtime_boring.go | 5 + src/syscall/syscall_windows.go | 3 + - 129 files changed, 1902 insertions(+), 248 deletions(-) + 127 files changed, 1750 insertions(+), 254 deletions(-) create mode 100644 src/cmd/go/systemcrypto_test.go create mode 100644 src/crypto/dsa/boring.go create mode 100644 src/crypto/dsa/notboring.go - create mode 100644 src/crypto/ed25519/boring.go - create mode 100644 src/crypto/ed25519/notboring.go create mode 100644 src/crypto/systemcrypto_nocgo_freebsd.go create mode 100644 src/crypto/systemcrypto_nocgo_linux.go create mode 100644 src/go/build/buildbackend_test.go @@ -2119,221 +2115,85 @@ index 3bd4a5e7b4adaa..b0513d91daf33d 100644 } var privateKeyCache fips140cache.Cache[PrivateKey, ecdsa.PrivateKey] -diff --git a/src/crypto/ed25519/boring.go b/src/crypto/ed25519/boring.go -new file mode 100644 -index 00000000000000..25a3f57660c356 ---- /dev/null -+++ b/src/crypto/ed25519/boring.go -@@ -0,0 +1,73 @@ -+// Copyright 2023 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 ed25519 -+ -+import ( -+ "crypto/internal/boring/bcache" -+ "unsafe" -+ -+ boring "github.com/microsoft/go/cryptobackend" -+ bed25519 "github.com/microsoft/go/cryptobackend/ed25519" -+) -+ -+var pubCache bcache.Cache[byte, boringPub] -+var privCache bcache.Cache[byte, boringPriv] -+ -+func init() { -+ if boring.Enabled && bed25519.Supports() { -+ pubCache.Register() -+ privCache.Register() -+ } -+} -+ -+type boringPub struct { -+ key bed25519.PublicKey -+ orig [PublicKeySize]byte -+} -+ -+func boringPublicKey(pub PublicKey) (bed25519.PublicKey, error) { -+ // Use the pointer to the underlying pub array as key. -+ p := unsafe.SliceData(pub) -+ b := pubCache.Get(p) -+ if b != nil && PublicKey(b.orig[:]).Equal(pub) { -+ return b.key, nil -+ } -+ -+ b = new(boringPub) -+ copy(b.orig[:], pub) -+ key, err := bed25519.NewPublicKey(b.orig[:]) -+ if err != nil { -+ return key, err -+ } -+ b.key = key -+ pubCache.Put(p, b) -+ return key, nil -+} -+ -+type boringPriv struct { -+ key bed25519.PrivateKey -+ orig [PrivateKeySize]byte -+} -+ -+func boringPrivateKey(priv PrivateKey) (bed25519.PrivateKey, error) { -+ // Use the pointer to the underlying priv array as key. -+ p := unsafe.SliceData(priv) -+ b := privCache.Get(p) -+ if b != nil && PrivateKey(b.orig[:]).Equal(priv) { -+ return b.key, nil -+ } -+ -+ b = new(boringPriv) -+ copy(b.orig[:], priv) -+ key, err := bed25519.NewPrivateKey(b.orig[:]) -+ if err != nil { -+ return key, err -+ } -+ b.key = key -+ privCache.Put(p, b) -+ return key, nil -+} diff --git a/src/crypto/ed25519/ed25519.go b/src/crypto/ed25519/ed25519.go -index ed599ad2908dfb..21ca98e7c70b83 100644 +index ed599ad2908dfb..f831109d187d8e 100644 --- a/src/crypto/ed25519/ed25519.go +++ b/src/crypto/ed25519/ed25519.go -@@ -27,6 +27,10 @@ import ( +@@ -17,7 +17,6 @@ package ed25519 + + import ( + "crypto" +- "crypto/internal/fips140/ed25519" + "crypto/internal/fips140cache" + "crypto/internal/fips140only" + "crypto/internal/rand" +@@ -27,6 +26,8 @@ import ( "internal/godebug" "io" "strconv" -+ "sync" + -+ boring "github.com/microsoft/go/cryptobackend" -+ bed25519 "github.com/microsoft/go/cryptobackend/ed25519" ++ "github.com/microsoft/go/cryptobackend/ed25519" ) const ( -@@ -164,6 +168,20 @@ func GenerateKey(random io.Reader) (PublicKey, PrivateKey, error) { - return nil, nil, errors.New("crypto/ed25519: only crypto/rand.Reader is allowed in FIPS 140-only mode") - } - -+ if boring.Enabled && rand.IsDefaultReader(random) && bed25519.Supports() { -+ priv, err := bed25519.GenerateKey() -+ if err != nil { -+ return nil, nil, err -+ } -+ privData, err := priv.Bytes() -+ if err != nil { -+ return nil, nil, err -+ } -+ privKey := PrivateKey(privData) -+ pubKey := privKey.Public().(PublicKey) -+ return pubKey, privKey, err -+ } -+ - if rand.IsDefaultReader(random) { - privateKey, err := ed25519.GenerateKey() - if err != nil { -@@ -188,6 +206,17 @@ func GenerateKey(random io.Reader) (PublicKey, PrivateKey, error) { - // with RFC 8032. RFC 8032's private keys correspond to seeds in this - // package. - func NewKeyFromSeed(seed []byte) PrivateKey { -+ if boring.Enabled && bed25519.Supports() { -+ key, err := bed25519.NewPrivateKeyFromSeed(seed) -+ if err != nil { -+ panic(err) -+ } -+ d, err := key.Bytes() -+ if err != nil { -+ panic(err) -+ } -+ return PrivateKey(d) -+ } - // Outline the function body so that the returned key can be stack-allocated. - privateKey := make([]byte, PrivateKeySize) - newKeyFromSeed(privateKey, seed) -@@ -206,6 +235,17 @@ func newKeyFromSeed(privateKey, seed []byte) { - // Sign signs the message with privateKey and returns a signature. It will - // panic if len(privateKey) is not [PrivateKeySize]. - func Sign(privateKey PrivateKey, message []byte) []byte { -+ if boring.Enabled && bed25519.Supports() { -+ priv, err := boringPrivateKey(privateKey) -+ if err != nil { -+ panic(err) -+ } -+ signature, err := bed25519.Sign(priv, message) -+ if err != nil { -+ panic(err) -+ } -+ return signature -+ } - // Outline the function body so that the returned signature can be - // stack-allocated. - signature := make([]byte, SignatureSize) -@@ -235,6 +275,32 @@ func Verify(publicKey PublicKey, message, sig []byte) bool { - return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil - } - -+// testMalleability returns true if the crypto backend correctly rejects -+// malleable signatures. The only known backend that fails to do so is -+// OpenSSL version 1.1.1a or lower. -+// See https://github.com/openssl/openssl/issues/7693. -+var testMalleability = sync.OnceValue(func() bool { -+ msg := []byte{0x54, 0x65, 0x73, 0x74} -+ sig := []byte{ -+ 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a, -+ 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b, -+ 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67, -+ 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, -+ 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, -+ 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d, -+ } -+ pkey := []byte{ -+ 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5, -+ 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34, -+ 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa, -+ } -+ pub, err := bed25519.NewPublicKey(pkey) -+ if err != nil { -+ return false -+ } -+ return bed25519.Verify(pub, msg, sig) != nil -+}) -+ - // VerifyWithOptions reports whether sig is a valid signature of message by - // publicKey. A valid signature is indicated by returning a nil error. It will - // panic if len(publicKey) is not [PublicKeySize]. -@@ -263,6 +329,13 @@ func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) +@@ -98,7 +99,7 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp + k, err := privateKeyCache.Get(&priv[0], func() (*ed25519.PrivateKey, error) { + return ed25519.NewPrivateKey(priv) + }, func(k *ed25519.PrivateKey) bool { +- return subtle.ConstantTimeCompare(priv, k.Bytes()) == 1 ++ return subtle.ConstantTimeCompare(priv, ed25519.PrivateKeyBytes(k)) == 1 + }) + if err != nil { + return nil, err +@@ -117,7 +118,7 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp } - return ed25519.VerifyCtx(k, message, sig, opts.Context) - case opts.Hash == crypto.Hash(0): // Ed25519 -+ if boring.Enabled && bed25519.Supports() && testMalleability() { -+ pub, err := boringPublicKey(publicKey) -+ if err != nil { -+ return err -+ } -+ return bed25519.Verify(pub, message, sig) -+ } - return ed25519.Verify(k, message, sig) + return ed25519.SignCtx(k, message, context) + case hash == crypto.Hash(0): // Ed25519 +- return ed25519.Sign(k, message), nil ++ return ed25519.SignDeterministic(k, message), nil default: - return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)") + return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)") + } +@@ -197,8 +198,7 @@ func NewKeyFromSeed(seed []byte) PrivateKey { + func newKeyFromSeed(privateKey, seed []byte) { + k, err := ed25519.NewPrivateKeyFromSeed(seed) + if err != nil { +- // NewPrivateKeyFromSeed only returns an error if the seed length is incorrect. +- panic("ed25519: bad seed length: " + strconv.Itoa(len(seed))) ++ panic(err) + } + copy(privateKey, k.Bytes()) + } +@@ -217,7 +217,7 @@ func sign(signature []byte, privateKey PrivateKey, message []byte) { + k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) { + return ed25519.NewPrivateKey(privateKey) + }, func(k *ed25519.PrivateKey) bool { +- return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1 ++ return subtle.ConstantTimeCompare(privateKey, ed25519.PrivateKeyBytes(k)) == 1 + }) + if err != nil { + panic("ed25519: bad private key: " + err.Error()) diff --git a/src/crypto/ed25519/ed25519_test.go b/src/crypto/ed25519/ed25519_test.go -index c8a23e3246a949..93df783d1d6a14 100644 +index c8a23e3246a949..0489b241c1936a 100644 --- a/src/crypto/ed25519/ed25519_test.go +++ b/src/crypto/ed25519/ed25519_test.go -@@ -13,8 +13,11 @@ import ( +@@ -13,10 +13,15 @@ import ( "crypto/rand" "crypto/sha512" "encoding/hex" -+ boring "github.com/microsoft/go/cryptobackend" + "internal/systemcrypto" "log" "os" + "runtime" "strings" "testing" ++ ++ "github.com/microsoft/go/cryptobackend" ++ bed25519 "github.com/microsoft/go/cryptobackend/ed25519" ) -@@ -316,7 +319,7 @@ func TestGolden(t *testing.T) { + + func Example_ed25519ctx() { +@@ -316,7 +321,7 @@ func TestGolden(t *testing.T) { copy(priv[32:], pubKey) sig2 := Sign(priv[:], msg) @@ -2342,19 +2202,21 @@ index c8a23e3246a949..93df783d1d6a14 100644 t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2) } -@@ -371,6 +374,11 @@ func TestAllocations(t *testing.T) { +@@ -371,6 +376,13 @@ func TestAllocations(t *testing.T) { cryptotest.SkipTestAllocations(t) seed := make([]byte, SeedSize) priv := NewKeyFromSeed(seed) + expectedAllocations := 0.0 -+ if boring.Enabled { ++ if backend.Enabled && bed25519.Supports() { + expectedAllocations = 6 ++ } else if backend.Enabled && runtime.GOOS != "windows" { ++ expectedAllocations = 1 + } + if allocs := testing.AllocsPerRun(100, func() { message := []byte("Hello, world!") pub := priv.Public().(PublicKey) -@@ -378,8 +386,8 @@ func TestAllocations(t *testing.T) { +@@ -378,8 +390,8 @@ func TestAllocations(t *testing.T) { if !Verify(pub, message, signature) { t.Fatal("signature didn't verify") } @@ -2365,28 +2227,6 @@ index c8a23e3246a949..93df783d1d6a14 100644 } } -diff --git a/src/crypto/ed25519/notboring.go b/src/crypto/ed25519/notboring.go -new file mode 100644 -index 00000000000000..57c8a6106b7e2b ---- /dev/null -+++ b/src/crypto/ed25519/notboring.go -@@ -0,0 +1,16 @@ -+// Copyright 2023 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 ed25519 -+ -+import bed25519 "github.com/microsoft/go/cryptobackend/ed25519" -+ -+func boringPublicKey(PublicKey) (bed25519.PublicKey, error) { -+ panic("boringcrypto: not available") -+} -+func boringPrivateKey(PrivateKey) (bed25519.PrivateKey, error) { -+ panic("boringcrypto: not available") -+} diff --git a/src/crypto/fips140/enforcement_test.go b/src/crypto/fips140/enforcement_test.go index d230c0f4ec1fa1..bd536dd39a0585 100644 --- a/src/crypto/fips140/enforcement_test.go @@ -4418,7 +4258,7 @@ index bc59300f41c762..698bc79a80aead 100644 } diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go -index d32d815261d9e1..0911f6bb20e2d2 100644 +index 198692f5aaa6e5..5c1a31f1c09f3b 100644 --- a/src/crypto/x509/verify_test.go +++ b/src/crypto/x509/verify_test.go @@ -3127,7 +3127,7 @@ func dsaSelfSignedCNX(t *testing.T) []byte { @@ -4487,7 +4327,7 @@ index 00000000000000..ffb835ce34a2f7 + } +} diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go -index 926a533c9c1fb8..5c5c45e441f9b7 100644 +index 926a533c9c1fb8..2e86f85ffc2da1 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -377,8 +377,10 @@ var depsRules = ` @@ -4533,7 +4373,7 @@ index 926a533c9c1fb8..5c5c45e441f9b7 100644 < crypto/internal/fips140only < crypto < crypto/subtle -@@ -583,6 +598,40 @@ var depsRules = ` +@@ -583,6 +598,39 @@ var depsRules = ` github.com/microsoft/go-crypto-winnative/internal/bcrypt < github.com/microsoft/go-crypto-winnative/cng; @@ -4558,7 +4398,6 @@ index 926a533c9c1fb8..5c5c45e441f9b7 100644 + github.com/microsoft/go/cryptobackend/aes/gcm, + github.com/microsoft/go/cryptobackend/des, + github.com/microsoft/go/cryptobackend/drbg, -+ github.com/microsoft/go/cryptobackend/ed25519, + github.com/microsoft/go/cryptobackend/hkdf, + github.com/microsoft/go/cryptobackend/hmac, + github.com/microsoft/go/cryptobackend/md5, @@ -4574,7 +4413,7 @@ index 926a533c9c1fb8..5c5c45e441f9b7 100644 FIPS, internal/godebug, embed, crypto/internal/boring/sig, crypto/internal/boring/syso, -@@ -590,7 +639,9 @@ var depsRules = ` +@@ -590,7 +638,9 @@ var depsRules = ` crypto/internal/fips140only, crypto, crypto/subtle, @@ -4585,7 +4424,7 @@ index 926a533c9c1fb8..5c5c45e441f9b7 100644 < crypto/sha3 < crypto/internal/fips140hash < crypto/internal/boring -@@ -605,15 +656,15 @@ var depsRules = ` +@@ -605,15 +655,15 @@ var depsRules = ` crypto/sha512, crypto/hmac, crypto/hkdf, @@ -4605,7 +4444,7 @@ index 926a533c9c1fb8..5c5c45e441f9b7 100644 CGO, fmt, net !< CRYPTO; # CRYPTO-MATH is crypto that exposes math/big APIs - no cgo, net; fmt now ok. -@@ -622,15 +673,32 @@ var depsRules = ` +@@ -622,15 +672,33 @@ var depsRules = ` math/big, github.com/microsoft/go-crypto-darwin/xcrypto < github.com/microsoft/go-crypto-darwin/bbig; math/big, github.com/microsoft/go-crypto-winnative/cng < github.com/microsoft/go-crypto-winnative/cng/bbig; @@ -4624,6 +4463,7 @@ index 926a533c9c1fb8..5c5c45e441f9b7 100644 < crypto/internal/fips140cache < crypto/rand + < github.com/microsoft/go/cryptobackend/ecdh, ++ github.com/microsoft/go/cryptobackend/ed25519, + github.com/microsoft/go/cryptobackend/mldsa, + github.com/microsoft/go/cryptobackend/mlkem + < crypto/ecdh, crypto/mldsa, crypto/mlkem