...
1
2 package main
3
4 import (
5 "crypto"
6 "errors"
7 "flag"
8 "fmt"
9 "log"
10 "os"
11
12 "github.com/letsencrypt/boulder/core"
13 "github.com/letsencrypt/boulder/web"
14 )
15
16 const usageHelp = `
17 block-a-key is utility tool for generating a SHA256 hash of the SubjectPublicKeyInfo
18 from a certificate or a synthetic SubjectPublicKeyInfo generated from a JWK public key.
19 It outputs the Base64 encoding of that hash.
20
21 The produced encoded digest can be used with Boulder's key blocklist to block
22 any ACME account creation or certificate requests that use the same public
23 key.
24
25 If you already have an SPKI hash, and it's a SHA256 hash, you can add it directly
26 to the key blocklist. If it's in hex form you'll need to convert it to base64 first.
27
28 installation:
29 go install github.com/letsencrypt/boulder/test/block-a-key/...
30
31 usage:
32 block-a-key -cert <PEM encoded x509 certificate file>
33 block-a-key -jwk <JSON encoded JWK file>
34
35 output format:
36 # <filepath>
37 - "<base64 encoded SHA256 subject public key digest>"
38
39 examples:
40 $> block-a-key -jwk ./test/block-a-key/test/test.ecdsa.jwk.json
41 ./test/block-a-key/test/test.ecdsa.jwk.json cuwGhNNI6nfob5aqY90e7BleU6l7rfxku4X3UTJ3Z7M=
42 $> block-a-key -cert ./test/block-a-key/test/test.rsa.cert.pem
43 ./test/block-a-key/test/test.rsa.cert.pem Qebc1V3SkX3izkYRGNJilm9Bcuvf0oox4U2Rn+b4JOE=
44 `
45
46
47
48 func keyFromCert(pemFile string) (crypto.PublicKey, error) {
49 c, err := core.LoadCert(pemFile)
50 if err != nil {
51 return nil, err
52 }
53 return c.PublicKey, nil
54 }
55
56
57
58 func keyFromJWK(jsonFile string) (crypto.PublicKey, error) {
59 jwk, err := web.LoadJWK(jsonFile)
60 if err != nil {
61 return nil, err
62 }
63 return jwk.Key, nil
64 }
65
66 func main() {
67 certFileArg := flag.String("cert", "", "path to a PEM encoded X509 certificate file")
68 jwkFileArg := flag.String("jwk", "", "path to a JSON encoded JWK file")
69
70 flag.Usage = func() {
71 fmt.Fprintf(os.Stderr, "%s\n\n", usageHelp)
72 fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
73 flag.PrintDefaults()
74 }
75
76 flag.Parse()
77
78 if *certFileArg == "" && *jwkFileArg == "" {
79 log.Fatalf("error: a -cert or -jwk argument must be provided")
80 }
81
82 if *certFileArg != "" && *jwkFileArg != "" {
83 log.Fatalf("error: -cert and -jwk arguments are mutually exclusive")
84 }
85
86 var file string
87 var key crypto.PublicKey
88 var err error
89
90 if *certFileArg != "" {
91 file = *certFileArg
92 key, err = keyFromCert(file)
93 } else if *jwkFileArg != "" {
94 file = *jwkFileArg
95 key, err = keyFromJWK(file)
96 } else {
97 err = errors.New("unexpected command line state")
98 }
99 if err != nil {
100 log.Fatalf("error loading public key: %v", err)
101 }
102
103 spkiHash, err := core.KeyDigestB64(key)
104 if err != nil {
105 log.Fatalf("error computing spki hash: %v", err)
106 }
107 fmt.Printf(" # %s\n - %s\n", file, spkiHash)
108 }
109
View as plain text