Skip to content
Snippets Groups Projects
Commit d35a530f authored by Gabriel Zachmann's avatar Gabriel Zachmann
Browse files

support RSA or EC based token signatures

parent e2ccdfed
No related branches found
No related tags found
No related merge requests found
......@@ -17,7 +17,7 @@ func main() {
if err != nil {
panic(err)
}
jws.Init()
jws.LoadKey()
server.Start()
......
package main
import (
"fmt"
"io/ioutil"
"log"
"github.com/zachmann/mytoken/internal/config"
"github.com/zachmann/mytoken/internal/jws"
)
func main() {
sk, _ := jws.GenerateRSAKeyPair()
str := jws.ExportRSAPrivateKeyAsPemStr(sk)
filepath := "/tmp/mytoken.key"
config.LoadForSetup()
sk, _, err := jws.GenerateKeyPair()
if err != nil {
log.Fatal(err)
}
str := jws.ExportPrivateKeyAsPemStr(sk)
filepath := config.Get().Signing.KeyFile
ioutil.WriteFile(filepath, []byte(str), 0600)
fmt.Printf("Wrote key to '%s'. Copy the keyfile to a secure location.\n", filepath)
log.Printf("Wrote key to '%s'.\n", filepath)
}
......@@ -24,6 +24,7 @@ enabled_super_token_endpoint_grant_types:
- "private_key_jwt"
polling_code_expires_after: 300
signing:
alg: "RS512"
alg: "ES512"
key_file: "/mytoken.key"
# rsa_key_len: 2048
service_documentation: "https://github.com/zachmann/mytoken"
......@@ -8,12 +8,13 @@ import (
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
"github.com/zachmann/mytoken/internal/utils/issuerUtils"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/zachmann/mytoken/internal/model"
"github.com/zachmann/mytoken/internal/utils/fileutil"
"gopkg.in/yaml.v3"
)
// Config holds the server configuration
......@@ -42,8 +43,9 @@ type serverConf struct {
}
type signingConf struct {
Alg string `yaml:"alg"`
KeyFile string `yaml:"key_file"`
Alg string `yaml:"alg"`
KeyFile string `yaml:"key_file"`
RSAKeyLen int `yaml:"rsa_key_len"`
}
// ProviderConf holds information about a provider
......@@ -136,6 +138,13 @@ func readConfigFile(filename string) []byte {
// Load reads the config file and populates the config struct; then validates the config
func Load() {
load()
if err := validate(); err != nil {
log.Fatal(err)
}
}
func load() {
data := readConfigFile("config.yaml")
conf = newConfig()
err := yaml.Unmarshal(data, conf)
......@@ -143,9 +152,11 @@ func Load() {
log.Fatal(err)
return
}
if err := validate(); err != nil {
log.Fatal(err)
}
}
// LoadForSetup reads the config file and populates the config struct; it does not validate the config, since this is not required for setup
func LoadForSetup() {
load()
}
func newConfig() *Config {
......
package jws
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"github.com/dgrijalva/jwt-go"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/zachmann/mytoken/internal/config"
)
// GenerateRSAKeyPair generates an RSA key pair
func GenerateRSAKeyPair() (*rsa.PrivateKey, *rsa.PublicKey) {
sk, _ := rsa.GenerateKey(rand.Reader, 1024)
return sk, &sk.PublicKey
func GenerateKeyPair() (sk interface{}, pk interface{}, err error) {
alg := config.Get().Signing.Alg
switch alg {
case oidc.RS256, oidc.RS384, oidc.RS512, oidc.PS256, oidc.PS384, oidc.PS512:
keyLen := config.Get().Signing.RSAKeyLen
if keyLen <= 0 {
return nil, nil, fmt.Errorf("%s specified, but no valid RSA key len", alg)
}
sk, err = rsa.GenerateKey(rand.Reader, keyLen)
case oidc.ES256:
sk, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
case oidc.ES384:
sk, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
case oidc.ES512:
sk, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
default:
return nil, nil, fmt.Errorf("unknown signing algorithm '%s'", alg)
}
if err != nil {
switch sk.(type) {
case *rsa.PrivateKey:
pk = &sk.(*rsa.PrivateKey).PublicKey
case *ecdsa.PrivateKey:
pk = &sk.(*ecdsa.PrivateKey).PublicKey
default:
err = fmt.Errorf("Something went wrong. We just created an unknown key type.")
}
}
return
}
// ExportPrivateKeyAsPemStr exports the private key
func ExportPrivateKeyAsPemStr(sk interface{}) string {
switch sk.(type) {
case *rsa.PrivateKey:
return exportRSAPrivateKeyAsPemStr(sk.(*rsa.PrivateKey))
case *ecdsa.PrivateKey:
return exportECPrivateKeyAsPemStr(sk.(*ecdsa.PrivateKey))
default:
return ""
}
}
func exportECPrivateKeyAsPemStr(privkey *ecdsa.PrivateKey) string {
privkeyBytes, _ := x509.MarshalECPrivateKey(privkey)
privkeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "EC PRIVATE KEY",
Bytes: privkeyBytes,
},
)
return string(privkeyPem)
}
// ExportRSAPrivateKeyAsPemStr exports the private key
func ExportRSAPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {
func exportRSAPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {
privkeyBytes := x509.MarshalPKCS1PrivateKey(privkey)
privkeyPem := pem.EncodeToMemory(
&pem.Block{
......@@ -30,43 +83,55 @@ func ExportRSAPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {
}
// ParseRSAPrivateKeyFromPemStr imports an private key
func ParseRSAPrivateKeyFromPemStr(privPEM string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(privPEM))
if block == nil {
return nil, errors.New("failed to parse PEM block containing the key")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return priv, nil
}
//func ParseRSAPrivateKeyFromPemStr(privPEM string) (*rsa.PrivateKey, error) {
// block, _ := pem.Decode([]byte(privPEM))
// if block == nil {
// return nil, errors.New("failed to parse PEM block containing the key")
// }
//
// priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
// if err != nil {
// return nil, err
// }
//
// return priv, nil
//}
var privateKey *rsa.PrivateKey
var publicKey *rsa.PublicKey
var privateKey interface{}
var publicKey interface{}
// GetPrivateKey returns the private key
func GetPrivateKey() *rsa.PrivateKey {
func GetPrivateKey() interface{} {
return privateKey
}
// GetPublicKey returns the public key
func GetPublicKey() *rsa.PublicKey {
func GetPublicKey() interface{} {
return publicKey
}
// Init does init
func Init() {
// LoadKey loads the private and public key
func LoadKey() {
keyFileContent, err := ioutil.ReadFile(config.Get().Signing.KeyFile)
if err != nil {
panic(err)
}
sk, err := ParseRSAPrivateKeyFromPemStr(string(keyFileContent))
if err != nil {
panic(err)
switch config.Get().Signing.Alg {
case oidc.RS256, oidc.RS384, oidc.RS512, oidc.PS256, oidc.PS384, oidc.PS512:
sk, err := jwt.ParseRSAPrivateKeyFromPEM(keyFileContent)
if err != nil {
panic(err)
}
privateKey = sk
publicKey = &sk.PublicKey
case oidc.ES256, oidc.ES384, oidc.ES512:
sk, err := jwt.ParseECPrivateKeyFromPEM(keyFileContent)
if err != nil {
panic(err)
}
privateKey = sk
publicKey = &sk.PublicKey
default:
panic(fmt.Errorf("unknown signing alg"))
}
privateKey = sk
publicKey = &sk.PublicKey
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment