Compare commits

...

6 Commits

Author SHA1 Message Date
Bas Westerbaan 357571e787
Merge fa2ee19f65 into 49cdf0c42e 2025-06-20 15:32:00 -04:00
Damien Neil 49cdf0c42e testing, testing/synctest: handle T.Helper in synctest bubbles
Fixes #74199

Change-Id: I6a15fbd59a3a3f8c496440f56d09d695e1504e4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/682576
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
2025-06-20 12:29:58 -07:00
cuishuang 3bf1eecbd3 runtime: fix struct comment
Change-Id: I0c33830b13c8a187ac82504c7653abb8f8cf7530
Reviewed-on: https://go-review.googlesource.com/c/go/+/681655
Reviewed-by: Sean Liao <sean@liao.dev>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Sean Liao <sean@liao.dev>
2025-06-20 11:28:03 -07:00
Sean Liao 8ed23a2936 crypto/cipher: fix link to crypto/aes
Fixes #74309

Change-Id: I4d97514355d825124a8d879c2590b45b039f5fd1
Reviewed-on: https://go-review.googlesource.com/c/go/+/682596
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-06-20 11:09:26 -07:00
Adam Bender ef60769b46 go/doc: add a golden test that reproduces #62640
For #62640.
For #61394.

This is a copy of https://go-review.googlesource.com/c/go/+/528402,
which has stalled in review and the owner is no longer working on Go.

Change-Id: Ic7a1ae65c70d4857ab1061ccae1a926bf5c4ff55
Reviewed-on: https://go-review.googlesource.com/c/go/+/681235
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
2025-06-20 10:05:12 -07:00
Bas Westerbaan fa2ee19f65 x509: Add VerifyOptions.UnknownAlgorithmVerifier
This allows callers to verify certificates using algorithms that Go
does not support (yet).

For instance, here we're verifying the ML-KEM-512 example certificate
from the LAMPS WG signed by a ML-DSA-44 public key.

    https://github.com/lamps-wg/dilithium-certificates/blob/main/examples/ML-DSA-44.crt
    https://github.com/lamps-wg/kyber-certificates/blob/main/example/ML-KEM-512.crt

package main

import (
        "crypto/x509"
        "crypto/x509/pkix"
        "encoding/asn1"
        "encoding/pem"
        "errors"
        "fmt"
        "github.com/cloudflare/circl/sign/schemes"
        "os"
)

func loadCert(path string) (*x509.Certificate, error) {
        raw, err := os.ReadFile(path)
        if err != nil {
                return nil, fmt.Errorf("ReadFile(%s): %w", path, err)
        }
        block, _ := pem.Decode(raw)
        if block == nil {
                return nil, fmt.Errorf("pem.Decode(%s) failed", path)
        }
        return x509.ParseCertificate(block.Bytes)
}

func main() {
        dsaCert, err := loadCert("ML-DSA-44.crt")
        if err != nil {
                panic(err)
        }
        kemCert, err := loadCert("ML-KEM-512.crt")
        if err != nil {
                panic(err)
        }

        roots := x509.NewCertPool()
        roots.AddCert(dsaCert)
        _, err = kemCert.Verify(x509.VerifyOptions{
                Roots: roots,
                UnknownAlgorithmVerifier: func(alg pkix.AlgorithmIdentifier,
                        signed, signature, pk []byte) error {
                        if !alg.Algorithm.Equal(asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 17}) {
                                return errors.New("unsupported scheme")
                        }
                        scheme := schemes.ByName("ML-DSA-44")
                        ppk, err := scheme.UnmarshalBinaryPublicKey(pk)
                        if err != nil {
                                return err
                        }
                        if !scheme.Verify(ppk, signed, signature, nil) {
                                return errors.New("invalid signature")
                        }
                        return nil
                },
        })
        if err != nil {
                panic(err)
        }
}
2025-06-06 13:19:43 +02:00
13 changed files with 168 additions and 20 deletions

View File

@ -82,7 +82,7 @@ func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
// NewGCMWithRandomNonce returns the given cipher wrapped in Galois Counter // NewGCMWithRandomNonce returns the given cipher wrapped in Galois Counter
// Mode, with randomly-generated nonces. The cipher must have been created by // Mode, with randomly-generated nonces. The cipher must have been created by
// [aes.NewCipher]. // [crypto/aes.NewCipher].
// //
// It generates a random 96-bit nonce, which is prepended to the ciphertext by Seal, // It generates a random 96-bit nonce, which is prepended to the ciphertext by Seal,
// and is extracted from the ciphertext by Open. The NonceSize of the AEAD is zero, // and is extracted from the ciphertext by Open. The NonceSize of the AEAD is zero,

View File

