aboutsummaryrefslogtreecommitdiff
path: root/x509roots/fallback/bundle/roots.go
diff options
context:
space:
mode:
Diffstat (limited to 'x509roots/fallback/bundle/roots.go')
-rw-r--r--x509roots/fallback/bundle/roots.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/x509roots/fallback/bundle/roots.go b/x509roots/fallback/bundle/roots.go
new file mode 100644
index 0000000..38a1b3d
--- /dev/null
+++ b/x509roots/fallback/bundle/roots.go
@@ -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
+}