109 lines
3.0 KiB
Go
109 lines
3.0 KiB
Go
// block-a-key is a small utility for creating key blocklist entries.
|
|
package main
|
|
|
|
import (
|
|
"crypto"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"github.com/letsencrypt/boulder/core"
|
|
"github.com/letsencrypt/boulder/web"
|
|
)
|
|
|
|
const usageHelp = `
|
|
block-a-key is utility tool for generating a SHA256 hash of the SubjectPublicKeyInfo
|
|
from a certificate or a synthetic SubjectPublicKeyInfo generated from a JWK public key.
|
|
It outputs the Base64 encoding of that hash.
|
|
|
|
The produced encoded digest can be used with Boulder's key blocklist to block
|
|
any ACME account creation or certificate requests that use the same public
|
|
key.
|
|
|
|
If you already have an SPKI hash, and it's a SHA256 hash, you can add it directly
|
|
to the key blocklist. If it's in hex form you'll need to convert it to base64 first.
|
|
|
|
installation:
|
|
go install github.com/letsencrypt/boulder/test/block-a-key/...
|
|
|
|
usage:
|
|
block-a-key -cert <PEM encoded x509 certificate file>
|
|
block-a-key -jwk <JSON encoded JWK file>
|
|
|
|
output format:
|
|
# <filepath>
|
|
- "<base64 encoded SHA256 subject public key digest>"
|
|
|
|
examples:
|
|
$> block-a-key -jwk ./test/block-a-key/test/test.ecdsa.jwk.json
|
|
./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=
|
|
`
|
|
|
|
// keyFromCert returns the public key from a PEM encoded certificate located in
|
|
// pemFile or returns an error.
|
|
func keyFromCert(pemFile string) (crypto.PublicKey, error) {
|
|
c, err := core.LoadCert(pemFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return c.PublicKey, nil
|
|
}
|
|
|
|
// keyFromJWK returns the public key from a JSON encoded JOSE JWK located in
|
|
// jsonFile or returns an error.
|
|
func keyFromJWK(jsonFile string) (crypto.PublicKey, error) {
|
|
jwk, err := web.LoadJWK(jsonFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return jwk.Key, nil
|
|
}
|
|
|
|
func main() {
|
|
certFileArg := flag.String("cert", "", "path to a PEM encoded X509 certificate file")
|
|
jwkFileArg := flag.String("jwk", "", "path to a JSON encoded JWK file")
|
|
|
|
flag.Usage = func() {
|
|
fmt.Fprintf(os.Stderr, "%s\n\n", usageHelp)
|
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
|
flag.PrintDefaults()
|
|
}
|
|
|
|
flag.Parse()
|
|
|
|
if *certFileArg == "" && *jwkFileArg == "" {
|
|
log.Fatalf("error: a -cert or -jwk argument must be provided")
|
|
}
|
|
|
|
if *certFileArg != "" && *jwkFileArg != "" {
|
|
log.Fatalf("error: -cert and -jwk arguments are mutually exclusive")
|
|
}
|
|
|
|
var file string
|
|
var key crypto.PublicKey
|
|
var err error
|
|
|
|
if *certFileArg != "" {
|
|
file = *certFileArg
|
|
key, err = keyFromCert(file)
|
|
} else if *jwkFileArg != "" {
|
|
file = *jwkFileArg
|
|
key, err = keyFromJWK(file)
|
|
} else {
|
|
err = errors.New("unexpected command line state")
|
|
}
|
|
if err != nil {
|
|
log.Fatalf("error loading public key: %v", err)
|
|
}
|
|
|
|
spkiHash, err := core.KeyDigestB64(key)
|
|
if err != nil {
|
|
log.Fatalf("error computing spki hash: %v", err)
|
|
}
|
|
fmt.Printf(" # %s\n - %s\n", file, spkiHash)
|
|
}
|