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) {
entry := logs[len(logs)-1]
require.NotNil(t, entry)
sessionjwt, err := entry.Jwt()
require.NoError(t, err)
require.Equal(t, "testip", sessionjwt.(*irma.IdentityProviderJwt).ServerName)
require.Equal(t, "testip", entry.Request.GetRequestorName())
require.NoError(t, err)
issued, err := entry.GetIssuedCredentials(client.Configuration)
require.NoError(t, err)
......@@ -206,9 +204,7 @@ func TestLogging(t *testing.T) {
entry = logs[len(logs)-1]
require.NotNil(t, entry)
sessionjwt, err = entry.Jwt()
require.NoError(t, err)
require.Equal(t, "testsp", sessionjwt.(*irma.ServiceProviderJwt).ServerName)
require.Equal(t, "testsp", entry.Request.GetRequestorName())
require.NoError(t, err)
disclosed, err = entry.GetDisclosedCredentials(client.Configuration)
require.NoError(t, err)
......@@ -222,9 +218,7 @@ func TestLogging(t *testing.T) {
require.True(t, len(logs) == oldLogLength+3)
entry = logs[len(logs)-1]
require.NotNil(t, entry)
sessionjwt, err = entry.Jwt()
require.NoError(t, err)
require.Equal(t, "testsigclient", sessionjwt.(*irma.SignatureRequestorJwt).ServerName)
require.Equal(t, "testsigclient", entry.Request.GetRequestorName())
require.NoError(t, err)
sig, err := entry.GetSignedMessage()
require.NoError(t, err)
......
......@@ -9,16 +9,13 @@ import (
"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.
type LogEntry struct {
// General info
Type irma.Action
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
Type irma.Action
Time irma.Timestamp // Time at which the session was completed
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
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
if entry.Type != irma.ActionIssuing {
return irma.CredentialInfoList{}, nil
}
jwt, err := irma.ParseRequestorJwt(irma.ActionIssuing, entry.SessionInfo.Jwt)
if err != nil {
return
}
ir := jwt.SessionRequest().(*irma.IssuanceRequest)
return ir.GetCredentialInfoList(conf, entry.Version)
return entry.Request.(*irma.IssuanceRequest).GetCredentialInfoList(conf, entry.Version)
}
// GetSignedMessage gets the signed for a log entry
......@@ -63,10 +55,11 @@ func (entry *LogEntry) GetSignedMessage() (abs *irma.SignedMessage, err error) {
if entry.Type != irma.ActionSigning {
return nil, nil
}
request := entry.Request.(*irma.SignatureRequest)
return &irma.SignedMessage{
Signature: entry.ProofList,
Nonce: entry.SessionInfo.Nonce,
Context: entry.SessionInfo.Context,
Nonce: request.Nonce,
Context: request.Context,
Message: string(entry.SignedMessage),
Timestamp: entry.Timestamp,
}, nil
......@@ -74,10 +67,10 @@ func (entry *LogEntry) GetSignedMessage() (abs *irma.SignedMessage, err error) {
func (session *session) createLogEntry(response interface{}) (*LogEntry, error) {
entry := &LogEntry{
Type: session.Action,
Time: irma.Timestamp(time.Now()),
Version: session.Version,
SessionInfo: (*LogSessionInfo)(session.info),
Type: session.Action,
Time: irma.Timestamp(time.Now()),
Version: session.Version,
Request: session.request,
}
switch entry.Type {
......@@ -100,9 +93,3 @@ func (session *session) createLogEntry(response interface{}) (*LogEntry, error)
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 {
// These are empty on manual sessions
ServerURL string
info *irma.SessionInfo
jwt irma.RequestorJwt
transport *irma.HTTPTransport
}
......@@ -76,7 +74,7 @@ var _ keyshareSessionHandler = (*session)(nil)
// Supported protocol versions. Minor version numbers should be reverse sorted.
var supportedVersions = map[int][]int{
2: {3, 2, 1},
2: {4, 3, 2, 1},
}
// Session constructors
......@@ -136,9 +134,9 @@ func (client *Client) newManualSession(sigrequest *irma.SignatureRequest, handle
request: sigrequest,
}
sigrequest.RequestorName = "Email request"
session.Handler.StatusUpdate(session.Action, irma.StatusManualStarted)
session.processSessionInfo("Email request")
session.processSessionInfo()
return session
}
......@@ -157,6 +155,21 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse
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)
if err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorProtocolVersionNotSupported, Err: err})
......@@ -168,18 +181,6 @@ func (client *Client) newQrSession(qr *irma.Qr, handler Handler) SessionDismisse
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()
return session
}
......@@ -193,43 +194,32 @@ func (session *session) getSessionInfo() {
session.Handler.StatusUpdate(session.Action, irma.StatusCommunicating)
// Get the first IRMA protocol message and parse it
session.info = &irma.SessionInfo{}
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)
err := session.transport.Get("", session.request)
if err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorInvalidJWT, Err: err})
session.fail(err.(*irma.SessionError))
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:
// 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()
if !session.checkAndUpateConfiguration() {
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 {
ir := session.request.(*irma.IssuanceRequest)
_, err := ir.GetCredentialInfoList(session.client.Configuration, session.Version)
......@@ -249,7 +239,7 @@ func (session *session) processSessionInfo(requestorname string) {
candidates, missing := session.client.CheckSatisfiability(session.request.ToDisclose())
if len(missing) > 0 {
session.Handler.UnsatisfiableRequest(session.Action, requestorname, missing)
session.Handler.UnsatisfiableRequest(session.Action, session.request.GetRequestorName(), missing)
return
}
session.request.SetCandidates(candidates)
......@@ -264,13 +254,13 @@ func (session *session) processSessionInfo(requestorname string) {
switch session.Action {
case irma.ActionDisclosing:
session.Handler.RequestVerificationPermission(
*session.request.(*irma.DisclosureRequest), requestorname, callback)
*session.request.(*irma.DisclosureRequest), session.request.GetRequestorName(), callback)
case irma.ActionSigning:
session.Handler.RequestSignaturePermission(
*session.request.(*irma.SignatureRequest), requestorname, callback)
*session.request.(*irma.SignatureRequest), session.request.GetRequestorName(), callback)
case irma.ActionIssuing:
session.Handler.RequestIssuancePermission(
*session.request.(*irma.IssuanceRequest), requestorname, callback)
*session.request.(*irma.IssuanceRequest), session.request.GetRequestorName(), callback)
default:
panic("Invalid session type") // does not happen, session.Action has been checked earlier
}
......
......@@ -2,6 +2,7 @@ package irmaclient
import (
"encoding/json"
"math/big"
"regexp"
"time"
......@@ -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.
// So read the logs again into a slice of a temp struct that does contain this field.
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
if err = client.storage.load(&oldLogs, logsFile); err != nil {
......@@ -96,6 +102,16 @@ var clientUpdates = []func(client *Client) error{
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 {
case actionRemoval: // nop
case irma.ActionSigning:
......@@ -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
// 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.
var jwt irma.RequestorJwt
jwt, err = entry.Jwt()
if err != nil {
return
}
for _, attr := range jwt.SessionRequest().(*irma.IssuanceRequest).Credentials[0].Attributes {
for _, attr := range entry.Request.(*irma.IssuanceRequest).Credentials[0].Attributes {
if regexp.MustCompile("^\\w").Match([]byte(attr)) {
entry.Version = irma.NewVersion(2, 2)
} 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
import (
"encoding/base64"
"encoding/json"
"math/big"
"strconv"
"strings"
......@@ -111,15 +110,6 @@ type Qr struct {
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
const (
StatusConnected = Status("connected")
......
......@@ -17,9 +17,10 @@ import (
// BaseRequest contains the context and nonce for an IRMA session.
type BaseRequest struct {
Context *big.Int `json:"context"`
Nonce *big.Int `json:"nonce"`
Candidates [][]*AttributeIdentifier `json:"-"`
Context *big.Int `json:"context"`
Nonce *big.Int `json:"nonce"`
RequestorName string `json:"requestorName"`
Candidates [][]*AttributeIdentifier `json:"-"`
Choice *DisclosureChoice `json:"-"`
Ids *IrmaIdentifierSet `json:"-"`
......@@ -51,6 +52,14 @@ func (sr *BaseRequest) GetVersion() *ProtocolVersion {
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.
type DisclosureRequest struct {
BaseRequest
......@@ -133,7 +142,10 @@ type SessionRequest interface {
SetNonce(*big.Int)
GetContext() *big.Int
SetContext(*big.Int)
GetVersion() *ProtocolVersion
SetVersion(*ProtocolVersion)
GetRequestorName() string
SetRequestorName(string)
ToDisclose() AttributeDisjunctionList
DisclosureChoice() *DisclosureChoice
SetDisclosureChoice(choice *DisclosureChoice)
......
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