@ -1038,11 +1038,14 @@ func parseCertificate(der []byte) (*Certificate, error) {
if !spki.ReadASN1BitString(&spk) { if !spki.ReadASN1BitString(&spk) {
return nil, errors.New("x509: malformed subjectPublicKey") return nil, errors.New("x509: malformed subjectPublicKey")
} }
if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { pki := &publicKeyInfo{
cert.PublicKey, err = parsePublicKey(&publicKeyInfo{ Algorithm: pkAI,
Algorithm: pkAI, PublicKey: spk,
PublicKey: spk, }
}) if cert.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
cert.PublicKey = pki
} else {
cert.PublicKey, err = parsePublicKey(pki)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -190,8 +190,8 @@ func verifyChain(c *Certificate, chainCtx *syscall.CertChainContext, opts *Verif
if parent.PublicKeyAlgorithm != ECDSA { if parent.PublicKeyAlgorithm != ECDSA {
continue continue
} }
if err := parent.CheckSignature(chain[i].SignatureAlgorithm, if err := checkSignature(chain[i].SignatureAlgorithm,
chain[i].RawTBSCertificate, chain[i].Signature); err != nil { chain[i].RawTBSCertificate, chain[i].Signature, parent.PublicKey, true, opts); err != nil {
return nil, err return nil, err
} }
} }

View File

@ -218,6 +218,10 @@ type VerifyOptions struct {
// field implies any valid policy is acceptable. // field implies any valid policy is acceptable.
CertificatePolicies []OID CertificatePolicies []OID
// UnknownAlgorithmVerifier specifies a callback to use to verify
// a signature with an unknown AlgorithmIdentifier.
UnknownAlgorithmVerifier func(alg pkix.AlgorithmIdentifier, signed, signature, pk []byte) error
// The following policy fields are unexported, because we do not expect // The following policy fields are unexported, because we do not expect
// users to actually need to use them, but are useful for testing the // users to actually need to use them, but are useful for testing the
// policy validation code. // policy validation code.
@ -975,7 +979,7 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
return return
} }
if err := c.CheckSignatureFrom(candidate.cert); err != nil { if err := c.checkSignatureFrom(candidate.cert, opts); err != nil {
if hintErr == nil { if hintErr == nil {
hintErr = err hintErr = err
hintCert = candidate.cert hintCert = candidate.cert

View File

@ -205,6 +205,17 @@ type publicKeyInfo struct {
PublicKey asn1.BitString PublicKey asn1.BitString
} }
func (pki *publicKeyInfo) Equal(other crypto.PublicKey) bool {
pki2, ok := other.(*publicKeyInfo)
if !ok {
return false
}
return (pki.Algorithm.Algorithm.Equal(pki2.Algorithm.Algorithm) &&
bytes.Equal(pki.Algorithm.Parameters.FullBytes, pki2.Algorithm.Parameters.FullBytes) &&
pki.PublicKey.BitLength == pki2.PublicKey.BitLength &&
bytes.Equal(pki.PublicKey.Bytes, pki2.PublicKey.Bytes))
}
// RFC 5280, 4.2.1.1 // RFC 5280, 4.2.1.1
type authKeyId struct { type authKeyId struct {
Id []byte `asn1:"optional,tag:0"` Id []byte `asn1:"optional,tag:0"`
@ -909,6 +920,10 @@ func (c *Certificate) hasSANExtension() bool {
// This is a low-level API that performs very limited checks, and not a full // This is a low-level API that performs very limited checks, and not a full
// path verifier. Most users should use [Certificate.Verify] instead. // path verifier. Most users should use [Certificate.Verify] instead.
func (c *Certificate) CheckSignatureFrom(parent *Certificate) error { func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
return c.checkSignatureFrom(parent, nil)
}
func (c *Certificate) checkSignatureFrom(parent *Certificate, opts *VerifyOptions) error {
// RFC 5280, 4.2.1.9: // RFC 5280, 4.2.1.9:
// "If the basic constraints extension is not present in a version 3 // "If the basic constraints extension is not present in a version 3
// certificate, or the extension is present but the cA boolean is not // certificate, or the extension is present but the cA boolean is not
@ -923,11 +938,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
return ConstraintViolationError{} return ConstraintViolationError{}
} }
if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, false, opts)
return ErrUnsupportedAlgorithm
}
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, false)
} }
// CheckSignature verifies that signature is a valid signature over signed from // CheckSignature verifies that signature is a valid signature over signed from
@ -938,7 +949,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
// [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1] // [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1]
// signatures are currently accepted. // signatures are currently accepted.
func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error { func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
return checkSignature(algo, signed, signature, c.PublicKey, true) return checkSignature(algo, signed, signature, c.PublicKey, true, nil)
} }
func (c *Certificate) hasNameConstraints() bool { func (c *Certificate) hasNameConstraints() bool {
@ -960,10 +971,24 @@ func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm,
// checkSignature verifies that signature is a valid signature over signed from // checkSignature verifies that signature is a valid signature over signed from
// a crypto.PublicKey. // a crypto.PublicKey.
func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey, allowSHA1 bool) (err error) { func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey, allowSHA1 bool, opts *VerifyOptions) (err error) {
var hashType crypto.Hash var hashType crypto.Hash
var pubKeyAlgo PublicKeyAlgorithm var pubKeyAlgo PublicKeyAlgorithm
if algo == UnknownSignatureAlgorithm {
pki, ok := publicKey.(*publicKeyInfo)
if !ok || opts == nil || opts.UnknownAlgorithmVerifier == nil {
return ErrUnsupportedAlgorithm
}
return opts.UnknownAlgorithmVerifier(
pki.Algorithm,
signed,
signature,
pki.PublicKey.Bytes,
)
}
for _, details := range signatureAlgorithmDetails { for _, details := range signatureAlgorithmDetails {
if details.algo == algo { if details.algo == algo {
hashType = details.hash hashType = details.hash
@ -1585,7 +1610,7 @@ func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.R
} }
// Check the signature to ensure the crypto.Signer behaved correctly. // Check the signature to ensure the crypto.Signer behaved correctly.
if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil { if err := checkSignature(sigAlg, tbs, signature, key.Public(), true, nil); err != nil {
return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err) return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err)
} }
@ -2259,7 +2284,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
// CheckSignature reports whether the signature on c is valid. // CheckSignature reports whether the signature on c is valid.
func (c *CertificateRequest) CheckSignature() error { func (c *CertificateRequest) CheckSignature() error {
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true) return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true, nil)
} }
// RevocationListEntry represents an entry in the revokedCertificates // RevocationListEntry represents an entry in the revokedCertificates

