x509roots/fallback/bundle: add bundle package to export root certs
Fixes golang/go#69898 Change-Id: Idbb1bbe48016a622414c84a56fe26f48bfe712c8 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/687155 Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Roland Shoemaker <roland@golang.org> Reviewed-by: Mateusz Poliwczak <mpoliwczak34@gmail.com>
This commit is contained in:
committed by
Gopher Robot
parent
8c9ba31836
commit
96dc232fbd
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
||||||
|
|
||||||
package fallback
|
package bundle
|
||||||
|
|
||||||
var unparsedCertificates = []unparsedCertificate{
|
var unparsedCertificates = []unparsedCertificate{
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package fallback
|
package bundle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// 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 bundle contains the bundle of root certificates parsed from the NSS
|
||||||
|
// trust store, using x509roots/nss.
|
||||||
|
package bundle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"iter"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed bundle.der
|
||||||
|
var rawCerts []byte
|
||||||
|
|
||||||
|
// Root represents a root certificate parsed from the NSS trust store.
|
||||||
|
type Root struct {
|
||||||
|
// Certificate is the DER-encoded certificate (read-only; do not modify!).
|
||||||
|
Certificate []byte
|
||||||
|
|
||||||
|
// Constraint is nil if the root is unconstrained. If Constraint is non-nil,
|
||||||
|
// the certificate has additional constraints that cannot be encoded in
|
||||||
|
// X.509, and when building a certificate chain anchored with this root the
|
||||||
|
// chain should be passed to this function to check its validity. If using a
|
||||||
|
// [crypto/x509.CertPool] the root should be added using
|
||||||
|
// [crypto/x509.CertPool.AddCertWithConstraint].
|
||||||
|
Constraint func([]*x509.Certificate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roots returns the bundle of root certificates from the NSS trust store. The
|
||||||
|
// [Root.Certificate] slice must be treated as read-only and should not be
|
||||||
|
// modified.
|
||||||
|
func Roots() iter.Seq[Root] {
|
||||||
|
return func(yield func(Root) bool) {
|
||||||
|
for _, unparsed := range unparsedCertificates {
|
||||||
|
root := Root{
|
||||||
|
Certificate: rawCerts[unparsed.certStartOff : unparsed.certStartOff+unparsed.certLength],
|
||||||
|
}
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
|
root.Constraint = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !yield(root) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type unparsedCertificate struct {
|
||||||
|
cn string
|
||||||
|
sha256Hash string
|
||||||
|
certStartOff int
|
||||||
|
certLength int
|
||||||
|
|
||||||
|
// possible constraints
|
||||||
|
distrustAfter string
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// 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 bundle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRootsCanBeParsed(t *testing.T) {
|
||||||
|
for root := range Roots() {
|
||||||
|
if _, err := x509.ParseCertificate(root.Certificate); err != nil {
|
||||||
|
t.Fatalf("Could not parse root certificate: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,13 +20,9 @@ package fallback
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
_ "embed"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed bundle.der
|
"golang.org/x/crypto/x509roots/fallback/bundle"
|
||||||
var rawCerts []byte
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
x509.SetFallbackRoots(newFallbackCertPool())
|
x509.SetFallbackRoots(newFallbackCertPool())
|
||||||
@@ -34,62 +30,16 @@ func init() {
|
|||||||
|
|
||||||
func newFallbackCertPool() *x509.CertPool {
|
func newFallbackCertPool() *x509.CertPool {
|
||||||
p := x509.NewCertPool()
|
p := x509.NewCertPool()
|
||||||
for _, c := range mustParse(unparsedCertificates) {
|
for c := range bundle.Roots() {
|
||||||
if len(c.constraints) == 0 {
|
cert, err := x509.ParseCertificate(c.Certificate)
|
||||||
p.AddCert(c.cert)
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if c.Constraint == nil {
|
||||||
|
p.AddCert(cert)
|
||||||
} else {
|
} else {
|
||||||
p.AddCertWithConstraint(c.cert, func(chain []*x509.Certificate) error {
|
p.AddCertWithConstraint(cert, c.Constraint)
|
||||||
for _, constraint := range c.constraints {
|
|
||||||
if err := constraint(chain); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
|
|
||||||
const tmpl = `// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
const tmpl = `// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
|
||||||
|
|
||||||
package fallback
|
package bundle
|
||||||
|
|
||||||
var unparsedCertificates = []unparsedCertificate{
|
var unparsedCertificates = []unparsedCertificate{
|
||||||
`
|
`
|
||||||
@@ -35,8 +35,8 @@ var unparsedCertificates = []unparsedCertificate{
|
|||||||
var (
|
var (
|
||||||
certDataURL = flag.String("certdata-url", "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt", "URL to the raw certdata.txt file to parse (certdata-path overrides this, if provided)")
|
certDataURL = flag.String("certdata-url", "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt", "URL to the raw certdata.txt file to parse (certdata-path overrides this, if provided)")
|
||||||
certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (this overrides certdata-url, if provided)")
|
certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (this overrides certdata-url, if provided)")
|
||||||
output = flag.String("output", "fallback/bundle.go", "Path to file to write output to")
|
output = flag.String("output", "fallback/bundle/bundle.go", "Path to file to write output to")
|
||||||
derOutput = flag.String("deroutput", "fallback/bundle.der", "Path to file to write output to (DER certificate bundle)")
|
derOutput = flag.String("deroutput", "fallback/bundle/bundle.der", "Path to file to write output to (DER certificate bundle)")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
Reference in New Issue
Block a user