-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor public key, remove it and use generated version. Switch priv…
…ate key format ot pkcs7 PEM files
- Loading branch information
Showing
17 changed files
with
315 additions
and
372 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,105 @@ | ||
package jwt_test | ||
|
||
import ( | ||
"crypto/x509" | ||
"encoding/base64" | ||
"fmt" | ||
"testing" | ||
|
||
jwt "github.com/golang-jwt/jwt/v4" | ||
jwti "github.com/madappgang/identifo/jwt" | ||
) | ||
|
||
// SEC 1, ASN.1, DER format | ||
// privateKeyPEM := []byte(`-----BEGIN EC PRIVATE KEY----- | ||
// MHcCAQEEIKcw4Osfw4a5G11fWprAjxrPLSAhKv5H5Gj27NBXsGDKoAoGCCqGSM49 | ||
// AwEHoUQDQgAED3DoOWZMbqYc0OO1Ih628hB2Odhv4mjl1vt0iBu3gTKz1XAk+YHG | ||
// 8aoI+42TJle6hawmTzrSD6khaNRaDQAKbg== | ||
// -----END EC PRIVATE KEY----- | ||
// `) | ||
|
||
var privateKeyPEM = []byte(`-----BEGIN PRIVATE KEY----- | ||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgpzDg6x/DhrkbXV9a | ||
msCPGs8tICEq/kfkaPbs0FewYMqhRANCAAQPcOg5ZkxuphzQ47UiHrbyEHY52G/i | ||
aOXW+3SIG7eBMrPVcCT5gcbxqgj7jZMmV7qFrCZPOtIPqSFo1FoNAApu | ||
-----END PRIVATE KEY----- | ||
`) | ||
|
||
var publicKeyPEM = []byte(`-----BEGIN PUBLIC KEY----- | ||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAED3DoOWZMbqYc0OO1Ih628hB2Odhv | ||
4mjl1vt0iBu3gTKz1XAk+YHG8aoI+42TJle6hawmTzrSD6khaNRaDQAKbg== | ||
-----END PUBLIC KEY----- | ||
`) | ||
|
||
func TestKeysManualSerializationService(t *testing.T) { | ||
private, err := jwt.ParseECPrivateKeyFromPEM(privateKeyPEM) | ||
if err != nil { | ||
fmt.Println(string(privateKeyPEM)) | ||
t.Fatalf("Error parsing key from PEM: %v", err) | ||
} | ||
|
||
public, err := jwt.ParseECPublicKeyFromPEM(publicKeyPEM) | ||
if err != nil { | ||
t.Fatalf("Error parsing key from PEM: %v", err) | ||
} | ||
|
||
generatedPublic := private.Public() | ||
|
||
if !public.Equal(generatedPublic) { | ||
t.Fatalf("Generated public key and reference keys are not equal") | ||
} | ||
|
||
genPEM, err := x509.MarshalPKIXPublicKey(generatedPublic) | ||
if err != nil { | ||
t.Fatalf("Error creating PEM: %v", err) | ||
} | ||
// creating the same certificate as ssl tool is doing with the following command: | ||
// openssl ec -in private.pem -pubout -out public.pem | ||
pemString := fmt.Sprintf("-----BEGIN PUBLIC KEY-----\n%s\n%s\n-----END PUBLIC KEY-----\n", | ||
base64.StdEncoding.EncodeToString(genPEM)[0:64], | ||
base64.StdEncoding.EncodeToString(genPEM)[64:], | ||
) | ||
if pemString != string(publicKeyPEM) { | ||
fmt.Printf("%s\n", pemString) | ||
t.Fatalf("generated public key PEM and referenced are not equal.") | ||
} | ||
|
||
genPEMPrivate, err := x509.MarshalPKCS8PrivateKey(private) | ||
// genPEMPrivate, err := x509.MarshalECPrivateKey(private) | ||
if err != nil { | ||
t.Fatalf("Error creating private PEM: %v", err) | ||
} | ||
pemStringPrivate := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n%s\n%s\n-----END PRIVATE KEY-----\n", | ||
base64.StdEncoding.EncodeToString(genPEMPrivate)[0:64], | ||
base64.StdEncoding.EncodeToString(genPEMPrivate)[64:128], | ||
base64.StdEncoding.EncodeToString(genPEMPrivate)[128:], | ||
) | ||
|
||
if pemStringPrivate != string(privateKeyPEM) { | ||
fmt.Printf("%s\n", pemStringPrivate) | ||
t.Fatalf("generated private key PEM and referenced are not equal.") | ||
} | ||
} | ||
|
||
func TestPemMarshalling(t *testing.T) { | ||
private, err := jwt.ParseECPrivateKeyFromPEM(privateKeyPEM) | ||
// private, alg, err := jwti.LoadPrivateKeyFromString(string(privateKeyPEM)) | ||
if err != nil { | ||
fmt.Println(string(privateKeyPEM)) | ||
t.Fatalf("Error parsing key from PEM: %v", err) | ||
} | ||
|
||
// if alg != model.TokenSignatureAlgorithmES256 { | ||
// t.Fatalf("wrong algorithm in PEM: %v", alg) | ||
// } | ||
|
||
result, err := jwti.MarshalPrivateKeyToPEM(private) | ||
if err != nil { | ||
t.Fatalf("Error marshaling key to PEM: %v", err) | ||
} | ||
|
||
if result != string(privateKeyPEM) { | ||
fmt.Printf("%s\n", result) | ||
t.Fatalf("generated private key PEM and referenced are not equal.") | ||
} | ||
} |
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 |
---|---|---|
@@ -1,114 +1,108 @@ | ||
package jwt | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/base64" | ||
"fmt" | ||
"io/ioutil" | ||
|
||
jwt "github.com/golang-jwt/jwt/v4" | ||
"github.com/madappgang/identifo/model" | ||
) | ||
|
||
var supportedSignatureAlgorithms = []model.TokenSignatureAlgorithm{model.TokenSignatureAlgorithmES256, model.TokenSignatureAlgorithmRS256} | ||
|
||
// LoadPrivateKeyFromPEM loads private key from PEM file. | ||
func LoadPrivateKeyFromPEM(file string, alg model.TokenSignatureAlgorithm) (interface{}, error) { | ||
prkb, err := ioutil.ReadFile(file) | ||
func LoadPrivateKeyFromString(s string) (interface{}, model.TokenSignatureAlgorithm, error) { | ||
pp, err := x509.ParsePKCS8PrivateKey([]byte(s)) | ||
if err != nil { | ||
return nil, err | ||
return nil, model.TokenSignatureAlgorithmInvalid, err | ||
} | ||
|
||
var privateKey interface{} | ||
switch alg { | ||
case model.TokenSignatureAlgorithmES256: | ||
privateKey, err = jwt.ParseECPrivateKeyFromPEM(prkb) | ||
case model.TokenSignatureAlgorithmRS256: | ||
privateKey, err = jwt.ParseRSAPrivateKeyFromPEM(prkb) | ||
switch private := pp.(type) { | ||
case *rsa.PrivateKey: | ||
return private, model.TokenSignatureAlgorithmRS256, nil | ||
case *ecdsa.PrivateKey: | ||
return private, model.TokenSignatureAlgorithmES256, nil | ||
default: | ||
return nil, model.ErrWrongSignatureAlgorithm | ||
return nil, model.TokenSignatureAlgorithmInvalid, fmt.Errorf("could not load unsupported key type: %T\n", private) | ||
} | ||
} | ||
|
||
// LoadPrivateKeyFromPEM loads private key from PEM file. | ||
func LoadPrivateKeyFromPEM(file string) (interface{}, model.TokenSignatureAlgorithm, error) { | ||
prkb, err := ioutil.ReadFile(file) | ||
if err != nil { | ||
return nil, err | ||
return nil, model.TokenSignatureAlgorithmInvalid, err | ||
} | ||
return privateKey, nil | ||
return LoadPrivateKeyFromString(string(prkb)) | ||
} | ||
|
||
// LoadPublicKeyFromPEM loads public key from PEM file. | ||
func LoadPublicKeyFromPEM(file string, alg model.TokenSignatureAlgorithm) (interface{}, error) { | ||
if alg == model.TokenSignatureAlgorithmAuto { | ||
k, _, e := LoadPublicKeyFromPEMAuto(file) | ||
return k, e | ||
} | ||
|
||
pkb, err := ioutil.ReadFile(file) | ||
// LoadPublicKeyFromString loads public key from string. | ||
func LoadPublicKeyFromString(s string) (interface{}, model.TokenSignatureAlgorithm, error) { | ||
pub, err := x509.ParsePKIXPublicKey([]byte(s)) | ||
if err != nil { | ||
return nil, err | ||
return nil, model.TokenSignatureAlgorithmInvalid, err | ||
} | ||
|
||
var publicKey interface{} | ||
switch alg { | ||
case model.TokenSignatureAlgorithmES256: | ||
publicKey, err = jwt.ParseECPublicKeyFromPEM(pkb) | ||
case model.TokenSignatureAlgorithmRS256: | ||
publicKey, err = jwt.ParseRSAPublicKeyFromPEM(pkb) | ||
switch pub := pub.(type) { | ||
case *rsa.PublicKey: | ||
return pub, model.TokenSignatureAlgorithmRS256, nil | ||
case *ecdsa.PublicKey: | ||
return pub, model.TokenSignatureAlgorithmES256, nil | ||
default: | ||
return nil, model.ErrWrongSignatureAlgorithm | ||
return nil, model.TokenSignatureAlgorithmInvalid, fmt.Errorf("could not load unsupported key type: %T\n", pub) | ||
} | ||
} | ||
|
||
// LoadPublicKeyFromPEM loads public key from file | ||
func LoadPublicKeyFromPEM(file string) (interface{}, model.TokenSignatureAlgorithm, error) { | ||
prkb, err := ioutil.ReadFile(file) | ||
if err != nil { | ||
return nil, err | ||
return nil, model.TokenSignatureAlgorithmInvalid, err | ||
} | ||
return publicKey, nil | ||
|
||
return LoadPublicKeyFromString(string(prkb)) | ||
} | ||
|
||
// LoadPublicKeyFromPEMAuto loads keys from pem file with key algorithm auto detection | ||
func LoadPublicKeyFromPEMAuto(file string) (interface{}, model.TokenSignatureAlgorithm, error) { | ||
var err error | ||
var key interface{} | ||
alg := model.TokenSignatureAlgorithmAuto | ||
for _, a := range supportedSignatureAlgorithms { | ||
if key, err = LoadPublicKeyFromPEM(file, a); err == nil { | ||
alg = a | ||
break | ||
} | ||
func MarshalPrivateKeyToPEM(key interface{}) (string, error) { | ||
pk, err := x509.MarshalPKCS8PrivateKey(key) | ||
if err != nil { | ||
return "", fmt.Errorf("error creating PEM: %v", err) | ||
} | ||
return key, alg, err | ||
b64 := []byte(base64.RawStdEncoding.EncodeToString(pk)) | ||
return fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s-----END PRIVATE KEY-----\n", make64ColsString(b64)), nil | ||
} | ||
|
||
// LoadPublicKeyFromString loads public key from string. | ||
func LoadPublicKeyFromString(s string, alg model.TokenSignatureAlgorithm) (interface{}, error) { | ||
if alg == model.TokenSignatureAlgorithmAuto { | ||
k, _, e := LoadPublicKeyFromStringAuto(s) | ||
return k, e | ||
func MarshalPublicKeyToPEM(key interface{}) (string, error) { | ||
pk, err := x509.MarshalPKIXPublicKey(key) | ||
if err != nil { | ||
return "", fmt.Errorf("error creating PEM: %v", err) | ||
} | ||
b64 := []byte(base64.RawStdEncoding.EncodeToString(pk)) | ||
return fmt.Sprintf("-----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n", make64ColsString(b64)), nil | ||
} | ||
|
||
var publicKey interface{} | ||
var err error | ||
|
||
switch alg { | ||
case model.TokenSignatureAlgorithmES256: | ||
publicKey, err = jwt.ParseECPublicKeyFromPEM([]byte(s)) | ||
case model.TokenSignatureAlgorithmRS256: | ||
publicKey, err = jwt.ParseRSAPublicKeyFromPEM([]byte(s)) | ||
default: | ||
return nil, model.ErrWrongSignatureAlgorithm | ||
} | ||
func make64ColsString(slice []byte) string { | ||
chunks := chunkSlice(slice, 64) | ||
|
||
if err != nil { | ||
return nil, err | ||
result := "" | ||
for _, line := range chunks { | ||
result = result + string(line) + "\n" | ||
} | ||
return publicKey, nil | ||
return result | ||
} | ||
|
||
// LoadPublicKeyFromStringAuto loads keys from string with key algorithm auto detection | ||
func LoadPublicKeyFromStringAuto(s string) (interface{}, model.TokenSignatureAlgorithm, error) { | ||
var err error | ||
var key interface{} | ||
alg := model.TokenSignatureAlgorithmAuto | ||
for _, a := range supportedSignatureAlgorithms { | ||
if key, err = LoadPublicKeyFromString(s, a); err == nil { | ||
alg = a | ||
break | ||
// chunkSlice split slices | ||
func chunkSlice(slice []byte, chunkSize int) [][]byte { | ||
var chunks [][]byte | ||
for i := 0; i < len(slice); i += chunkSize { | ||
end := i + chunkSize | ||
|
||
// necessary check to avoid slicing beyond | ||
// slice capacity | ||
if end > len(slice) { | ||
end = len(slice) | ||
} | ||
chunks = append(chunks, slice[i:end]) | ||
} | ||
return key, alg, err | ||
|
||
return chunks | ||
} |
Oops, something went wrong.