-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds the nss parser, under x509roots/nss, and the fallback module/package, with the initial generated bundle. Fixes golang/go#57792 Change-Id: Iebb1052e49126fa5baba1236f4ebc8dd8a823179 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/462036 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Roland Shoemaker <roland@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org> Reviewed-by: Damien Neil <dneil@google.com> Auto-Submit: Roland Shoemaker <roland@golang.org>
- Loading branch information
1 parent
1622238
commit d0b3160
Showing
6 changed files
with
5,388 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// 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. | ||
|
||
//go:build go1.20 | ||
// +build go1.20 | ||
|
||
// 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" | ||
|
||
func init() { | ||
p := x509.NewCertPool() | ||
for _, c := range bundle { | ||
p.AddCert(c) | ||
} | ||
x509.SetFallbackRoots(p) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module golang.org/x/crypto/x509roots/fallback | ||
|
||
go 1.20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// 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. | ||
|
||
//go:build gen | ||
// +build gen | ||
|
||
//go:generate go run gen_fallback_bundle.go | ||
|
||
package main | ||
|
||
import ( | ||
"bytes" | ||
"crypto/sha256" | ||
"encoding/pem" | ||
"flag" | ||
"fmt" | ||
"go/format" | ||
"io" | ||
"log" | ||
"net/http" | ||
"os" | ||
"sort" | ||
"time" | ||
|
||
"golang.org/x/crypto/x509roots/nss" | ||
) | ||
|
||
const tmpl = `// Code generated by gen.go at %s; DO NOT EDIT. | ||
// list hash: %x | ||
package fallback | ||
import "crypto/x509" | ||
import "encoding/pem" | ||
func mustParse(b []byte) []*x509.Certificate { | ||
var roots []*x509.Certificate | ||
for len(b) > 0 { | ||
var block *pem.Block | ||
block, b = pem.Decode(b) | ||
if block == nil { | ||
break | ||
} | ||
if block.Type != "CERTIFICATE" { | ||
panic("unexpected PEM block type: "+block.Type) | ||
} | ||
cert, err := x509.ParseCertificate(block.Bytes) | ||
if err != nil { | ||
panic(err) | ||
} | ||
roots = append(roots, cert) | ||
} | ||
return roots | ||
} | ||
var bundle = mustParse([]byte(pemRoots)) | ||
// Format of the PEM list is: | ||
// * Subject common name | ||
// * SHA256 hash | ||
// * PEM block | ||
` | ||
|
||
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 (only one of certdata-url and certdata-path may be specified)") | ||
certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (only one of certdata-url and certdata-path may be specified)") | ||
output = flag.String("output", "fallback/bundle.go", "Path to file to write output to") | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
if *certDataPath != "" && *certDataURL != "" { | ||
log.Fatal("Only one of --certdata-url and --certdata-path may be supplied") | ||
} | ||
|
||
var certdata io.Reader | ||
|
||
if *certDataPath != "" { | ||
f, err := os.Open(*certDataPath) | ||
if err != nil { | ||
log.Fatalf("unable to open %q: %s", *certDataPath, err) | ||
} | ||
defer f.Close() | ||
certdata = f | ||
} else { | ||
resp, err := http.Get(*certDataURL) | ||
if err != nil { | ||
log.Fatalf("failed to request %q: %s", *certDataURL, err) | ||
} | ||
defer resp.Body.Close() | ||
certdata = resp.Body | ||
} | ||
|
||
certs, err := nss.Parse(certdata) | ||
if err != nil { | ||
log.Fatalf("failed to parse %q: %s", *certDataPath, err) | ||
} | ||
|
||
sort.Slice(certs, func(i, j int) bool { | ||
return certs[i].X509.Subject.String() < certs[j].X509.Subject.String() | ||
}) | ||
|
||
h := sha256.New() | ||
for _, c := range certs { | ||
h.Write(c.X509.Raw) | ||
} | ||
listHash := h.Sum(nil) | ||
|
||
b := bytes.NewBuffer(nil) | ||
b.Write([]byte(fmt.Sprintf(tmpl, time.Now().Format(time.RFC1123), listHash))) | ||
b.Write([]byte("const pemRoots = `\n")) | ||
for _, c := range certs { | ||
if len(c.Constraints) > 0 { | ||
// Until the constrained roots API lands, skip anything that has any | ||
// additional constraints. Once that API is available, we can add | ||
// build constraints that support both the current version and the | ||
// new version. | ||
continue | ||
} | ||
b.Write([]byte(fmt.Sprintf("# %s\n# %x\n", c.X509.Subject.String(), sha256.Sum256(c.X509.Raw)))) | ||
pem.Encode(b, &pem.Block{Type: "CERTIFICATE", Bytes: c.X509.Raw}) | ||
} | ||
b.Write([]byte("`\n")) | ||
|
||
formatted, err := format.Source(b.Bytes()) | ||
if err != nil { | ||
log.Fatalf("failed to format source: %s", err) | ||
} | ||
|
||
if err := os.WriteFile(*output, formatted, 0644); err != nil { | ||
log.Fatalf("failed to write to %q: %s", *output, err) | ||
} | ||
} |
Oops, something went wrong.