@@ -22,13 +22,14 @@ import (
2222 "crypto/elliptic"
2323 "crypto/rand"
2424 "crypto/rsa"
25- "encoding/base32 "
25+ "encoding/base64 "
2626 "errors"
2727 "fmt"
28- "golang.org/x/crypto/ed25519"
2928 "io"
3029 "os"
3130
31+ "golang.org/x/crypto/ed25519"
32+
3233 "gopkg.in/alecthomas/kingpin.v2"
3334 "gopkg.in/square/go-jose.v2"
3435)
@@ -75,20 +76,32 @@ func KeygenSig(alg jose.SignatureAlgorithm, bits int) (crypto.PublicKey, crypto.
7576 case jose .ES256 :
7677 // The cryptographic operations are implemented using constant-time algorithms.
7778 key , err := ecdsa .GenerateKey (elliptic .P256 (), rand .Reader )
79+ if err != nil {
80+ return nil , nil , err
81+ }
7882 return key .Public (), key , err
7983 case jose .ES384 :
8084 // NB: The cryptographic operations do not use constant-time algorithms.
8185 key , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
86+ if err != nil {
87+ return nil , nil , err
88+ }
8289 return key .Public (), key , err
8390 case jose .ES512 :
8491 // NB: The cryptographic operations do not use constant-time algorithms.
8592 key , err := ecdsa .GenerateKey (elliptic .P521 (), rand .Reader )
93+ if err != nil {
94+ return nil , nil , err
95+ }
8696 return key .Public (), key , err
8797 case jose .EdDSA :
8898 pub , key , err := ed25519 .GenerateKey (rand .Reader )
8999 return pub , key , err
90100 case jose .RS256 , jose .RS384 , jose .RS512 , jose .PS256 , jose .PS384 , jose .PS512 :
91101 key , err := rsa .GenerateKey (rand .Reader , bits )
102+ if err != nil {
103+ return nil , nil , err
104+ }
92105 return key .Public (), key , err
93106 default :
94107 return nil , nil , errors .New ("unknown `alg` for `use` = `sig`" )
@@ -106,6 +119,9 @@ func KeygenEnc(alg jose.KeyAlgorithm, bits int) (crypto.PublicKey, crypto.Privat
106119 return nil , nil , errors .New ("too short key for RSA `alg`, 2048+ is required" )
107120 }
108121 key , err := rsa .GenerateKey (rand .Reader , bits )
122+ if err != nil {
123+ return nil , nil , err
124+ }
109125 return key .Public (), key , err
110126 case jose .ECDH_ES , jose .ECDH_ES_A128KW , jose .ECDH_ES_A192KW , jose .ECDH_ES_A256KW :
111127 var crv elliptic.Curve
@@ -120,6 +136,9 @@ func KeygenEnc(alg jose.KeyAlgorithm, bits int) (crypto.PublicKey, crypto.Privat
120136 return nil , nil , errors .New ("unknown elliptic curve bit length, use one of 256, 384, 521" )
121137 }
122138 key , err := ecdsa .GenerateKey (crv , rand .Reader )
139+ if err != nil {
140+ return nil , nil , err
141+ }
123142 return key .Public (), key , err
124143 default :
125144 return nil , nil , errors .New ("unknown `alg` for `use` = `enc`" )
@@ -130,29 +149,39 @@ func main() {
130149 app .Version ("v2" )
131150 kingpin .MustParse (app .Parse (os .Args [1 :]))
132151
133- if * kidRand {
134- if * kid == "" {
135- b := make ([]byte , 5 )
136- _ , err := rand .Read (b )
137- app .FatalIfError (err , "can't Read() crypto/rand" )
138- * kid = base32 .StdEncoding .EncodeToString (b )
139- } else {
140- app .FatalUsage ("can't combine --kid and --kid-rand" )
141- }
142- }
143-
144- var privKey crypto.PublicKey
145- var pubKey crypto.PrivateKey
152+ var privKey crypto.PrivateKey
153+ var pubKey crypto.PublicKey
146154 var err error
147155 switch * use {
148156 case "sig" :
149157 pubKey , privKey , err = KeygenSig (jose .SignatureAlgorithm (* alg ), * bits )
150158 case "enc" :
151159 pubKey , privKey , err = KeygenEnc (jose .KeyAlgorithm (* alg ), * bits )
160+ default :
161+ // According to RFC 7517 section-8.2. This is unlikely to change in the
162+ // near future. If it were, new values could be found in the registry under
163+ // "JSON Web Key Use": https://www.iana.org/assignments/jose/jose.xhtml
164+ app .FatalIfError (errors .New ("invalid key use. Must be \" sig\" or \" enc\" " ), "unable to generate key" )
152165 }
153166 app .FatalIfError (err , "unable to generate key" )
154167
155168 priv := jose.JSONWebKey {Key : privKey , KeyID : * kid , Algorithm : * alg , Use : * use }
169+
170+ if * kidRand {
171+ // Generate a canonical kid based on RFC 7638
172+ if * kid == "" {
173+ thumb , err := priv .Thumbprint (crypto .SHA256 )
174+ app .FatalIfError (err , "unable to compute thumbprint" )
175+ * kid = base64 .URLEncoding .EncodeToString (thumb )
176+ priv .KeyID = * kid
177+ } else {
178+ app .FatalUsage ("can't combine --kid and --kid-rand" )
179+ }
180+ }
181+
182+ // I'm not sure why we couldn't use `pub := priv.Public()` here as the private
183+ // key should contain the public key. In case for some reason it doesn't,
184+ // this builds a public JWK from scratch.
156185 pub := jose.JSONWebKey {Key : pubKey , KeyID : * kid , Algorithm : * alg , Use : * use }
157186
158187 if priv .IsPublic () || ! pub .IsPublic () || ! priv .Valid () || ! pub .Valid () {
@@ -170,8 +199,6 @@ func main() {
170199 fmt .Printf ("==> jwk_%s <==\n " , * alg )
171200 fmt .Println (string (privJS ))
172201 } else {
173- // JWK Thumbprint (RFC7638) is not used for key id because of
174- // lack of canonical representation.
175202 fname := fmt .Sprintf ("jwk_%s_%s_%s" , * use , * alg , * kid )
176203 err = writeNewFile (fname + ".pub" , pubJS , 0444 )
177204 app .FatalIfError (err , "can't write public key to file %s.pub" , fname )
0 commit comments