Allow block-a-key to process private key files (#7737)

The CAB/F Debian weak keys (https://github.com/cabforum/Debian-weak-keys)
repository contains a bunch of DER encoded private keys that we should ensure
are blocked. I hacked up the block-a-key tool to output a base64 encoded SPKI
hash from an arbitrary PEM formatted private key file.
This commit is contained in:
Phil Porada 2024-10-07 14:56:14 -04:00 committed by GitHub
parent 7b032a663f
commit 56d392793a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 14 deletions

View File

@ -10,6 +10,7 @@ import (
"os"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/privatekey"
"github.com/letsencrypt/boulder/web"
)
@ -29,8 +30,9 @@ installation:
go install github.com/letsencrypt/boulder/test/block-a-key/...
usage:
block-a-key -cert <PEM encoded x509 certificate file>
block-a-key -cert <PEM formatted x509 certificate file>
block-a-key -jwk <JSON encoded JWK file>
block-a-key -privateKey <PEM formatted private key file>
output format:
# <filepath>
@ -41,10 +43,21 @@ examples:
./test/block-a-key/test/test.ecdsa.jwk.json cuwGhNNI6nfob5aqY90e7BleU6l7rfxku4X3UTJ3Z7M=
$> block-a-key -cert ./test/block-a-key/test/test.rsa.cert.pem
./test/block-a-key/test/test.rsa.cert.pem Qebc1V3SkX3izkYRGNJilm9Bcuvf0oox4U2Rn+b4JOE=
$> block-a-key -privateKey private.key
`
// keyFromCert returns the public key from a PEM encoded certificate located in
// pemFile or returns an error.
// keyFromPrivateKeyFile returns the public key from a PEM formatted private key
// located in pemFile or returns an error.
func keyFromPrivateKeyFile(pemFile string) (crypto.PublicKey, error) {
_, pubKey, err := privatekey.Load(pemFile)
if err != nil {
return nil, err
}
return pubKey, nil
}
// keyFromCert returns the public key from a PEM formatted certificate located
// in pemFile or returns an error.
func keyFromCert(pemFile string) (crypto.PublicKey, error) {
c, err := core.LoadCert(pemFile)
if err != nil {
@ -64,8 +77,9 @@ func keyFromJWK(jsonFile string) (crypto.PublicKey, error) {
}
func main() {
certFileArg := flag.String("cert", "", "path to a PEM encoded X509 certificate file")
certFileArg := flag.String("cert", "", "path to a PEM formatted X509 certificate file")
jwkFileArg := flag.String("jwk", "", "path to a JSON encoded JWK file")
privKeyFileArg := flag.String("privateKey", "", "path to a PEM formatted private key file")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s\n\n", usageHelp)
@ -75,12 +89,12 @@ func main() {
flag.Parse()
if *certFileArg == "" && *jwkFileArg == "" {
log.Fatalf("error: a -cert or -jwk argument must be provided")
if *certFileArg == "" && *jwkFileArg == "" && *privKeyFileArg == "" {
log.Fatalf("error: a -cert, -jwk, or -privateKey argument must be provided")
}
if *certFileArg != "" && *jwkFileArg != "" {
log.Fatalf("error: -cert and -jwk arguments are mutually exclusive")
if *certFileArg != "" && *jwkFileArg != "" && *privKeyFileArg != "" {
log.Fatalf("error: -cert, -jwk, and -privateKey arguments are mutually exclusive")
}
var file string
@ -93,6 +107,9 @@ func main() {
} else if *jwkFileArg != "" {
file = *jwkFileArg
key, err = keyFromJWK(file)
} else if *privKeyFileArg != "" {
file = *privKeyFileArg
key, err = keyFromPrivateKeyFile(file)
} else {
err = errors.New("unexpected command line state")
}

View File

@ -10,10 +10,11 @@ import (
func TestKeyBlocking(t *testing.T) {
testCases := []struct {
name string
certPath string
jwkPath string
expected string
name string
certPath string
jwkPath string
privKeyPath string
expected string
}{
// NOTE(@cpu): The JWKs and certificates were generated with the same
// keypair within an algorithm/parameter family. E.g. the RSA JWK public key
@ -39,16 +40,28 @@ func TestKeyBlocking(t *testing.T) {
certPath: "test/test.rsa.cert.pem",
expected: "Qebc1V3SkX3izkYRGNJilm9Bcuvf0oox4U2Rn+b4JOE=",
},
{
name: "P-256 ECDSA Private Key",
privKeyPath: "../hierarchy/ee-e1.key.pem",
expected: "ysCgov5oH7fsFs+ry0ODIx7runcINcS8V/0a0NWNQSY=",
},
{
name: "2048 RSA Private Key",
privKeyPath: "../hierarchy/ee-r4.key.pem",
expected: "ClG5+g8ypi7kMF6mxMT+gszQbwLjPsIv9mHNVjOv4FU=",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var key crypto.PublicKey
var err error
if tc.jwkPath != "" {
if tc.certPath != "" {
key, err = keyFromCert(tc.certPath)
} else if tc.jwkPath != "" {
key, err = keyFromJWK(tc.jwkPath)
} else {
key, err = keyFromCert(tc.certPath)
key, err = keyFromPrivateKeyFile(tc.privKeyPath)
}
test.AssertNotError(t, err, "error getting key from input file")
spkiHash, err := core.KeyDigestB64(key)