Commit 3d7ba7f7 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

feat: update revocation commands of irma cli

parent e1e60e99
...@@ -46,7 +46,7 @@ var requestCmd = &cobra.Command{ ...@@ -46,7 +46,7 @@ var requestCmd = &cobra.Command{
}, },
} }
func signRequest(request irma.RequestorRequest, name, authmethod, key string) (string, error) { func configureJWTKey(authmethod, key string) (interface{}, jwt.SigningMethod, error) {
var ( var (
err error err error
sk interface{} sk interface{}
...@@ -61,17 +61,25 @@ func signRequest(request irma.RequestorRequest, name, authmethod, key string) (s ...@@ -61,17 +61,25 @@ func signRequest(request irma.RequestorRequest, name, authmethod, key string) (s
case "hmac": case "hmac":
jwtalg = jwt.SigningMethodHS256 jwtalg = jwt.SigningMethodHS256
if sk, err = fs.Base64Decode(bts); err != nil { if sk, err = fs.Base64Decode(bts); err != nil {
return "", err return nil, nil, err
} }
case "rsa": case "rsa":
jwtalg = jwt.SigningMethodRS256 jwtalg = jwt.SigningMethodRS256
if sk, err = jwt.ParseRSAPrivateKeyFromPEM(bts); err != nil { if sk, err = jwt.ParseRSAPrivateKeyFromPEM(bts); err != nil {
return "", err return nil, nil, err
} }
default: default:
return "", errors.Errorf("Unsupported signing algorithm: '%s'", authmethod) return nil, nil, errors.Errorf("Unsupported signing algorithm: '%s'", authmethod)
} }
return sk, jwtalg, nil
}
func signRequest(request irma.RequestorRequest, name, authmethod, key string) (string, error) {
sk, jwtalg, err := configureJWTKey(authmethod, key)
if err != nil {
return "", err
}
return irma.SignRequestorRequest(request, jwtalg, sk, name) return irma.SignRequestorRequest(request, jwtalg, sk, name)
} }
......
package cmd package cmd
import ( import (
"path/filepath"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/revocation"
irma "github.com/privacybydesign/irmago" irma "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var revokeEnableCmd = &cobra.Command{ var revokeEnableCmd = &cobra.Command{
Use: "enable CREDENTIALTYPE [PATH]", Use: "enable CREDENTIALTYPE",
Short: "Enable revocation for a credential type", Short: "Enable revocation for a credential type",
Long: `Enable revocation for a given credential type. Long: `Enable revocation for a given credential type.
Must be done (and can only be done) by the issuer of the specified credential type, if enable in the Must be done (and can only be done) by the issuer of the specified credential type, if enable in the
scheme. The revocation database is written to or updated from PATH, or the default IRMA storage path scheme.`,
(` + irma.DefaultDataPath() + `).`, Args: cobra.ExactArgs(1),
Args: cobra.RangeArgs(1, 2),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
path := irma.DefaultDataPath() flags := cmd.Flags()
if len(args) > 1 { schemespath, _ := flags.GetString("schemes-path")
path = args[1] authmethod, _ := flags.GetString("auth-method")
key, _ := flags.GetString("key")
name, _ := flags.GetString("name")
verbosity, _ := cmd.Flags().GetCount("verbose")
request := &irma.RevocationRequest{
LDContext: irma.LDContextRevocationRequest,
CredentialType: irma.NewCredentialTypeIdentifier(args[0]),
Enable: true,
} }
db, nonrevKey := configureRevocation(cmd, path, args[0])
if err := db.EnableRevocation(nonrevKey); err != nil { postRevocation(request, schemespath, authmethod, key, name, verbosity)
die("failed to enable revocation", err)
}
}, },
} }
func configureRevocation(cmd *cobra.Command, path, credtype string) (*revocation.DB, *revocation.PrivateKey) {
var err error
if err = fs.EnsureDirectoryExists(filepath.Join(path, "revocation")); err != nil {
die("failed to create revocation database folder", err)
}
// parse irma_configuration and lookup credential type
irmaconf, err := irma.NewConfiguration(filepath.Join(path, "irma_configuration"), irma.ConfigurationOptions{})
if err != nil {
die("failed to open irma_configuration", err)
}
if err = irmaconf.ParseFolder(); err != nil {
die("failed to parse irma_configuration", err)
}
id := irma.NewCredentialTypeIdentifier(credtype)
typ := irmaconf.CredentialTypes[id]
if typ == nil {
die("unknown credential type", nil)
}
// Read private key from either flag or irma_configuration
var privatekey *gabi.PrivateKey
privkeypath, _ := cmd.Flags().GetString("privatekey")
if privkeypath != "" {
privatekey, err = gabi.NewPrivateKeyFromFile(privkeypath)
} else {
privatekey, err = irmaconf.PrivateKey(typ.IssuerIdentifier())
}
if err != nil {
die("failed to read private key", err)
}
if privatekey == nil {
die("no private key specified and none found in irma_configuration", nil)
}
nonrevKey, err := privatekey.RevocationKey()
if err != nil {
die("failed to load nonrevocation private key from IRMA private key", err)
}
db, err := irmaconf.RevocationDB(id)
if err != nil {
die("failed to load revocation database", err)
}
return db, nonrevKey
}
func init() { func init() {
revokeEnableCmd.Flags().StringP("privatekey", "s", "", `Issuer private key for specified credential type`) flags := revokeEnableCmd.Flags()
flags.StringP("schemes-path", "s", irma.DefaultSchemesPath(), "path to irma_configuration")
flags.StringP("auth-method", "a", "none", "Authentication method to server (none, token, rsa, hmac)")
flags.String("key", "", "Key to sign request with")
flags.String("name", "", "Requestor name")
flags.CountP("verbose", "v", "verbose (repeatable)")
revocationCmd.AddCommand(revokeEnableCmd) revocationCmd.AddCommand(revokeEnableCmd)
} }
package cmd
import (
"time"
irma "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server"
"github.com/spf13/cobra"
)
var revokeCmd = &cobra.Command{
Use: "revoke CREDENTIALTYPE KEY",
Short: "Revoke a previously issued credential identified by a given key",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
flags := cmd.Flags()
schemespath, _ := flags.GetString("schemes-path")
authmethod, _ := flags.GetString("auth-method")
key, _ := flags.GetString("key")
name, _ := flags.GetString("name")
verbosity, _ := cmd.Flags().GetCount("verbose")
request := &irma.RevocationRequest{
LDContext: irma.LDContextRevocationRequest,
CredentialType: irma.NewCredentialTypeIdentifier(args[0]),
Key: args[1],
}
postRevocation(request, schemespath, authmethod, key, name, verbosity)
},
}
func postRevocation(request *irma.RevocationRequest, schemespath, authmethod, key, name string, verbosity int) {
logger.Level = server.Verbosity(verbosity)
irma.Logger = logger
conf, err := irma.NewConfiguration(schemespath, irma.ConfigurationOptions{ReadOnly: true})
if err != nil {
die("failed to open irma_configuration", err)
}
if err = conf.ParseFolder(); err != nil {
die("failed to parse irma_configuration", err)
}
credtype, known := conf.CredentialTypes[request.CredentialType]
if !known {
die("unknown credential type", nil)
}
if credtype.RevocationServer == "" {
die("credential type does not support revocation", nil)
}
transport := irma.NewHTTPTransport(credtype.RevocationServer)
switch authmethod {
case "none":
err = transport.Post("session", nil, request)
case "token":
transport.SetHeader("Authorization", key)
err = transport.Post("session", nil, request)
case "hmac", "rsa":
sk, jwtalg, err := configureJWTKey(authmethod, key)
j := irma.RevocationJwt{
ServerJwt: irma.ServerJwt{
ServerName: name,
IssuedAt: irma.Timestamp(time.Now()),
},
Request: request,
}
jwtstr, err := j.Sign(jwtalg, sk)
if err != nil {
die("failed to sign JWT", err)
}
err = transport.Post("session", nil, jwtstr)
default:
die("Invalid authentication method (must be none, token, hmac or rsa)", nil)
}
if err != nil {
die("failed to post revocation request", err)
}
}
func init() {
flags := revokeCmd.Flags()
flags.StringP("schemes-path", "s", irma.DefaultSchemesPath(), "path to irma_configuration")
flags.StringP("auth-method", "a", "none", "Authentication method to server (none, token, rsa, hmac)")
flags.String("key", "", "Key to sign request with")
flags.String("name", "", "Requestor name")
flags.CountP("verbose", "v", "verbose (repeatable)")
revocationCmd.AddCommand(revokeCmd)
}
package cmd
import (
irma "github.com/privacybydesign/irmago"
"github.com/spf13/cobra"
)
var revokeCmd = &cobra.Command{
Use: "revoke CREDENTIALTYPE KEY [PATH]",
Short: "Revoke a previously issued credential identified by a given key",
Args: cobra.RangeArgs(2, 3),
Run: func(cmd *cobra.Command, args []string) {
irmaconf := irma.DefaultSchemesPath()
if len(args) == 3 {
irmaconf = args[2]
} else if irmaconf == "" {
die("Failed to find default irma_configuration path", nil)
}
conf, err := irma.NewConfigurationReadOnly(irmaconf)
if err != nil {
die("", err)
}
if err = conf.ParseFolder(); err != nil {
die("", err)
}
cred := irma.NewCredentialTypeIdentifier(args[0])
if _, known := conf.CredentialTypes[cred]; !known {
die("unknown credential type", nil)
}
flags := cmd.Flags()
authmethod, _ := flags.GetString("authmethod")
key, _ := flags.GetString("key")
name, _ := flags.GetString("name")
_ = &irma.RevocationRequest{
LDContext: irma.LDContextRevocationRequest,
CredentialType: cred,
Key: args[1],
}
},
}
func init() {
flags := revocationCmd.Flags()
flags.StringP("authmethod", "a", "none", "Authentication method to server (none, token, rsa, hmac)")
flags.String("key", "", "Key to sign request with")
flags.String("name", "", "Requestor name")
revocationCmd.AddCommand(revokeCmd)
}
...@@ -42,13 +42,16 @@ func init() { ...@@ -42,13 +42,16 @@ func init() {
func die(message string, err error) { func die(message string, err error) {
var m string var m string
if message != "" { if message != "" {
m = message + ": " m = message
} }
if err != nil { if err != nil {
if message != "" {
m += ": "
}
if e, ok := err.(*errors.Error); ok && logger.IsLevelEnabled(logrus.DebugLevel) { if e, ok := err.(*errors.Error); ok && logger.IsLevelEnabled(logrus.DebugLevel) {
m += e.ErrorStack() m += e.ErrorStack()
} else { } else {
m = m + err.Error() m += err.Error()
} }
} }
......
...@@ -199,7 +199,8 @@ type AttributeRequest struct { ...@@ -199,7 +199,8 @@ type AttributeRequest struct {
type RevocationRequest struct { type RevocationRequest struct {
LDContext string `json:"@context,omitempty"` LDContext string `json:"@context,omitempty"`
CredentialType CredentialTypeIdentifier `json:"type"` CredentialType CredentialTypeIdentifier `json:"type"`
Key string `json:"key"` Key string `json:"key,omitempty"`
Enable bool `json:"enable,omitempty"`
} }
func (r *RevocationRequest) Validate() error { func (r *RevocationRequest) Validate() error {
...@@ -923,6 +924,10 @@ func (claims *RevocationJwt) Valid() error { ...@@ -923,6 +924,10 @@ func (claims *RevocationJwt) Valid() error {
return nil return nil
} }
func (claims *RevocationJwt) Sign(method jwt.SigningMethod, key interface{}) (string, error) {
return jwt.NewWithClaims(method, claims).SignedString(key)
}
func (claims *ServiceProviderJwt) Action() Action { return ActionDisclosing } func (claims *ServiceProviderJwt) Action() Action { return ActionDisclosing }
func (claims *SignatureRequestorJwt) Action() Action { return ActionSigning } func (claims *SignatureRequestorJwt) Action() Action { return ActionSigning }
......
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