22
src/go/doc/testdata/issue62640.0.golden vendored Normal file
View File

@ -0,0 +1,22 @@
//
PACKAGE issue62640
IMPORTPATH
testdata/issue62640
FILENAMES
testdata/issue62640.go
TYPES
//
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F()
//
type S struct {
E
F int
}

22
src/go/doc/testdata/issue62640.1.golden vendored Normal file
View File

@ -0,0 +1,22 @@
//
PACKAGE issue62640
IMPORTPATH
testdata/issue62640
FILENAMES
testdata/issue62640.go
TYPES
//
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F()
//
type S struct {
E
F int
}

25
src/go/doc/testdata/issue62640.2.golden vendored Normal file
View File

@ -0,0 +1,25 @@
//
PACKAGE issue62640
IMPORTPATH
testdata/issue62640
FILENAMES
testdata/issue62640.go
TYPES
//
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F()
//
type S struct {
E
F int
}
// F should be hidden within S because of the S.F field.
func (S) F()

15
src/go/doc/testdata/issue62640.go vendored Normal file
View File

@ -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.
package issue62640
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F() {}
type S struct {
E
F int
}

View File

@ -312,8 +312,10 @@ type heapArena struct {
// during marking. // during marking.
pageSpecials [pagesPerArena / 8]uint8 pageSpecials [pagesPerArena / 8]uint8
// pageUseSpanDartboard is a bitmap that indicates which spans are // pageUseSpanInlineMarkBits is a bitmap where each bit corresponds
// heap spans and also gcUsesSpanDartboard. // to a span, as only spans one page in size can have inline mark bits.
// The bit indicates that the span has a spanInlineMarkBits struct
// stored directly at the top end of the span's memory.
pageUseSpanInlineMarkBits [pagesPerArena / 8]uint8 pageUseSpanInlineMarkBits [pagesPerArena / 8]uint8
// checkmarks stores the debug.gccheckmark state. It is only // checkmarks stores the debug.gccheckmark state. It is only

View File

@ -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.
package synctest_test
import "testing"
// helperLog is a t.Helper which logs.
// Since it is a helper, the log prefix should contain
// the caller's file, not helper_test.go.
func helperLog(t *testing.T, s string) {
t.Helper()
t.Log(s)
}

View File

@ -140,6 +140,18 @@ func TestRun(t *testing.T) {
}) })
} }
func TestHelper(t *testing.T) {
runTest(t, []string{"-test.v"}, func() {
synctest.Test(t, func(t *testing.T) {
helperLog(t, "log in helper")
})
}, `^=== RUN TestHelper
synctest_test.go:.* log in helper
--- PASS: TestHelper.*
PASS
$`)
}
func wantPanic(t *testing.T, want string) { func wantPanic(t *testing.T, want string) {
if e := recover(); e != nil { if e := recover(); e != nil {
if got := fmt.Sprint(e); got != want { if got := fmt.Sprint(e); got != want {

View File

@ -1261,6 +1261,9 @@ func (c *common) Skipped() bool {
// When printing file and line information, that function will be skipped. // When printing file and line information, that function will be skipped.
// Helper may be called simultaneously from multiple goroutines. // Helper may be called simultaneously from multiple goroutines.
func (c *common) Helper() { func (c *common) Helper() {
if c.isSynctest {
c = c.parent
}
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
if c.helperPCs == nil { if c.helperPCs == nil {