@@ -21,246 +21,130 @@ import (
21
21
"io/ioutil"
22
22
"os"
23
23
24
- "github.com/codegangsta/cli "
24
+ "gopkg.in/alecthomas/kingpin.v2 "
25
25
"gopkg.in/square/go-jose.v1"
26
26
)
27
27
28
- func main () {
29
- app := cli .NewApp ()
30
- app .Name = "jose-util"
31
- app .Usage = "command-line utility to deal with JOSE objects"
32
- app .Version = "0.0.2"
33
- app .Author = ""
34
- app .Email = ""
35
-
36
- app .Commands = []cli.Command {
37
- {
38
- Name : "encrypt" ,
39
- Usage : "encrypt a plaintext" ,
40
- Flags : []cli.Flag {
41
- cli.StringFlag {
42
- Name : "key, k" ,
43
- Usage : "Path to key file (PEM/DER)" ,
44
- },
45
- cli.StringFlag {
46
- Name : "input, in" ,
47
- Usage : "Path to input file (stdin if missing)" ,
48
- },
49
- cli.StringFlag {
50
- Name : "output, out" ,
51
- Usage : "Path to output file (stdout if missing)" ,
52
- },
53
- cli.StringFlag {
54
- Name : "algorithm, alg" ,
55
- Usage : "Key management algorithm (e.g. RSA-OAEP)" ,
56
- },
57
- cli.StringFlag {
58
- Name : "encryption, enc" ,
59
- Usage : "Content encryption algorithm (e.g. A128GCM)" ,
60
- },
61
- cli.BoolFlag {
62
- Name : "full, f" ,
63
- Usage : "Use full serialization format (instead of compact)" ,
64
- },
65
- },
66
- Action : func (c * cli.Context ) {
67
- keyBytes , err := ioutil .ReadFile (requiredFlag (c , "key" ))
68
- exitOnError (err , "unable to read key file" )
69
-
70
- pub , err := jose .LoadPublicKey (keyBytes )
71
- exitOnError (err , "unable to read public key" )
72
-
73
- alg := jose .KeyAlgorithm (requiredFlag (c , "alg" ))
74
- enc := jose .ContentEncryption (requiredFlag (c , "enc" ))
75
-
76
- crypter , err := jose .NewEncrypter (alg , enc , pub )
77
- exitOnError (err , "unable to instantiate encrypter" )
78
-
79
- obj , err := crypter .Encrypt (readInput (c .String ("input" )))
80
- exitOnError (err , "unable to encrypt" )
81
-
82
- var msg string
83
- if c .Bool ("full" ) {
84
- msg = obj .FullSerialize ()
85
- } else {
86
- msg , err = obj .CompactSerialize ()
87
- exitOnError (err , "unable to serialize message" )
88
- }
89
-
90
- writeOutput (c .String ("output" ), []byte (msg ))
91
- },
92
- },
93
- {
94
- Name : "decrypt" ,
95
- Usage : "decrypt a ciphertext" ,
96
- Flags : []cli.Flag {
97
- cli.StringFlag {
98
- Name : "key, k" ,
99
- Usage : "Path to key file (PEM/DER)" ,
100
- },
101
- cli.StringFlag {
102
- Name : "input, in" ,
103
- Usage : "Path to input file (stdin if missing)" ,
104
- },
105
- cli.StringFlag {
106
- Name : "output, out" ,
107
- Usage : "Path to output file (stdout if missing)" ,
108
- },
109
- },
110
- Action : func (c * cli.Context ) {
111
- keyBytes , err := ioutil .ReadFile (requiredFlag (c , "key" ))
112
- exitOnError (err , "unable to read private key" )
113
-
114
- priv , err := jose .LoadPrivateKey (keyBytes )
115
- exitOnError (err , "unable to read private key" )
116
-
117
- obj , err := jose .ParseEncrypted (string (readInput (c .String ("input" ))))
118
- exitOnError (err , "unable to parse message" )
119
-
120
- plaintext , err := obj .Decrypt (priv )
121
- exitOnError (err , "unable to decrypt message" )
122
-
123
- writeOutput (c .String ("output" ), plaintext )
124
- },
125
- },
126
- {
127
- Name : "sign" ,
128
- Usage : "sign a plaintext" ,
129
- Flags : []cli.Flag {
130
- cli.StringFlag {
131
- Name : "algorithm, alg" ,
132
- Usage : "Signing algorithm (e.g. PS256)" ,
133
- },
134
- cli.StringFlag {
135
- Name : "key, k" ,
136
- Usage : "Path to key file (PEM/DER)" ,
137
- },
138
- cli.StringFlag {
139
- Name : "input, in" ,
140
- Usage : "Path to input file (stdin if missing)" ,
141
- },
142
- cli.StringFlag {
143
- Name : "output, out" ,
144
- Usage : "Path to output file (stdout if missing)" ,
145
- },
146
- cli.BoolFlag {
147
- Name : "full, f" ,
148
- Usage : "Use full serialization format (instead of compact)" ,
149
- },
150
- },
151
- Action : func (c * cli.Context ) {
152
- keyBytes , err := ioutil .ReadFile (requiredFlag (c , "key" ))
153
- exitOnError (err , "unable to read key file" )
154
-
155
- signingKey , err := jose .LoadPrivateKey (keyBytes )
156
- exitOnError (err , "unable to read private key" )
157
-
158
- alg := jose .SignatureAlgorithm (requiredFlag (c , "algorithm" ))
159
- signer , err := jose .NewSigner (alg , signingKey )
160
- exitOnError (err , "unable to make signer" )
161
-
162
- obj , err := signer .Sign (readInput (c .String ("input" )))
163
- exitOnError (err , "unable to sign" )
164
-
165
- var msg string
166
- if c .Bool ("full" ) {
167
- msg = obj .FullSerialize ()
168
- } else {
169
- msg , err = obj .CompactSerialize ()
170
- exitOnError (err , "unable to serialize message" )
171
- }
172
-
173
- writeOutput (c .String ("output" ), []byte (msg ))
174
- },
175
- },
176
- {
177
- Name : "verify" ,
178
- Usage : "verify a signature" ,
179
- Flags : []cli.Flag {
180
- cli.StringFlag {
181
- Name : "key, k" ,
182
- Usage : "Path to key file (PEM/DER)" ,
183
- },
184
- cli.StringFlag {
185
- Name : "input, in" ,
186
- Usage : "Path to input file (stdin if missing)" ,
187
- },
188
- cli.StringFlag {
189
- Name : "output, out" ,
190
- Usage : "Path to output file (stdout if missing)" ,
191
- },
192
- },
193
- Action : func (c * cli.Context ) {
194
- keyBytes , err := ioutil .ReadFile (requiredFlag (c , "key" ))
195
- exitOnError (err , "unable to read key file" )
196
-
197
- verificationKey , err := jose .LoadPublicKey (keyBytes )
198
- exitOnError (err , "unable to read private key" )
199
-
200
- obj , err := jose .ParseSigned (string (readInput (c .String ("input" ))))
201
- exitOnError (err , "unable to parse message" )
202
-
203
- plaintext , err := obj .Verify (verificationKey )
204
- exitOnError (err , "invalid signature" )
205
-
206
- writeOutput (c .String ("output" ), plaintext )
207
- },
208
- },
209
- {
210
- Name : "expand" ,
211
- Usage : "expand compact message to full format" ,
212
- Flags : []cli.Flag {
213
- cli.StringFlag {
214
- Name : "input, in" ,
215
- Usage : "Path to input file (stdin if missing)" ,
216
- },
217
- cli.StringFlag {
218
- Name : "output, out" ,
219
- Usage : "Path to output file (stdout if missing)" ,
220
- },
221
- cli.StringFlag {
222
- Name : "format, f" ,
223
- Usage : "Message format (JWE/JWS, defaults to JWE)" ,
224
- },
225
- },
226
- Action : func (c * cli.Context ) {
227
- input := string (readInput (c .String ("input" )))
228
-
229
- var serialized string
230
- var err error
231
- switch c .String ("format" ) {
232
- case "" , "JWE" :
233
- var jwe * jose.JsonWebEncryption
234
- jwe , err = jose .ParseEncrypted (input )
235
- if err == nil {
236
- serialized = jwe .FullSerialize ()
237
- }
238
- case "JWS" :
239
- var jws * jose.JsonWebSignature
240
- jws , err = jose .ParseSigned (input )
241
- if err == nil {
242
- serialized = jws .FullSerialize ()
243
- }
244
- }
245
-
246
- exitOnError (err , "unable to expand message" )
247
- writeOutput (c .String ("output" ), []byte (serialized ))
248
- },
249
- },
250
- }
28
+ var (
29
+ app = kingpin .New ("jose-util" , "A command-line utility for dealing with JOSE objects." )
251
30
252
- err : = app .Run ( os . Args )
253
- exitOnError ( err , "unable to run application" )
254
- }
31
+ keyFile = app .Flag ( "key" , "Path to key file (PEM or DER-encoded)" ). Required (). ExistingFile ( )
32
+ inFile = app . Flag ( "in" , "Path to input file (stdin if missing)" ). ExistingFile ( )
33
+ outFile = app . Flag ( "out" , "Path to output file (stdout if missing)" ). ExistingFile ()
255
34
256
- // Retrieve value of a required flag
257
- func requiredFlag (c * cli.Context , flag string ) string {
258
- value := c .String (flag )
259
- if value == "" {
260
- fmt .Fprintf (os .Stderr , "missing required flag --%s\n " , flag )
261
- os .Exit (1 )
35
+ encryptCommand = app .Command ("encrypt" , "Encrypt a plaintext, output ciphertext." )
36
+ algFlag = encryptCommand .Flag ("alg" , "Key management algorithm (e.g. RSA-OAEP)" ).Required ().String ()
37
+ encFlag = encryptCommand .Flag ("enc" , "Content encryption algorithm (e.g. A128GCM)" ).Required ().String ()
38
+
39
+ decryptCommand = app .Command ("decrypt" , "Decrypt a ciphertext, output plaintext." )
40
+
41
+ signCommand = app .Command ("sign" , "Sign a payload, output signed message." )
42
+ sigAlgFlag = signCommand .Flag ("alg" , "Key management algorithm (e.g. RSA-OAEP)" ).Required ().String ()
43
+
44
+ verifyCommand = app .Command ("verify" , "Verify a signed message, output payload." )
45
+
46
+ expandCommand = app .Command ("expand" , "Expand JOSE object to full serialization format." )
47
+ formatFlag = expandCommand .Flag ("format" , "Type of message to expand (JWS or JWE, defaults to JWE)" ).String ()
48
+
49
+ full = app .Flag ("full" , "Use full serialization format (instead of compact)" ).Bool ()
50
+ )
51
+
52
+ func main () {
53
+ app .Version ("v1" )
54
+
55
+ command := kingpin .MustParse (app .Parse (os .Args [1 :]))
56
+
57
+ keyBytes , err := ioutil .ReadFile (* keyFile )
58
+ exitOnError (err , "unable to read key file" )
59
+
60
+ switch command {
61
+ case "encrypt" :
62
+ pub , err := jose .LoadPublicKey (keyBytes )
63
+ exitOnError (err , "unable to read public key" )
64
+
65
+ alg := jose .KeyAlgorithm (* algFlag )
66
+ enc := jose .ContentEncryption (* encFlag )
67
+
68
+ crypter , err := jose .NewEncrypter (alg , enc , pub )
69
+ exitOnError (err , "unable to instantiate encrypter" )
70
+
71
+ obj , err := crypter .Encrypt (readInput (* inFile ))
72
+ exitOnError (err , "unable to encrypt" )
73
+
74
+ var msg string
75
+ if * full {
76
+ msg = obj .FullSerialize ()
77
+ } else {
78
+ msg , err = obj .CompactSerialize ()
79
+ exitOnError (err , "unable to serialize message" )
80
+ }
81
+
82
+ writeOutput (* outFile , []byte (msg ))
83
+ case "decrypt" :
84
+ priv , err := jose .LoadPrivateKey (keyBytes )
85
+ exitOnError (err , "unable to read private key" )
86
+
87
+ obj , err := jose .ParseEncrypted (string (readInput (* inFile )))
88
+ exitOnError (err , "unable to parse message" )
89
+
90
+ plaintext , err := obj .Decrypt (priv )
91
+ exitOnError (err , "unable to decrypt message" )
92
+
93
+ writeOutput (* outFile , plaintext )
94
+ case "sign" :
95
+ signingKey , err := jose .LoadPrivateKey (keyBytes )
96
+ exitOnError (err , "unable to read private key" )
97
+
98
+ alg := jose .SignatureAlgorithm (* sigAlgFlag )
99
+ signer , err := jose .NewSigner (alg , signingKey )
100
+ exitOnError (err , "unable to make signer" )
101
+
102
+ obj , err := signer .Sign (readInput (* inFile ))
103
+ exitOnError (err , "unable to sign" )
104
+
105
+ var msg string
106
+ if * full {
107
+ msg = obj .FullSerialize ()
108
+ } else {
109
+ msg , err = obj .CompactSerialize ()
110
+ exitOnError (err , "unable to serialize message" )
111
+ }
112
+
113
+ writeOutput (* outFile , []byte (msg ))
114
+ case "verify" :
115
+ verificationKey , err := jose .LoadPublicKey (keyBytes )
116
+ exitOnError (err , "unable to read private key" )
117
+
118
+ obj , err := jose .ParseSigned (string (readInput (* inFile )))
119
+ exitOnError (err , "unable to parse message" )
120
+
121
+ plaintext , err := obj .Verify (verificationKey )
122
+ exitOnError (err , "invalid signature" )
123
+
124
+ writeOutput (* outFile , plaintext )
125
+ case "expand" :
126
+ input := string (readInput (* inFile ))
127
+
128
+ var serialized string
129
+ var err error
130
+ switch * formatFlag {
131
+ case "" , "JWE" :
132
+ var jwe * jose.JsonWebEncryption
133
+ jwe , err = jose .ParseEncrypted (input )
134
+ if err == nil {
135
+ serialized = jwe .FullSerialize ()
136
+ }
137
+ case "JWS" :
138
+ var jws * jose.JsonWebSignature
139
+ jws , err = jose .ParseSigned (input )
140
+ if err == nil {
141
+ serialized = jws .FullSerialize ()
142
+ }
143
+ }
144
+
145
+ exitOnError (err , "unable to expand message" )
146
+ writeOutput (* outFile , []byte (serialized ))
262
147
}
263
- return value
264
148
}
265
149
266
150
// Exit and print error message if we encountered a problem
0 commit comments