Skip to content
This repository was archived by the owner on Feb 27, 2023. It is now read-only.

Commit e3f973b

Browse files
committed
Merge branch 'master' into v1
* master: Migrate jose-util to kingpin package Add JsonWebKey.Valid method Add unit tests for unicode handling Fix spelling error
2 parents 40d457b + d2a8471 commit e3f973b

File tree

5 files changed

+222
-236
lines changed

5 files changed

+222
-236
lines changed

jose-util/main.go

Lines changed: 118 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -21,246 +21,130 @@ import (
2121
"io/ioutil"
2222
"os"
2323

24-
"github.com/codegangsta/cli"
24+
"gopkg.in/alecthomas/kingpin.v2"
2525
"gopkg.in/square/go-jose.v1"
2626
)
2727

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.")
25130

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()
25534

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))
262147
}
263-
return value
264148
}
265149

266150
// Exit and print error message if we encountered a problem

0 commit comments

Comments
 (0)