Commit 61b8a2aa authored by Sietse Ringers's avatar Sietse Ringers
Browse files

feat: make keyshare JWT issuer and pin JWT expiry configurable

parent 38cd7a81
......@@ -10,6 +10,11 @@ import (
irma "github.com/privacybydesign/irmago"
)
const (
JWTIssuerDefault = "keyshare_server"
JWTPinExpiryDefault = 5 * 60 // seconds
)
type (
AesKey [32]byte
......@@ -30,13 +35,18 @@ type (
// IRMA issuer keys that are allowed to be used in keyshare
// sessions
trustedKeys map[irma.PublicKeyIdentifier]*gabikeys.PublicKey
jwtIssuer string
jwtPinExpiry int
}
Configuration struct {
AESKeyID uint32
AESKey AesKey
SignKeyID uint32
SignKey *rsa.PrivateKey
AESKeyID uint32
AESKey AesKey
SignKeyID uint32
SignKey *rsa.PrivateKey
JWTIssuer string
JWTPinExpiry int // in seconds
}
)
......@@ -46,8 +56,19 @@ func NewKeyshareCore(conf *Configuration) *Core {
commitmentData: map[uint64]*big.Int{},
trustedKeys: map[irma.PublicKeyIdentifier]*gabikeys.PublicKey{},
}
c.setAESEncryptionKey(conf.AESKeyID, conf.AESKey)
c.setSignKey(conf.SignKeyID, conf.SignKey)
c.jwtIssuer = conf.JWTIssuer
if c.jwtIssuer == "" {
c.jwtIssuer = JWTIssuerDefault
}
c.jwtPinExpiry = conf.JWTPinExpiry
if c.jwtPinExpiry == 0 {
c.jwtPinExpiry = JWTPinExpiryDefault
}
return c
}
......
......@@ -70,10 +70,10 @@ func (c *Core) ValidatePin(ep EncryptedKeysharePacket, pin string, userID string
// Generate jwt token
id := p.id()
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "keyshare_server",
"iss": c.jwtIssuer,
"sub": "auth_tok",
"iat": time.Now().Unix(),
"exp": time.Now().Add(3 * time.Minute).Unix(),
"exp": time.Now().Add(time.Duration(c.jwtPinExpiry) * time.Second).Unix(),
"token_id": base64.StdEncoding.EncodeToString(id[:]),
})
token.Header["kid"] = c.signKeyID
......@@ -226,7 +226,7 @@ func (c *Core) GenerateResponse(ep EncryptedKeysharePacket, accessToken string,
"ProofP": gabi.KeyshareResponse(p.keyshareSecret(), commit, challenge, key),
"iat": time.Now().Unix(),
"sub": "ProofP",
"iss": "keyshare_server",
"iss": c.jwtIssuer,
})
token.Header["kid"] = c.signKeyID
return token.SignedString(c.signKey)
......
......@@ -37,8 +37,16 @@ func TestPinFunctionality(t *testing.T) {
require.NoError(t, err)
// Test with correct pin
_, err = c.ValidatePin(ep, pin, "testid")
j, err := c.ValidatePin(ep, pin, "testid")
assert.NoError(t, err)
var claims jwt.StandardClaims
_, err = jwt.ParseWithClaims(j, &claims, func(_ *jwt.Token) (interface{}, error) {
return &jwtTestKey.PublicKey, nil
})
assert.NoError(t, err)
assert.Equal(t, "auth_tok", claims.Subject)
assert.Equal(t, time.Now().Unix()+JWTPinExpiryDefault, claims.ExpiresAt)
assert.Equal(t, JWTIssuerDefault, claims.Issuer)
// test change pin
var bnewpin [64]byte
......
......@@ -2,6 +2,7 @@ package cmd
import (
irma "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/keysharecore"
"github.com/privacybydesign/irmago/server"
"github.com/privacybydesign/irmago/server/keyshare/keyshareserver"
"github.com/sietseringers/cobra"
......@@ -47,6 +48,8 @@ func init() {
flags.String("jwt-privkey", "", "Private jwt key of keyshare server")
flags.String("jwt-privkey-file", "", "Path to file containing private jwt key of keyshare server")
flags.Int("jwt-privkey-id", 0, "Key identifier of keyshare server public key matching used private key")
flags.String("jwt-issuer", keysharecore.JWTIssuerDefault, "JWT issuer used in \"iss\" field")
flags.Int("jwt-pin-expiry", keysharecore.JWTPinExpiryDefault, "Expiry of PIN JWT in seconds")
flags.String("storage-primary-keyfile", "", "Primary key used for encrypting and decrypting secure containers")
flags.StringSlice("storage-fallback-keyfile", nil, "Fallback key(s) used to decrypt older secure containers")
flags.Lookup("jwt-privkey").Header = `Cryptographic keys`
......@@ -93,6 +96,8 @@ func configureKeyshared(cmd *cobra.Command) *keyshareserver.Configuration {
JwtKeyID: viper.GetUint32("jwt-privkey-id"),
JwtPrivateKey: viper.GetString("jwt-privkey"),
JwtPrivateKeyFile: viper.GetString("jwt-privkey-file"),
JwtIssuer: viper.GetString("jwt-issuer"),
JwtPinExpiry: viper.GetInt("jwt-pin-expiry"),
StoragePrimaryKeyFile: viper.GetString("storage-primary-keyfile"),
StorageFallbackKeyFiles: viper.GetStringSlice("storage-fallback-keyfile"),
......
......@@ -39,6 +39,8 @@ type Configuration struct {
// Configuration of secure Core
// Private key used to sign JWTs with
JwtKeyID uint32 `json:"jwt_key_id" mapstructure:"jwt_key_id"`
JwtIssuer string `json:"jwt_issuer" mapstructure:"jwt_issuer"`
JwtPinExpiry int `json:"jwt_pin_expiry" mapstructure:"jwt_pin_expiry"`
JwtPrivateKey string `json:"jwt_privkey" mapstructure:"jwt_privkey"`
JwtPrivateKeyFile string `json:"jwt_privkey_file" mapstructure:"jwt_privkey_file"`
// Decryption keys used for keyshare packets
......@@ -142,10 +144,12 @@ func processConfiguration(conf *Configuration) (*keysharecore.Core, error) {
}
core := keysharecore.NewKeyshareCore(&keysharecore.Configuration{
AESKeyID: encID,
AESKey: encKey,
SignKeyID: conf.JwtKeyID,
SignKey: jwtPrivateKey,
AESKeyID: encID,
AESKey: encKey,
SignKeyID: conf.JwtKeyID,
SignKey: jwtPrivateKey,
JWTIssuer: conf.JwtIssuer,
JWTPinExpiry: conf.JwtPinExpiry,
})
for _, keyFile := range conf.StorageFallbackKeyFiles {
id, key, err := readAESKey(keyFile)
......
Supports Markdown
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