Commit cf78cdef authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Improve private and public key configuration

parent ae84e177
......@@ -138,22 +138,40 @@ func CopyDirectory(src, dest string) error {
)
}
func ReadKey(key string) ([]byte, error) {
// ReadKey returns either the content of the file specified at path, if it exists,
// or []byte(key) otherwise. It is an error to specify both or none arguments, or
// specify an empty or unreadable file. If there is no error then the return []byte is non-empty.
func ReadKey(key, path string) ([]byte, error) {
if (key != "" && path != "") || (key == "" && path == "") {
return nil, errors.New("provide either key or path to key")
}
var bts []byte
if stat, err := os.Stat(key); err == nil {
if path == "" {
bts = []byte(key)
} else {
stat, err := os.Stat(path)
if err != nil {
return nil, errors.New("no key found at specified path")
}
if stat.IsDir() {
return nil, errors.New("cannot read key from a directory")
}
bts, err = ioutil.ReadFile(key)
bts, err = ioutil.ReadFile(path)
if err != nil {
return nil, err
}
} else {
bts = []byte(key)
}
if len(bts) == 0 {
return nil, errors.New("empty key provided")
}
return bts, nil
}
// Base64Decode decodes the specified bytes as any of the Base64 dialects:
// standard encoding (+, /) and URL encoding (-, _), with or without padding.
func Base64Decode(b []byte) ([]byte, error) {
var (
err error
......
......@@ -162,8 +162,9 @@ func postRequest(serverurl string, request irma.RequestorRequest, name, authmeth
jwtstr string
bts []byte
)
if bts, err = fs.ReadKey(key); err != nil {
return nil, nil, err
// If the key refers to an existing file, use contents of the file as key
if bts, err = fs.ReadKey("", key); err != nil {
bts = []byte(key)
}
if authmethod == "hmac" {
jwtalg = jwt.SigningMethodHS256
......
......@@ -77,14 +77,9 @@ func (hauth *HmacAuthenticator) Authenticate(
}
func (hauth *HmacAuthenticator) Initialize(name string, requestor Requestor) error {
if requestor.AuthenticationKey == "" {
return errors.Errorf("Requestor %s has no authentication key", name)
}
// Read file contents or string contents
bts, err := fs.ReadKey(requestor.AuthenticationKey)
bts, err := fs.ReadKey(requestor.AuthenticationKey, requestor.AuthenticationKeyFile)
if err != nil {
return err
return errors.WrapPrefix(err, "Failed to read key of requestor "+name, 0)
}
// We accept any of the base64 encodings
......@@ -105,13 +100,11 @@ func (pkauth *PublicKeyAuthenticator) Authenticate(
}
func (pkauth *PublicKeyAuthenticator) Initialize(name string, requestor Requestor) error {
bts, err := fs.ReadKey(requestor.AuthenticationKey)
bts, err := fs.ReadKey(requestor.AuthenticationKey, requestor.AuthenticationKeyFile)
if err != nil {
return err
}
if len(bts) == 0 {
return errors.Errorf("Requestor %s has invalid public key", name)
return errors.WrapPrefix(err, "Failed to read key of requestor "+name, 0)
}
pk, err := jwt.ParseRSAPublicKeyFromPEM(bts)
if err != nil {
return err
......@@ -140,12 +133,9 @@ func (pskauth *PresharedKeyAuthenticator) Authenticate(
}
func (pskauth *PresharedKeyAuthenticator) Initialize(name string, requestor Requestor) error {
if requestor.AuthenticationKey == "" {
return errors.Errorf("Requestor %s has no authentication key", name)
}
bts, err := fs.ReadKey(requestor.AuthenticationKey)
bts, err := fs.ReadKey(requestor.AuthenticationKey, requestor.AuthenticationKeyFile)
if err != nil {
return err
return errors.WrapPrefix(err, "Failed to read key of requestor "+name, 0)
}
pskauth.presharedkeys[string(bts)] = name
return nil
......
......@@ -3,7 +3,6 @@ package irmaserver
import (
"crypto/rsa"
"fmt"
"io/ioutil"
"regexp"
"strconv"
"strings"
......@@ -45,7 +44,8 @@ type Configuration struct {
JwtIssuer string `json:"jwtissuer" mapstructure:"jwtissuer"`
// Private key to sign result JWTs with. If absent, /result-jwt and /getproof are disabled.
JwtPrivateKey string `json:"jwtprivatekey" mapstructure:"jwtprivatekey"`
JwtPrivateKey string `json:"jwtprivatekey" mapstructure:"jwtprivatekey"`
JwtPrivateKeyFile string `json:"jwtprivatekeyfile" mapstructure:"jwtprivatekeyfile"`
// Max age in seconds of a session request JWT (using iat field)
MaxRequestAge int `json:"maxrequestage" mapstructure:"maxrequestage"`
......@@ -68,8 +68,9 @@ type Permissions struct {
type Requestor struct {
Permissions `mapstructure:",squash"`
AuthenticationMethod AuthenticationMethod `json:"authmethod" mapstructure:"authmethod"`
AuthenticationKey string `json:"key" mapstructure:"key"`
AuthenticationMethod AuthenticationMethod `json:"authmethod" mapstructure:"authmethod"`
AuthenticationKey string `json:"key" mapstructure:"key"`
AuthenticationKeyFile string `json:"keyfile" mapstructure:"keyfile"`
}
// CanIssue returns whether or not the specified requestor may issue the specified credentials.
......@@ -262,21 +263,13 @@ func (conf *Configuration) validatePermissionSet(requestor string, requestorperm
}
func (conf *Configuration) readPrivateKey() error {
if conf.JwtPrivateKey == "" {
if conf.JwtPrivateKey == "" && conf.JwtPrivateKeyFile == "" {
return nil
}
var keybytes []byte
var err error
if strings.HasPrefix(conf.JwtPrivateKey, "-----BEGIN") {
keybytes = []byte(conf.JwtPrivateKey)
} else {
if err = fs.AssertPathExists(conf.JwtPrivateKey); err != nil {
return err
}
if keybytes, err = ioutil.ReadFile(conf.JwtPrivateKey); err != nil {
return err
}
keybytes, err := fs.ReadKey(conf.JwtPrivateKey, conf.JwtPrivateKeyFile)
if err != nil {
return errors.WrapPrefix(err, "failed to read private key", 0)
}
conf.jwtPrivateKey, err = jwt.ParseRSAPrivateKeyFromPEM(keybytes)
......
......@@ -75,7 +75,8 @@ func setFlags(cmd *cobra.Command) error {
flags.String("cachepath", cachepath, "Directory for writing cache files to")
flags.Uint("schemeupdate", 60, "Update IRMA schemes every x minutes (0 to disable)")
flags.StringP("jwtissuer", "j", "irmaserver", "JWT issuer")
flags.StringP("jwtprivatekey", "w", "", "JWT private key or path to it")
flags.String("jwtprivatekey", "", "JWT private key")
flags.String("jwtprivatekeyfile", "", "Path to JWT private key")
flags.Int("maxrequestage", 300, "Max age in seconds of a session request JWT")
flags.StringP("url", "u", defaulturl, "External URL to server to which the IRMA client connects")
flags.StringP("listenaddr", "l", "0.0.0.0", "Address at which to listen")
......@@ -151,6 +152,7 @@ func configure() error {
GlobalPermissions: irmaserver.Permissions{},
JwtIssuer: viper.GetString("jwtissuer"),
JwtPrivateKey: viper.GetString("jwtprivatekey"),
JwtPrivateKeyFile: viper.GetString("jwtprivatekeyfile"),
MaxRequestAge: viper.GetInt("maxrequestage"),
Verbose: viper.GetInt("verbose"),
Quiet: viper.GetBool("quiet"),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment