-
Notifications
You must be signed in to change notification settings - Fork 321
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
- Loading branch information
Showing
6 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package jwt | ||
|
||
import ( | ||
"errors" | ||
|
||
"crypto/ed25519" | ||
) | ||
|
||
var ( | ||
ErrEd25519Verification = errors.New("ed25519: verification error") | ||
) | ||
|
||
// Implements the EdDSA family | ||
// Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification | ||
type SigningMethodEd25519 struct{} | ||
|
||
// Specific instance for EdDSA | ||
var ( | ||
SigningMethodEdDSA *SigningMethodEd25519 | ||
) | ||
|
||
func init() { | ||
SigningMethodEdDSA = &SigningMethodEd25519{} | ||
RegisterSigningMethod(SigningMethodEdDSA.Alg(), func() SigningMethod { | ||
return SigningMethodEdDSA | ||
}) | ||
} | ||
|
||
func (m *SigningMethodEd25519) Alg() string { | ||
return "EdDSA" | ||
} | ||
|
||
// Implements the Verify method from SigningMethod | ||
// For this verify method, key must be an ed25519.PublicKey | ||
func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error { | ||
var err error | ||
var ed25519Key ed25519.PublicKey | ||
var ok bool | ||
|
||
if ed25519Key, ok = key.(ed25519.PublicKey); !ok { | ||
return ErrInvalidKeyType | ||
} | ||
|
||
if len(ed25519Key) != ed25519.PublicKeySize { | ||
return ErrInvalidKey | ||
} | ||
|
||
// Decode the signature | ||
var sig []byte | ||
if sig, err = DecodeSegment(signature); err != nil { | ||
return err | ||
} | ||
|
||
// Verify the signature | ||
if !ed25519.Verify(ed25519Key, []byte(signingString), sig) { | ||
return ErrEd25519Verification | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Implements the Sign method from SigningMethod | ||
// For this signing method, key must be an ed25519.PrivateKey | ||
func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) { | ||
var ed25519Key ed25519.PrivateKey | ||
var ok bool | ||
|
||
if ed25519Key, ok = key.(ed25519.PrivateKey); !ok { | ||
return "", ErrInvalidKeyType | ||
} | ||
|
||
// ed25519.Sign panics if private key not equal to ed25519.PrivateKeySize | ||
// this allows to avoid recover usage | ||
if len(ed25519Key) != ed25519.PrivateKeySize { | ||
return "", ErrInvalidKey | ||
} | ||
|
||
// Sign the string and return the encoded result | ||
sig := ed25519.Sign(ed25519Key, []byte(signingString)) | ||
return EncodeSegment(sig), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package jwt_test | ||
|
||
import ( | ||
"io/ioutil" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/golang-jwt/jwt" | ||
) | ||
|
||
var ed25519TestData = []struct { | ||
name string | ||
keys map[string]string | ||
tokenString string | ||
alg string | ||
claims map[string]interface{} | ||
valid bool | ||
}{ | ||
{ | ||
"Basic Ed25519", | ||
map[string]string{"private": "test/ed25519-private.pem", "public": "test/ed25519-public.pem"}, | ||
"eyJhbGciOiJFRDI1NTE5IiwidHlwIjoiSldUIn0.eyJmb28iOiJiYXIifQ.ESuVzZq1cECrt9Od_gLPVG-_6uRP_8Nq-ajx6CtmlDqRJZqdejro2ilkqaQgSL-siE_3JMTUW7UwAorLaTyFCw", | ||
"EdDSA", | ||
map[string]interface{}{"foo": "bar"}, | ||
true, | ||
}, | ||
{ | ||
"Basic Ed25519", | ||
map[string]string{"private": "test/ed25519-private.pem", "public": "test/ed25519-public.pem"}, | ||
"eyJhbGciOiJFRDI1NTE5IiwidHlwIjoiSldUIn0.eyJmb28iOiJiYXoifQ.ESuVzZq1cECrt9Od_gLPVG-_6uRP_8Nq-ajx6CtmlDqRJZqdejro2ilkqaQgSL-siE_3JMTUW7UwAorLaTyFCw", | ||
"EdDSA", | ||
map[string]interface{}{"foo": "bar"}, | ||
false, | ||
}, | ||
} | ||
|
||
func TestEd25519Verify(t *testing.T) { | ||
for _, data := range ed25519TestData { | ||
var err error | ||
|
||
key, _ := ioutil.ReadFile(data.keys["public"]) | ||
|
||
ed25519Key, err := jwt.ParseEdPublicKeyFromPEM(key) | ||
if err != nil { | ||
t.Errorf("Unable to parse Ed25519 public key: %v", err) | ||
} | ||
|
||
parts := strings.Split(data.tokenString, ".") | ||
|
||
method := jwt.GetSigningMethod(data.alg) | ||
|
||
err = method.Verify(strings.Join(parts[0:2], "."), parts[2], ed25519Key) | ||
if data.valid && err != nil { | ||
t.Errorf("[%v] Error while verifying key: %v", data.name, err) | ||
} | ||
if !data.valid && err == nil { | ||
t.Errorf("[%v] Invalid key passed validation", data.name) | ||
} | ||
} | ||
} | ||
|
||
func TestEd25519Sign(t *testing.T) { | ||
for _, data := range ed25519TestData { | ||
var err error | ||
key, _ := ioutil.ReadFile(data.keys["private"]) | ||
|
||
ed25519Key, err := jwt.ParseEdPrivateKeyFromPEM(key) | ||
if err != nil { | ||
t.Errorf("Unable to parse Ed25519 private key: %v", err) | ||
} | ||
|
||
parts := strings.Split(data.tokenString, ".") | ||
|
||
method := jwt.GetSigningMethod(data.alg) | ||
|
||
sig, err := method.Sign(strings.Join(parts[0:2], "."), ed25519Key) | ||
if err != nil { | ||
t.Errorf("[%v] Error signing token: %v", data.name, err) | ||
} | ||
if sig == parts[2] && !data.valid { | ||
t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package jwt | ||
|
||
import ( | ||
"crypto" | ||
"crypto/ed25519" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"errors" | ||
) | ||
|
||
var ( | ||
ErrNotEdPrivateKey = errors.New("Key is not a valid Ed25519 private key") | ||
ErrNotEdPublicKey = errors.New("Key is not a valid Ed25519 public key") | ||
) | ||
|
||
// Parse PEM-encoded Edwards curve private key | ||
func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) { | ||
var err error | ||
|
||
// Parse PEM block | ||
var block *pem.Block | ||
if block, _ = pem.Decode(key); block == nil { | ||
return nil, ErrKeyMustBePEMEncoded | ||
} | ||
|
||
// Parse the key | ||
var parsedKey interface{} | ||
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { | ||
return nil, err | ||
} | ||
|
||
var pkey ed25519.PrivateKey | ||
var ok bool | ||
if pkey, ok = parsedKey.(ed25519.PrivateKey); !ok { | ||
return nil, ErrNotEdPrivateKey | ||
} | ||
|
||
return pkey, nil | ||
} | ||
|
||
// Parse PEM-encoded Edwards curve public key | ||
func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) { | ||
var err error | ||
|
||
// Parse PEM block | ||
var block *pem.Block | ||
if block, _ = pem.Decode(key); block == nil { | ||
return nil, ErrKeyMustBePEMEncoded | ||
} | ||
|
||
// Parse the key | ||
var parsedKey interface{} | ||
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { | ||
return nil, err | ||
} | ||
|
||
var pkey ed25519.PublicKey | ||
var ok bool | ||
if pkey, ok = parsedKey.(ed25519.PublicKey); !ok { | ||
return nil, ErrNotEdPublicKey | ||
} | ||
|
||
return pkey, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
-----BEGIN PRIVATE KEY----- | ||
MC4CAQAwBQYDK2VwBCIEIEFMEZrmlYxczXKFxIlNvNGR5JQvDhTkLovJYxwQd3ua | ||
-----END PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
-----BEGIN PUBLIC KEY----- | ||
MCowBQYDK2VwAyEAWH7z6hpYqvPns2i4n9yymwvB3APhi4LyQ7iHOT6crtE= | ||
-----END PUBLIC KEY----- |