Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
IRMA
Github mirrors
irmago
Commits
dd3437ff
Commit
dd3437ff
authored
Oct 01, 2017
by
Sietse Ringers
Browse files
Adding session logs
parent
a2a7f94f
Changes
9
Hide whitespace changes
Inline
Side-by-side
identifiers.go
View file @
dd3437ff
...
...
@@ -112,12 +112,12 @@ func (id *SchemeManagerIdentifier) UnmarshalText(text []byte) error {
return
nil
}
// MarshalText implements encoding.TextMarshaler.
func
(
id
IssuerIdentifier
)
MarshalText
()
([]
byte
,
error
)
{
return
[]
byte
(
id
.
String
()),
nil
}
// TODO enable this when updating protocol
//// MarshalText implements encoding.TextMarshaler.
//func (id IssuerIdentifier) MarshalText() ([]byte, error) {
// return []byte(id.String()), nil
//}
//
//// UnmarshalText implements encoding.TextUnmarshaler.
//func (id *IssuerIdentifier) UnmarshalText(text []byte) error {
// *id = NewIssuerIdentifier(string(text))
...
...
irmago_test.go
View file @
dd3437ff
...
...
@@ -174,13 +174,33 @@ func TestAndroidParse(t *testing.T) {
}
func
TestUnmarshaling
(
t
*
testing
.
T
)
{
parseStorage
(
t
)
manager
:=
parseStorage
(
t
)
// Do session so we can examine its log item later
logs
,
err
:=
manager
.
Logs
()
require
.
NoError
(
t
,
err
)
jwt
:=
getIssuanceJwt
(
"testip"
,
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
))
sessionHelper
(
t
,
jwt
,
"issue"
,
manager
)
newmanager
,
err
:=
NewCredentialManager
(
"testdata/storage/test"
,
"testdata/irma_configuration"
,
"testdata/oldstorage"
,
nil
)
require
.
NoError
(
t
,
err
)
verifyManagerIsUnmarshaled
(
t
,
newmanager
)
verifyCredentials
(
t
,
newmanager
)
verifyKeyshareIsUnmarshaled
(
t
,
newmanager
)
newlogs
,
err
:=
newmanager
.
Logs
()
require
.
NoError
(
t
,
err
)
require
.
True
(
t
,
len
(
newlogs
)
==
len
(
logs
)
+
1
)
entry
:=
newlogs
[
len
(
newlogs
)
-
1
]
require
.
NotNil
(
t
,
entry
)
sessionjwt
,
_
,
err
:=
entry
.
Jwt
()
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
"testip"
,
sessionjwt
.
(
*
IdentityProviderJwt
)
.
ServerName
)
response
,
err
:=
entry
.
GetResponse
()
require
.
NoError
(
t
,
err
)
require
.
NotEmpty
(
t
,
response
.
(
*
IssuanceLog
)
.
Proofs
)
teardown
(
t
)
}
...
...
keyshare.go
View file @
dd3437ff
...
...
@@ -382,7 +382,7 @@ func (ks *keyshareSession) Finish(challenge *big.Int, responses map[SchemeManage
ks
.
sessionHandler
.
KeyshareError
(
err
)
return
}
message
:=
gabi
.
IssueCommitmentMessage
{
Proofs
:
list
,
Nonce2
:
ks
.
session
.
(
*
IssuanceRequest
)
.
state
.
nonce2
}
message
:=
&
gabi
.
IssueCommitmentMessage
{
Proofs
:
list
,
Nonce2
:
ks
.
session
.
(
*
IssuanceRequest
)
.
state
.
nonce2
}
for
_
,
response
:=
range
responses
{
message
.
ProofPjwt
=
response
break
...
...
oldprotocol
.go
→
legacy
.go
View file @
dd3437ff
...
...
@@ -4,10 +4,16 @@ import (
"encoding/json"
"math/big"
"strings"
"time"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
// Legacy from the old Android app, and from the protocol that will be updated
// in the future
func
(
pki
*
publicKeyIdentifier
)
MarshalJSON
()
([]
byte
,
error
)
{
temp
:=
struct
{
Issuer
map
[
string
]
string
`json:"issuer"`
...
...
@@ -82,3 +88,110 @@ func (si *SessionInfo) UnmarshalJSON(b []byte) error {
}
return
nil
}
const
(
androidLogVerificationType
=
"verification"
androidLogIssueType
=
"issue"
androidLogSignatureType
=
"signature"
androidLogRemoveType
=
"remove"
androidLogTimeFormat
=
"January 2, 2006 3:04:05 PM MST -07:00"
)
type
androidLogEnvelope
struct
{
Type
string
`json:"type"`
Value
json
.
RawMessage
`json:"value"`
}
func
(
env
*
androidLogEnvelope
)
Parse
()
(
interface
{},
error
)
{
switch
env
.
Type
{
case
androidLogVerificationType
:
val
:=
&
androidLogVerification
{}
return
val
,
json
.
Unmarshal
(
env
.
Value
,
val
)
case
androidLogIssueType
:
val
:=
&
androidLogIssuance
{}
return
val
,
json
.
Unmarshal
(
env
.
Value
,
val
)
case
androidLogSignatureType
:
val
:=
&
androidLogSignature
{}
return
val
,
json
.
Unmarshal
(
env
.
Value
,
val
)
case
androidLogRemoveType
:
val
:=
&
androidLogRemoval
{}
return
val
,
json
.
Unmarshal
(
env
.
Value
,
val
)
default
:
return
nil
,
errors
.
New
(
"Invalid Android log type"
)
}
}
type
androidLogEntry
struct
{
Time
string
`json:"timestamp"`
Credential
struct
{
Identifier
CredentialTypeIdentifier
`json:"identifier"`
}
`json:"credential"`
}
func
(
entry
*
androidLogEntry
)
GetTime
()
Timestamp
{
// An example date directly from cardemu.xml: September 29, 2017 11:12:57 AM GMT+02:00
// Unfortunately, the seemingly appropriate format parameter for time.Parse, with
// "MST-07:00" at the end, makes time.Parse emit an error: "GMT+02" gets to be
// interpreted as the timezone, i.e. as MST, and then nothing gets mapped onto "-07".
// So, we put a space between "GMT" and "+02:00".
fixed
:=
strings
.
Replace
(
entry
.
Time
,
"+"
,
" +"
,
1
)
parsed
,
_
:=
time
.
Parse
(
androidLogTimeFormat
,
fixed
)
return
Timestamp
(
parsed
)
}
type
androidLogIssuance
struct
{
androidLogEntry
}
type
androidLogRemoval
struct
{
androidLogEntry
}
type
androidLogVerification
struct
{
androidLogEntry
Disclosed
map
[
string
]
bool
`json:"attributeDisclosed"`
}
type
androidLogSignature
struct
{
androidLogVerification
Message
string
`json:"message"`
}
// TODO remove on protocol upgrade
type
logSessionInfo
struct
{
Jwt
string
`json:"jwt"`
Nonce
*
big
.
Int
`json:"nonce"`
Context
*
big
.
Int
`json:"context"`
Keys
map
[
string
]
int
`json:"keys"`
}
// TODO remove on protocol upgrade
func
(
entry
*
LogEntry
)
MarshalJSON
()
([]
byte
,
error
)
{
resp
:=
entry
.
raw
if
len
(
resp
)
==
0
{
if
bytes
,
err
:=
json
.
Marshal
(
entry
.
Response
);
err
==
nil
{
resp
=
json
.
RawMessage
(
bytes
)
}
else
{
return
nil
,
err
}
}
temp
:=
&
jsonLogEntry
{
Type
:
entry
.
Type
,
Time
:
entry
.
Time
,
Response
:
resp
,
SessionInfo
:
&
logSessionInfo
{
Jwt
:
entry
.
SessionInfo
.
Jwt
,
Nonce
:
entry
.
SessionInfo
.
Nonce
,
Context
:
entry
.
SessionInfo
.
Context
,
Keys
:
make
(
map
[
string
]
int
),
},
}
for
iss
,
count
:=
range
entry
.
SessionInfo
.
Keys
{
temp
.
SessionInfo
.
Keys
[
iss
.
String
()]
=
count
}
return
json
.
Marshal
(
temp
)
}
logs.go
0 → 100644
View file @
dd3437ff
package
irmago
import
(
"encoding/json"
"time"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
type
LogEntry
struct
{
Type
Action
Time
Timestamp
// Time at which the session was completed
SessionInfo
*
SessionInfo
// Message that started the session
Response
interface
{}
// Session-type specific info, parsed on-demand, use .GetResponse()
raw
json
.
RawMessage
}
type
RemovalLog
struct
{
Credential
CredentialTypeIdentifier
}
type
VerificationLog
struct
{
Proofs
[]
*
gabi
.
ProofD
}
type
IssuanceLog
struct
{
Proofs
[]
*
gabi
.
ProofD
AttributeList
[]
*
AttributeList
}
type
SigningLog
struct
{
Proofs
[]
*
gabi
.
ProofD
Message
[]
byte
MessageType
string
}
func
(
session
*
session
)
createLogEntry
(
response
gabi
.
ProofList
)
(
*
LogEntry
,
error
)
{
entry
:=
&
LogEntry
{
Type
:
session
.
Action
,
Time
:
Timestamp
(
time
.
Now
()),
SessionInfo
:
session
.
info
,
}
proofs
:=
[]
*
gabi
.
ProofD
{}
for
_
,
proof
:=
range
response
{
if
proofd
,
isproofd
:=
proof
.
(
*
gabi
.
ProofD
);
isproofd
{
proofs
=
append
(
proofs
,
proofd
)
}
}
switch
entry
.
Type
{
case
ActionDisclosing
:
item
:=
&
VerificationLog
{
Proofs
:
proofs
}
entry
.
Response
=
item
case
ActionIssuing
:
item
:=
&
IssuanceLog
{
Proofs
:
proofs
}
for
_
,
req
:=
range
session
.
jwt
.
(
*
IdentityProviderJwt
)
.
Request
.
Request
.
Credentials
{
list
,
err
:=
req
.
AttributeList
(
session
.
credManager
.
Store
)
if
err
!=
nil
{
continue
// TODO?
}
item
.
AttributeList
=
append
(
item
.
AttributeList
,
list
)
}
entry
.
Response
=
item
case
ActionSigning
:
item
:=
SigningLog
{
Proofs
:
proofs
}
item
.
Message
=
[]
byte
(
session
.
jwt
.
(
*
SignatureRequestorJwt
)
.
Request
.
Request
.
Message
)
item
.
MessageType
=
session
.
jwt
.
(
*
SignatureRequestorJwt
)
.
Request
.
Request
.
MessageType
entry
.
Response
=
item
default
:
return
nil
,
errors
.
New
(
"Invalid log type"
)
}
return
entry
,
nil
}
func
(
entry
*
LogEntry
)
Jwt
()
(
RequestorJwt
,
string
,
error
)
{
return
parseRequestorJwt
(
entry
.
Type
,
entry
.
SessionInfo
.
Jwt
)
}
func
(
entry
*
LogEntry
)
GetResponse
()
(
interface
{},
error
)
{
if
entry
.
Response
==
nil
{
switch
entry
.
Type
{
case
ActionDisclosing
:
entry
.
Response
=
&
VerificationLog
{}
case
ActionIssuing
:
entry
.
Response
=
&
IssuanceLog
{}
case
ActionSigning
:
entry
.
Response
=
&
SigningLog
{}
case
Action
(
"removal"
)
:
entry
.
Response
=
&
RemovalLog
{}
default
:
return
nil
,
errors
.
New
(
"Invalid log type"
)
}
err
:=
json
.
Unmarshal
(
entry
.
raw
,
entry
.
Response
)
if
err
!=
nil
{
return
nil
,
err
}
}
return
entry
.
Response
,
nil
}
type
jsonLogEntry
struct
{
Type
Action
Time
Timestamp
SessionInfo
*
logSessionInfo
Response
json
.
RawMessage
}
func
(
entry
*
LogEntry
)
UnmarshalJSON
(
bytes
[]
byte
)
error
{
var
err
error
temp
:=
&
jsonLogEntry
{}
if
err
=
json
.
Unmarshal
(
bytes
,
temp
);
err
!=
nil
{
return
err
}
*
entry
=
LogEntry
{
Type
:
temp
.
Type
,
Time
:
temp
.
Time
,
SessionInfo
:
&
SessionInfo
{
Jwt
:
temp
.
SessionInfo
.
Jwt
,
Nonce
:
temp
.
SessionInfo
.
Nonce
,
Context
:
temp
.
SessionInfo
.
Context
,
Keys
:
make
(
map
[
IssuerIdentifier
]
int
),
},
raw
:
temp
.
Response
,
}
// TODO remove on protocol upgrade
for
iss
,
count
:=
range
temp
.
SessionInfo
.
Keys
{
entry
.
SessionInfo
.
Keys
[
NewIssuerIdentifier
(
iss
)]
=
count
}
return
nil
}
manager.go
View file @
dd3437ff
...
...
@@ -18,6 +18,7 @@ type CredentialManager struct {
credentials
map
[
CredentialTypeIdentifier
]
map
[
int
]
*
credential
keyshareServers
map
[
SchemeManagerIdentifier
]
*
keyshareServer
paillierKeyCache
*
paillierPrivateKey
logs
[]
*
LogEntry
irmaConfigurationPath
string
androidStoragePath
string
...
...
@@ -409,3 +410,19 @@ func (cm *CredentialManager) KeyshareRemove(manager SchemeManagerIdentifier) err
delete
(
cm
.
keyshareServers
,
manager
)
return
cm
.
storeKeyshareServers
()
}
func
(
cm
*
CredentialManager
)
addLogEntry
(
entry
*
LogEntry
)
error
{
cm
.
logs
=
append
(
cm
.
logs
,
entry
)
return
cm
.
storeLogs
()
}
func
(
cm
*
CredentialManager
)
Logs
()
([]
*
LogEntry
,
error
)
{
if
cm
.
logs
==
nil
||
len
(
cm
.
logs
)
==
0
{
var
err
error
cm
.
logs
,
err
=
cm
.
loadLogs
()
if
err
!=
nil
{
return
nil
,
err
}
}
return
cm
.
logs
,
nil
}
messages.go
View file @
dd3437ff
...
...
@@ -130,3 +130,22 @@ func jwtDecode(jwt string, body interface{}) (string, error) {
}
return
header
.
Issuer
,
json
.
Unmarshal
(
bodybytes
,
body
)
}
func
parseRequestorJwt
(
action
Action
,
jwt
string
)
(
RequestorJwt
,
string
,
error
)
{
var
retval
RequestorJwt
switch
action
{
case
ActionDisclosing
:
retval
=
&
ServiceProviderJwt
{}
case
ActionSigning
:
retval
=
&
SignatureRequestorJwt
{}
case
ActionIssuing
:
retval
=
&
IdentityProviderJwt
{}
default
:
return
nil
,
""
,
errors
.
New
(
"Invalid session type"
)
}
server
,
err
:=
jwtDecode
(
jwt
,
retval
)
if
err
!=
nil
{
return
nil
,
""
,
err
}
return
retval
,
server
,
nil
}
session.go
View file @
dd3437ff
...
...
@@ -36,6 +36,7 @@ type session struct {
ServerURL
string
Handler
Handler
info
*
SessionInfo
credManager
*
CredentialManager
jwt
RequestorJwt
irmaSession
IrmaSession
...
...
@@ -132,35 +133,27 @@ func (session *session) start() {
session
.
Handler
.
StatusUpdate
(
session
.
Action
,
StatusCommunicating
)
// Get the first IRMA protocol message and parse it
info
:
=
&
SessionInfo
{}
Err
:=
session
.
transport
.
Get
(
"jwt"
,
info
)
session
.
info
=
&
SessionInfo
{}
Err
:=
session
.
transport
.
Get
(
"jwt"
,
session
.
info
)
if
Err
!=
nil
{
session
.
fail
(
Err
.
(
*
Error
))
return
}
switch
session
.
Action
{
case
ActionDisclosing
:
session
.
jwt
=
&
ServiceProviderJwt
{}
case
ActionSigning
:
session
.
jwt
=
&
SignatureRequestorJwt
{}
case
ActionIssuing
:
session
.
jwt
=
&
IdentityProviderJwt
{}
default
:
panic
(
"Invalid session type"
)
// does not happen, session.Action has been checked earlier
}
server
,
err
:=
jwtDecode
(
info
.
Jwt
,
session
.
jwt
)
var
server
string
var
err
error
session
.
jwt
,
server
,
err
=
parseRequestorJwt
(
session
.
Action
,
session
.
info
.
Jwt
)
if
err
!=
nil
{
session
.
fail
(
&
Error
{
ErrorCode
:
ErrorInvalidJWT
,
Err
:
err
})
return
}
session
.
irmaSession
=
session
.
jwt
.
IrmaSession
()
session
.
irmaSession
.
SetContext
(
info
.
Context
)
session
.
irmaSession
.
SetNonce
(
info
.
Nonce
)
session
.
irmaSession
.
SetContext
(
session
.
info
.
Context
)
session
.
irmaSession
.
SetNonce
(
session
.
info
.
Nonce
)
if
session
.
Action
==
ActionIssuing
{
// Store which public keys the server will use
for
_
,
credreq
:=
range
session
.
irmaSession
.
(
*
IssuanceRequest
)
.
Credentials
{
credreq
.
KeyCounter
=
info
.
Keys
[
credreq
.
Credential
.
IssuerIdentifier
()]
credreq
.
KeyCounter
=
session
.
info
.
Keys
[
credreq
.
Credential
.
IssuerIdentifier
()]
}
}
...
...
@@ -253,7 +246,9 @@ func (session *session) KeyshareError(err error) {
type
disclosureResponse
string
func
(
session
*
session
)
sendResponse
(
message
interface
{})
{
var
log
*
LogEntry
var
err
error
switch
session
.
Action
{
case
ActionSigning
:
fallthrough
...
...
@@ -267,6 +262,7 @@ func (session *session) sendResponse(message interface{}) {
session
.
fail
(
&
Error
{
ErrorCode
:
ErrorRejected
,
Info
:
string
(
response
)})
return
}
log
,
err
=
session
.
createLogEntry
(
message
.
(
gabi
.
ProofList
))
// TODO err
case
ActionIssuing
:
response
:=
[]
*
gabi
.
IssueSignatureMessage
{}
if
err
=
session
.
transport
.
Post
(
"commitments"
,
&
response
,
message
);
err
!=
nil
{
...
...
@@ -277,7 +273,9 @@ func (session *session) sendResponse(message interface{}) {
session
.
fail
(
&
Error
{
Err
:
err
,
ErrorCode
:
ErrorCrypto
})
return
}
log
,
err
=
session
.
createLogEntry
(
message
.
(
*
gabi
.
IssueCommitmentMessage
)
.
Proofs
)
// TODO err
}
session
.
credManager
.
addLogEntry
(
log
)
// TODO err
session
.
Handler
.
Success
(
session
.
Action
)
}
storage.go
View file @
dd3437ff
...
...
@@ -20,6 +20,7 @@ const (
kssFile
=
"kss"
paillierFile
=
"paillier"
updatesFile
=
"updates"
logsFile
=
"logs"
signaturesDir
=
"sigs"
)
...
...
@@ -288,6 +289,15 @@ func (cm *CredentialManager) storePaillierKeys() (err error) {
return
}
func
(
cm
*
CredentialManager
)
storeLogs
()
(
err
error
)
{
bts
,
err
:=
json
.
Marshal
(
cm
.
logs
)
if
err
!=
nil
{
return
}
err
=
saveFile
(
cm
.
path
(
logsFile
),
bts
)
return
}
func
(
cm
*
CredentialManager
)
loadSignature
(
attrs
*
AttributeList
)
(
signature
*
gabi
.
CLSignature
,
err
error
)
{
sigpath
:=
cm
.
signatureFilename
(
attrs
)
exists
,
err
:=
PathExists
(
sigpath
)
...
...
@@ -402,3 +412,20 @@ func (cm *CredentialManager) loadPaillierKeys() (key *paillierPrivateKey, err er
}
return
}
func
(
cm
*
CredentialManager
)
loadLogs
()
(
logs
[]
*
LogEntry
,
err
error
)
{
logs
=
[]
*
LogEntry
{}
exists
,
err
:=
PathExists
(
cm
.
path
(
logsFile
))
if
err
!=
nil
||
!
exists
{
return
}
bytes
,
err
:=
ioutil
.
ReadFile
(
cm
.
path
(
logsFile
))
if
err
!=
nil
{
return
nil
,
err
}
err
=
json
.
Unmarshal
(
bytes
,
&
logs
)
if
err
!=
nil
{
return
nil
,
err
}
return
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment