Files
Michael Stapelberg 96dc232fbd 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>
2025-09-11 08:14:50 -07:00

74 lines
2.2 KiB
Go

// 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
}