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

Get session request directly instead of jwt at start of interactive sessions


Co-authored-by: Tomas's avatarConfiks <confiks@scriptbase.org>
parent fe20bca4
...@@ -186,9 +186,7 @@ func TestLogging(t *testing.T) { ...@@ -186,9 +186,7 @@ func TestLogging(t *testing.T) {
entry := logs[len(logs)-1] entry := logs[len(logs)-1]
require.NotNil(t, entry) require.NotNil(t, entry)
sessionjwt, err := entry.Jwt() require.Equal(t, "testip", entry.Request.GetRequestorName())
require.NoError(t, err)
require.Equal(t, "testip", sessionjwt.(*irma.IdentityProviderJwt).ServerName)
require.NoError(t, err) require.NoError(t, err)
issued, err := entry.GetIssuedCredentials(client.Configuration) issued, err := entry.GetIssuedCredentials(client.Configuration)
require.NoError(t, err) require.NoError(t, err)
...@@ -206,9 +204,7 @@ func TestLogging(t *testing.T) { ...@@ -206,9 +204,7 @@ func TestLogging(t *testing.T) {
entry = logs[len(logs)-1] entry = logs[len(logs)-1]
require.NotNil(t, entry) require.NotNil(t, entry)
sessionjwt, err = entry.Jwt() require.Equal(t, "testsp", entry.Request.GetRequestorName())
require.NoError(t, err)
require.Equal(t, "testsp", sessionjwt.(*irma.ServiceProviderJwt).ServerName)
require.NoError(t, err) require.NoError(t, err)
disclosed, err = entry.GetDisclosedCredentials(client.Configuration) disclosed, err = entry.GetDisclosedCredentials(client.Configuration)
require.NoError(t, err) require.NoError(t, err)
...@@ -222,9 +218,7 @@ func TestLogging(t *testing.T) { ...@@ -222,9 +218,7 @@ func TestLogging(t *testing.T) {
require.True(t, len(logs) == oldLogLength+3) require.True(t, len(logs) == oldLogLength+3)
entry = logs[len(logs)-1] entry = logs[len(logs)-1]
require.NotNil(t, entry) require.NotNil(t, entry)
sessionjwt, err = entry.Jwt() require.Equal(t, "testsigclient", entry.Request.GetRequestorName())
require.NoError(t, err)
require.Equal(t, "testsigclient", sessionjwt.(*irma.SignatureRequestorJwt).ServerName)
require.NoError(t, err) require.NoError(t, err)
sig, err := entry.GetSignedMessage() sig, err := entry.GetSignedMessage()
require.NoError(t, err) require.NoError(t, err)
......
...@@ -9,16 +9,13 @@ import ( ...@@ -9,16 +9,13 @@ import (
"github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago"
) )
// LogSessionInfo is a SessionInfo alias to bypass the custom JSON marshaler
type LogSessionInfo irma.SessionInfo
// LogEntry is a log entry of a past event. // LogEntry is a log entry of a past event.
type LogEntry struct { type LogEntry struct {
// General info // General info
Type irma.Action Type irma.Action
Time irma.Timestamp // Time at which the session was completed Time irma.Timestamp // Time at which the session was completed
SessionInfo *LogSessionInfo `json:",omitempty"` // Message that started the session Version *irma.ProtocolVersion `json:",omitempty"` // Protocol version that was used in the session
Version *irma.ProtocolVersion `json:",omitempty"` // Protocol version that was used in the session Request irma.SessionRequest `json:",omitempty"` // Message that started the session
// Session type-specific info // Session type-specific info
Removed map[irma.CredentialTypeIdentifier][]irma.TranslatedString `json:",omitempty"` // In case of credential removal Removed map[irma.CredentialTypeIdentifier][]irma.TranslatedString `json:",omitempty"` // In case of credential removal
...@@ -50,12 +47,7 @@ func (entry *LogEntry) GetIssuedCredentials(conf *irma.Configuration) (list irma ...@@ -50,12 +47,7 @@ func (entry *LogEntry) GetIssuedCredentials(conf *irma.Configuration) (list irma
if entry.Type != irma.ActionIssuing { if entry.Type != irma.ActionIssuing {
return irma.CredentialInfoList{}, nil return irma.CredentialInfoList{}, nil
} }
jwt, err := irma.ParseRequestorJwt(irma.ActionIssuing, entry.SessionInfo.Jwt) return entry.Request.(*irma.IssuanceRequest).GetCredentialInfoList(conf, entry.Version)
if err != nil {
return
}
ir := jwt.SessionRequest().(*irma.IssuanceRequest)
return ir.GetCredentialInfoList(conf, entry.Version)
} }
// GetSignedMessage gets the signed for a log entry // GetSignedMessage gets the signed for a log entry
...@@ -63,10 +55,11 @@ func (entry *LogEntry) GetSignedMessage() (abs *irma.SignedMessage, err error) { ...@@ -63,10 +55,11 @@ func (entry *LogEntry) GetSignedMessage() (abs *irma.SignedMessage, err error) {
if entry.Type != irma.ActionSigning { if entry.Type != irma.ActionSigning {
return nil, nil return nil, nil
} }
request := entry.Request.(*irma.SignatureRequest)
return &irma.SignedMessage{ return &irma.SignedMessage{
Signature: entry.ProofList, Signature: entry.ProofList,
Nonce: entry.SessionInfo.Nonce, Nonce: request.Nonce,
Context: entry.SessionInfo.Context, Context: request.Context,
Message: string(entry.SignedMessage), Message: string(entry.SignedMessage),
Timestamp: entry.Timestamp, Timestamp: entry.Timestamp,
}, nil }, nil
...@@ -74,10 +67,10 @@ func (entry *LogEntry) GetSignedMessage() (abs *irma.SignedMessage, err error) { ...@@ -74,10 +67,10 @@ func (entry *LogEntry) GetSignedMessage() (abs *irma.SignedMessage, err error) {
func (session *session) createLogEntry(response interface{}) (*LogEntry, error) { func (session *session) createLogEntry(response interface{}) (*LogEntry, error) {
entry := &LogEntry{ entry := &LogEntry{
Type: session.Action, Type: session.Action,
Time: irma.Timestamp(time.Now()), Time: irma.Timestamp(time.Now()),
Version: session.Version, Version: session.Version,
SessionInfo: (*LogSessionInfo)(session.info), Request: session.request,
} }
switch entry.Type { switch entry.Type {
...@@ -100,9 +93,3 @@ func (session *session) createLogEntry(response interface{}) (*LogEntry, error) ...@@ -100,9 +93,3 @@ func (session *session) createLogEntry(response interface{}) (*LogEntry, error)
return entry, nil return entry, nil
} }
// Jwt returns the JWT from the requestor that started the IRMA session which the
// current log entry tracks.
func (entry *LogEntry) Jwt() (irma.RequestorJwt, error) {
return irma.ParseRequestorJwt(entry.Type, entry.SessionInfo.Jwt)
}
...@@ -66,8 +66,6 @@ type session struct { ...@@ -66,8 +66,6 @@ type session struct {
// These are empty on manual sessions // These are empty on manual sessions
ServerURL string ServerURL string
info *irma.SessionInfo
jwt irma.RequestorJwt
transport *irma.HTTPTransport transport *irma.HTTPTransport
} }
...@@ -76,7 +74,7 @@ var _ keyshareSessionHandler = (*session)(nil) ...@@ -76,7 +74,7 @@ var _ keyshareSessionHandler = (*session)(nil)
// Supported protocol versions. Minor version numbers should be reverse sorted. // Supported protocol versions. Minor version numbers should be reverse sorted.
var supportedVersions = map[int][]int{ var supportedVersions = map[int][]int{
2: {3, 2, 1}, 2: {4, 3, 2, 1},
} }
// Session constructors // Session constructors
...@@ -136,9 +134,9 @@ func (client *Client) newManualSession(sigrequest *irma.SignatureRequest, handle ...@@ -136,9 +134,9 @@ func (client *Client) newManualSession(sigrequest *irma.SignatureRequest, handle
request: sigrequest, request: sigrequest,
} }
sigrequest.RequestorName = "Email request"
session.Handler.StatusUpdate(session.Action, irma.StatusManualStarted) session.Handler.StatusUpdate(session.Action, irma.StatusManualStarted)
session.processSessionInfo()
session.processSessionInfo("Email request")
return session return session
} }
...@@ -157,6 +155,21 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse ...@@ -157,6 +155,21 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse
return session return session
} }
// Check if the action is one of the supported types
switch session.Action {
case irma.ActionDisclosing:
session.request = &irma.DisclosureRequest{}
case irma.ActionSigning:
session.request = &irma.SignatureRequest{}
case irma.ActionIssuing:
session.request = &irma.IssuanceRequest{}
case irma.ActionUnknown:
fallthrough
default:
session.fail(&irma.SessionError{ErrorType: irma.ErrorUnknownAction, Info: string(session.Action)})
return nil
}
version, err := calcVersion(qr) version, err := calcVersion(qr)
if err != nil { if err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorProtocolVersionNotSupported, Err: err}) session.fail(&irma.SessionError{ErrorType: irma.ErrorProtocolVersionNotSupported, Err: err})
...@@ -168,18 +181,6 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse ...@@ -168,18 +181,6 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse
session.ServerURL += "/" session.ServerURL += "/"
} }
// Check if the action is one of the supported types
switch session.Action {
case irma.ActionDisclosing: // nop
case irma.ActionSigning: // nop
case irma.ActionIssuing: // nop
case irma.ActionUnknown:
fallthrough
default:
session.fail(&irma.SessionError{ErrorType: irma.ErrorUnknownAction, Info: string(session.Action)})
return nil
}
go session.getSessionInfo() go session.getSessionInfo()
return session return session
} }
...@@ -193,43 +194,32 @@ func (session *session) getSessionInfo() { ...@@ -193,43 +194,32 @@ func (session *session) getSessionInfo() {
session.Handler.StatusUpdate(session.Action, irma.StatusCommunicating) session.Handler.StatusUpdate(session.Action, irma.StatusCommunicating)
// Get the first IRMA protocol message and parse it // Get the first IRMA protocol message and parse it
session.info = &irma.SessionInfo{} err := session.transport.Get("", session.request)
Err := session.transport.Get("jwt", session.info)
if Err != nil {
session.fail(Err.(*irma.SessionError))
return
}
var err error
session.jwt, err = irma.ParseRequestorJwt(session.Action, session.info.Jwt)
if err != nil { if err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorInvalidJWT, Err: err}) session.fail(err.(*irma.SessionError))
return return
} }
session.request = session.jwt.SessionRequest()
session.request.SetContext(session.info.Context)
session.request.SetNonce(session.info.Nonce)
session.request.SetVersion(session.Version)
if session.Action == irma.ActionIssuing {
ir := session.request.(*irma.IssuanceRequest)
// Store which public keys the server will use
for _, credreq := range ir.Credentials {
credreq.KeyCounter = session.info.Keys[credreq.CredentialTypeID.IssuerIdentifier()]
}
}
session.processSessionInfo(session.jwt.Requestor()) session.processSessionInfo()
} }
// processSessionInfo continues the session after all session state has been received: // processSessionInfo continues the session after all session state has been received:
// it checks if the session can be performed and asks the user for consent. // it checks if the session can be performed and asks the user for consent.
func (session *session) processSessionInfo(requestorname string) { func (session *session) processSessionInfo() {
defer session.recoverFromPanic() defer session.recoverFromPanic()
if !session.checkAndUpateConfiguration() { if !session.checkAndUpateConfiguration() {
return return
} }
confirmedProtocolVersion := session.request.GetVersion()
if confirmedProtocolVersion != nil {
session.Version = confirmedProtocolVersion
} else {
session.Version = irma.NewVersion(2, 0)
session.request.SetVersion(session.Version)
}
if session.Action == irma.ActionIssuing { if session.Action == irma.ActionIssuing {
ir := session.request.(*irma.IssuanceRequest) ir := session.request.(*irma.IssuanceRequest)
_, err := ir.GetCredentialInfoList(session.client.Configuration, session.Version) _, err := ir.GetCredentialInfoList(session.client.Configuration, session.Version)
...@@ -249,7 +239,7 @@ func (session *session) processSessionInfo(requestorname string) { ...@@ -249,7 +239,7 @@ func (session *session) processSessionInfo(requestorname string) {
candidates, missing := session.client.CheckSatisfiability(session.request.ToDisclose()) candidates, missing := session.client.CheckSatisfiability(session.request.ToDisclose())
if len(missing) > 0 { if len(missing) > 0 {
session.Handler.UnsatisfiableRequest(session.Action, requestorname, missing) session.Handler.UnsatisfiableRequest(session.Action, session.request.GetRequestorName(), missing)
return return
} }
session.request.SetCandidates(candidates) session.request.SetCandidates(candidates)
...@@ -264,13 +254,13 @@ func (session *session) processSessionInfo(requestorname string) { ...@@ -264,13 +254,13 @@ func (session *session) processSessionInfo(requestorname string) {
switch session.Action { switch session.Action {
case irma.ActionDisclosing: case irma.ActionDisclosing:
session.Handler.RequestVerificationPermission( session.Handler.RequestVerificationPermission(
*session.request.(*irma.DisclosureRequest), requestorname, callback) *session.request.(*irma.DisclosureRequest), session.request.GetRequestorName(), callback)
case irma.ActionSigning: case irma.ActionSigning:
session.Handler.RequestSignaturePermission( session.Handler.RequestSignaturePermission(
*session.request.(*irma.SignatureRequest), requestorname, callback) *session.request.(*irma.SignatureRequest), session.request.GetRequestorName(), callback)
case irma.ActionIssuing: case irma.ActionIssuing:
session.Handler.RequestIssuancePermission( session.Handler.RequestIssuancePermission(
*session.request.(*irma.IssuanceRequest), requestorname, callback) *session.request.(*irma.IssuanceRequest), session.request.GetRequestorName(), callback)
default: default:
panic("Invalid session type") // does not happen, session.Action has been checked earlier panic("Invalid session type") // does not happen, session.Action has been checked earlier
} }
......
...@@ -2,6 +2,7 @@ package irmaclient ...@@ -2,6 +2,7 @@ package irmaclient
import ( import (
"encoding/json" "encoding/json"
"math/big"
"regexp" "regexp"
"time" "time"
...@@ -78,7 +79,12 @@ var clientUpdates = []func(client *Client) error{ ...@@ -78,7 +79,12 @@ var clientUpdates = []func(client *Client) error{
// The logs read above do not contain the Response field as it has been removed from the LogEntry struct. // The logs read above do not contain the Response field as it has been removed from the LogEntry struct.
// So read the logs again into a slice of a temp struct that does contain this field. // So read the logs again into a slice of a temp struct that does contain this field.
type oldLogEntry struct { type oldLogEntry struct {
Response json.RawMessage Response json.RawMessage
SessionInfo struct {
Nonce *big.Int `json:"nonce"`
Context *big.Int `json:"context"`
Jwt string `json:"jwt"`
}
} }
var oldLogs []*oldLogEntry var oldLogs []*oldLogEntry
if err = client.storage.load(&oldLogs, logsFile); err != nil { if err = client.storage.load(&oldLogs, logsFile); err != nil {
...@@ -96,6 +102,16 @@ var clientUpdates = []func(client *Client) error{ ...@@ -96,6 +102,16 @@ var clientUpdates = []func(client *Client) error{
return errors.New("Log entry had no Response field") return errors.New("Log entry had no Response field")
} }
var jwt irma.RequestorJwt
jwt, err = irma.ParseRequestorJwt(entry.Type, oldEntry.SessionInfo.Jwt)
if err != nil {
return err
}
entry.Request = jwt.SessionRequest()
entry.Request.SetRequestorName(jwt.Requestor())
entry.Request.SetNonce(oldEntry.SessionInfo.Nonce)
entry.Request.SetContext(oldEntry.SessionInfo.Context)
switch entry.Type { switch entry.Type {
case actionRemoval: // nop case actionRemoval: // nop
case irma.ActionSigning: case irma.ActionSigning:
...@@ -125,12 +141,7 @@ var clientUpdates = []func(client *Client) error{ ...@@ -125,12 +141,7 @@ var clientUpdates = []func(client *Client) error{
// that was introduced in version 2.3 of the protocol. The only thing that I can think of to determine this // that was introduced in version 2.3 of the protocol. The only thing that I can think of to determine this
// is to check if the attributes are human-readable, i.e., alphanumeric: if the presence bit is present and // is to check if the attributes are human-readable, i.e., alphanumeric: if the presence bit is present and
// we do not shift it away, then they almost certainly will not be. // we do not shift it away, then they almost certainly will not be.
var jwt irma.RequestorJwt for _, attr := range entry.Request.(*irma.IssuanceRequest).Credentials[0].Attributes {
jwt, err = entry.Jwt()
if err != nil {
return
}
for _, attr := range jwt.SessionRequest().(*irma.IssuanceRequest).Credentials[0].Attributes {
if regexp.MustCompile("^\\w").Match([]byte(attr)) { if regexp.MustCompile("^\\w").Match([]byte(attr)) {
entry.Version = irma.NewVersion(2, 2) entry.Version = irma.NewVersion(2, 2)
} else { } else {
......
package irma
import (
"encoding/json"
"math/big"
"github.com/go-errors/errors"
)
// Legacy from the protocol that will be updated in the future
// Because the Java version of the current version of the protocol misses a serializer for the Java-equivalent
// of the Java-equivalent of the IssuerIdentifier struct, these get serialized to an ugly map structure that we
// have to parse here.
func (si *SessionInfo) UnmarshalJSON(b []byte) error {
temp := &struct {
Jwt string `json:"jwt"`
Nonce *big.Int `json:"nonce"`
Context *big.Int `json:"context"`
Keys [][]interface{} `json:"keys"`
}{}
err := json.Unmarshal(b, temp)
if err != nil {
return err
}
si.Jwt = temp.Jwt
si.Nonce = temp.Nonce
si.Context = temp.Context
si.Keys = make(map[IssuerIdentifier]int, len(temp.Keys))
for _, item := range temp.Keys {
var idmap map[string]interface{}
var idstr string
var counter float64
var ok bool
if idmap, ok = item[0].(map[string]interface{}); !ok {
return errors.New("Failed to deserialize session info")
}
if idstr, ok = idmap["identifier"].(string); !ok {
return errors.New("Failed to deserialize session info")
}
if counter, ok = item[1].(float64); !ok {
return errors.New("Failed to deserialize session info")
}
id := NewIssuerIdentifier(idstr)
si.Keys[id] = int(counter)
}
return nil
}
...@@ -3,7 +3,6 @@ package irma ...@@ -3,7 +3,6 @@ package irma
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"math/big"
"strconv" "strconv"
"strings" "strings"
...@@ -111,15 +110,6 @@ type Qr struct { ...@@ -111,15 +110,6 @@ type Qr struct {
ProtocolMaxVersion ProtocolVersion `json:"vmax"` ProtocolMaxVersion ProtocolVersion `json:"vmax"`
} }
// A SessionInfo is the first message in the IRMA protocol (i.e., GET on the server URL),
// containing the session request info.
type SessionInfo struct {
Jwt string `json:"jwt"`
Nonce *big.Int `json:"nonce"`
Context *big.Int `json:"context"`
Keys map[IssuerIdentifier]int `json:"keys"`
}
// Statuses // Statuses
const ( const (
StatusConnected = Status("connected") StatusConnected = Status("connected")
......
...@@ -17,9 +17,10 @@ import ( ...@@ -17,9 +17,10 @@ import (
// BaseRequest contains the context and nonce for an IRMA session. // BaseRequest contains the context and nonce for an IRMA session.
type BaseRequest struct { type BaseRequest struct {
Context *big.Int `json:"context"` Context *big.Int `json:"context"`
Nonce *big.Int `json:"nonce"` Nonce *big.Int `json:"nonce"`
Candidates [][]*AttributeIdentifier `json:"-"` RequestorName string `json:"requestorName"`
Candidates [][]*AttributeIdentifier `json:"-"`
Choice *DisclosureChoice `json:"-"` Choice *DisclosureChoice `json:"-"`
Ids *IrmaIdentifierSet `json:"-"` Ids *IrmaIdentifierSet `json:"-"`
...@@ -51,6 +52,14 @@ func (sr *BaseRequest) GetVersion() *ProtocolVersion { ...@@ -51,6 +52,14 @@ func (sr *BaseRequest) GetVersion() *ProtocolVersion {
return sr.version return sr.version
} }
func (sr *BaseRequest) GetRequestorName() string {
return sr.RequestorName
}
func (sr *BaseRequest) SetRequestorName(name string) {
sr.RequestorName = name
}
// A DisclosureRequest is a request to disclose certain attributes. // A DisclosureRequest is a request to disclose certain attributes.
type DisclosureRequest struct { type DisclosureRequest struct {
BaseRequest BaseRequest
...@@ -133,7 +142,10 @@ type SessionRequest interface { ...@@ -133,7 +142,10 @@ type SessionRequest interface {
SetNonce(*big.Int) SetNonce(*big.Int)
GetContext() *big.Int GetContext() *big.Int
SetContext(*big.Int) SetContext(*big.Int)
GetVersion() *ProtocolVersion
SetVersion(*ProtocolVersion) SetVersion(*ProtocolVersion)
GetRequestorName() string
SetRequestorName(string)
ToDisclose() AttributeDisjunctionList ToDisclose() AttributeDisjunctionList
DisclosureChoice() *DisclosureChoice DisclosureChoice() *DisclosureChoice
SetDisclosureChoice(choice *DisclosureChoice) SetDisclosureChoice(choice *DisclosureChoice)
......
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