cmd: add handling of HS keys

Signed-off-by: Paul Greenberg <greenpau@outlook.com>
This commit is contained in:
Paul Greenberg 2022-02-08 14:17:53 -05:00
parent d0c0939ff8
commit c6a6a5f45b
2 changed files with 117 additions and 7 deletions

View File

@ -1,19 +1,97 @@
`jwt` command-line tool
=======================
# `jwt` command-line tool
This is a simple tool to sign, verify and show JSON Web Tokens from
the command line.
## Getting Started
The following will create and sign a token, then verify it and output the original claims:
echo {\"foo\":\"bar\"} | ./jwt -key ../../test/sample_key -alg RS256 -sign - | ./jwt -key ../../test/sample_key.pub -alg RS256 -verify -
```bash
echo {\"foo\":\"bar\"} | ./jwt -key ../../test/sample_key -alg RS256 -sign - | ./jwt -key ../../test/sample_key.pub -alg RS256 -verify -
```
Key files should be in PEM format. Other formats are not supported by this tool.
To simply display a token, use:
echo $JWT | ./jwt -show -
```bash
echo $JWT | ./jwt -show -
```
You can install this tool with the following command:
go install github.com/golang-jwt/jwt/v4/cmd/jwt
```bash
go install github.com/golang-jwt/jwt/v4/cmd/jwt
```
## Sign/Verify with Shared Secret
First, create a JSON document with token payload, e.g. `~/experimental/jwt/data`.
```json
{
"email": "jsmith@foo.bar",
"aud": "foo.bar",
"exp": 2559489932,
"iat": 1612805132,
"iss": "foo.bar",
"sub": "jsmith"
}
```
Then, create a file with shared secret key, e.g. `~/experimental/jwt/token.key`.
```
foobarbaz
```
Next, sign the token:
```bash
./jwt -key ~/experimental/jwt/token.key -alg HS512 -sign ~/experimental/jwt/data > ~/experimental/jwt/token.jwt
```
After that, review the token:
```bash
./jwt -show ~/experimental/jwt/token.jwt
```
The expected output follows:
```
Header:
{
"alg": "HS512",
"typ": "JWT"
}
Claims:
{
"aud": "foo.bar",
"email": "jsmith@foo.bar",
"exp": 2559489932,
"iat": 1612805132,
"iss": "foo.bar",
"sub": "jsmith"
}
```
Subsequently, validate the token:
```bash
./jwt -key ~/experimental/jwt/token.key -alg HS512 -verify ~/experimental/jwt/token.jwt
```
The expected output follows:
```
{
"aud": "foo.bar",
"email": "jsmith@foo.bar",
"exp": 2559489932,
"iat": 1612805132,
"iss": "foo.bar",
"sub": "jsmith"
}
```

View File

@ -7,6 +7,7 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
@ -16,6 +17,7 @@ import (
"regexp"
"sort"
"strings"
"unicode"
"github.com/golang-jwt/jwt/v4"
)
@ -142,6 +144,8 @@ func verifyToken() error {
return jwt.ParseRSAPublicKeyFromPEM(data)
} else if isEd() {
return jwt.ParseEdPublicKeyFromPEM(data)
} else if isHs() {
return parseHSKey(data)
}
return data, nil
})
@ -196,9 +200,19 @@ func signToken() error {
// get the key
var key interface{}
if isNone() {
switch {
case isNone():
key = jwt.UnsafeAllowNoneSignatureType
} else {
case isHs():
kb, err := loadData(*flagKey)
if err != nil {
return fmt.Errorf("couldn't read key: %w", err)
}
key, err = parseHSKey(kb)
if err != nil {
return err
}
default:
key, err = loadData(*flagKey)
if err != nil {
return fmt.Errorf("couldn't read key: %w", err)
@ -292,6 +306,10 @@ func showToken() error {
return nil
}
func isHs() bool {
return strings.HasPrefix(*flagAlg, "HS")
}
func isEs() bool {
return strings.HasPrefix(*flagAlg, "ES")
}
@ -342,3 +360,17 @@ func (l ArgList) Set(arg string) error {
l[parts[0]] = parts[1]
return nil
}
func parseHSKey(b []byte) ([]byte, error) {
if len(b) == 0 {
return nil, fmt.Errorf("shared key is empty")
}
f := func(c rune) bool {
return unicode.IsSpace(c)
}
i := bytes.IndexFunc(b, f)
if i < 0 {
return b, nil
}
return b[:i], nil
}