goos: linux
goarch: amd64
pkg: golang.org/x/crypto/x509roots/fallback
cpu: AMD Ryzen 5 4600G with Radeon Graphics
│ /tmp/before │ /tmp/after │
│ sec/op │ sec/op vs base │
InitTime-12 1.726m ± 0% 1.101m ± 1% -36.20% (p=0.000 n=30)
│ /tmp/before │ /tmp/after │
│ B/op │ B/op vs base │
InitTime-12 1178.2Ki ± 0% 779.8Ki ± 0% -33.81% (p=0.000 n=30)
│ /tmp/before │ /tmp/after │
│ allocs/op │ allocs/op vs base │
InitTime-12 11.35k ± 0% 10.64k ± 0% -6.32% (p=0.000 n=30)
Updates golang/go#73691
Change-Id: Ic33f2fdfc65001c41afeb3b6af8a383288d10de6
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/676217
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Freeman <mark@golang.org>
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
// 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.
|
|
|
|
// Package fallback embeds a set of fallback X.509 trusted roots in the
|
|
// application by automatically invoking [x509.SetFallbackRoots]. This allows
|
|
// the application to work correctly even if the operating system does not
|
|
// provide a verifier or system roots pool.
|
|
//
|
|
// To use it, import the package like
|
|
//
|
|
// import _ "golang.org/x/crypto/x509roots/fallback"
|
|
//
|
|
// It's recommended that only binaries, and not libraries, import this package.
|
|
//
|
|
// This package must be kept up to date for security and compatibility reasons.
|
|
// Use govulncheck to be notified of when new versions of the package are
|
|
// available.
|
|
package fallback
|
|
|
|
import (
|
|
"crypto/x509"
|
|
_ "embed"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
//go:embed bundle.der
|
|
var rawCerts []byte
|
|
|
|
func init() {
|
|
x509.SetFallbackRoots(newFallbackCertPool())
|
|
}
|
|
|
|
func newFallbackCertPool() *x509.CertPool {
|
|
p := x509.NewCertPool()
|
|
for _, c := range mustParse(unparsedCertificates) {
|
|
if len(c.constraints) == 0 {
|
|
p.AddCert(c.cert)
|
|
} else {
|
|
p.AddCertWithConstraint(c.cert, func(chain []*x509.Certificate) error {
|
|
for _, constraint := range c.constraints {
|
|
if err := constraint(chain); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
type unparsedCertificate struct {
|
|
cn string
|
|
sha256Hash string
|
|
certStartOff int
|
|
certLength int
|
|
|
|
// possible constraints
|
|
distrustAfter string
|
|
}
|
|
|
|
type parsedCertificate struct {
|
|
cert *x509.Certificate
|
|
constraints []func([]*x509.Certificate) error
|
|
}
|
|
|
|
func mustParse(unparsedCerts []unparsedCertificate) []parsedCertificate {
|
|
b := make([]parsedCertificate, 0, len(unparsedCerts))
|
|
for _, unparsed := range unparsedCerts {
|
|
cert, err := x509.ParseCertificate(rawCerts[unparsed.certStartOff : unparsed.certStartOff+unparsed.certLength])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
parsed := parsedCertificate{cert: cert}
|
|
// parse possible constraints, this should check all fields of unparsedCertificate.
|
|
if unparsed.distrustAfter != "" {
|
|
distrustAfter, err := time.Parse(time.RFC3339, unparsed.distrustAfter)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("failed to parse distrustAfter %q: %s", unparsed.distrustAfter, err))
|
|
}
|
|
parsed.constraints = append(parsed.constraints, func(chain []*x509.Certificate) error {
|
|
for _, c := range chain {
|
|
if c.NotBefore.After(distrustAfter) {
|
|
return fmt.Errorf("certificate issued after distrust-after date %q", distrustAfter)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
b = append(b, parsed)
|
|
}
|
|
return b
|
|
}
|