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
b73b7df8
Commit
b73b7df8
authored
Mar 02, 2018
by
Sietse Ringers
Browse files
Merge branch 'optional-attributes'
parents
f4262fdf
6b0a56ad
Changes
13
Hide whitespace changes
Inline
Side-by-side
attributes.go
View file @
b73b7df8
...
...
@@ -9,6 +9,7 @@ import (
"time"
"fmt"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
...
...
@@ -38,8 +39,6 @@ const (
)
var
(
metadataVersion
=
[]
byte
{
0x02
}
versionField
=
metadataField
{
1
,
0
}
signingDateField
=
metadataField
{
3
,
1
}
validityField
=
metadataField
{
2
,
4
}
...
...
@@ -102,7 +101,15 @@ func (al *AttributeList) Strings() []TranslatedString {
if
al
.
strings
==
nil
{
al
.
strings
=
make
([]
TranslatedString
,
len
(
al
.
Ints
)
-
1
)
for
index
,
num
:=
range
al
.
Ints
[
1
:
]
{
// skip metadata
al
.
strings
[
index
]
=
map
[
string
]
string
{
"en"
:
string
(
num
.
Bytes
()),
"nl"
:
string
(
num
.
Bytes
())}
// TODO
bi
:=
new
(
big
.
Int
)
.
Set
(
num
)
if
al
.
MetadataAttribute
.
Version
()
>=
3
{
if
bi
.
Bit
(
0
)
==
0
{
// attribute does not exist
continue
}
bi
=
bi
.
Rsh
(
bi
,
1
)
}
val
:=
string
(
bi
.
Bytes
())
al
.
strings
[
index
]
=
map
[
string
]
string
{
"en"
:
val
,
"nl"
:
val
}
// TODO
}
}
return
al
.
strings
...
...
@@ -139,13 +146,13 @@ func MetadataFromInt(i *big.Int, conf *Configuration) *MetadataAttribute {
}
// NewMetadataAttribute constructs a new instance containing the default values:
//
0x02
as versionField
//
provided version
as versionField
// now as signing date
// 0 as keycounter
// ValidityDefault (half a year) as default validity.
func
NewMetadataAttribute
()
*
MetadataAttribute
{
func
NewMetadataAttribute
(
version
byte
)
*
MetadataAttribute
{
val
:=
MetadataAttribute
{
new
(
big
.
Int
),
nil
,
nil
}
val
.
setField
(
versionField
,
metadataV
ersion
)
val
.
setField
(
versionField
,
[]
byte
{
v
ersion
}
)
val
.
setSigningDate
()
val
.
setKeyCounter
(
0
)
val
.
setDefaultValidityDuration
()
...
...
credinfo.go
View file @
b73b7df8
...
...
@@ -31,7 +31,6 @@ func NewCredentialInfo(ints []*big.Int, conf *Configuration) *CredentialInfo {
}
attrs
:=
NewAttributeListFromInts
(
ints
,
conf
)
id
:=
credtype
.
Identifier
()
issid
:=
id
.
IssuerIdentifier
()
return
&
CredentialInfo
{
...
...
descriptions.go
View file @
b73b7df8
...
...
@@ -77,6 +77,7 @@ func (ct *CredentialType) ContainsAttribute(ai AttributeTypeIdentifier) bool {
// AttributeDescription is a description of an attribute within a credential type.
type
AttributeDescription
struct
{
ID
string
`xml:"id,attr"`
Optional
string
`xml:"optional,attr"`
Name
TranslatedString
Description
TranslatedString
}
...
...
irmaclient/client.go
View file @
b73b7df8
...
...
@@ -594,7 +594,7 @@ func (client *Client) ConstructCredentials(msg []*gabi.IssueSignatureMessage, re
// we save none of them to fail the session cleanly
gabicreds
:=
[]
*
gabi
.
Credential
{}
for
i
,
sig
:=
range
msg
{
attrs
,
err
:=
request
.
Credentials
[
i
]
.
AttributeList
(
client
.
Configuration
)
attrs
,
err
:=
request
.
Credentials
[
i
]
.
AttributeList
(
client
.
Configuration
,
getMetadataVersion
(
request
.
GetVersion
())
)
if
err
!=
nil
{
return
err
}
...
...
irmaclient/logs.go
View file @
b73b7df8
...
...
@@ -54,7 +54,7 @@ func (session *session) createLogEntry(response interface{}) (*LogEntry, error)
entry
.
Received
=
map
[
irma
.
CredentialTypeIdentifier
][]
irma
.
TranslatedString
{}
}
for
_
,
req
:=
range
session
.
jwt
.
(
*
irma
.
IdentityProviderJwt
)
.
Request
.
Request
.
Credentials
{
list
,
err
:=
req
.
AttributeList
(
session
.
client
.
Configuration
)
list
,
err
:=
req
.
AttributeList
(
session
.
client
.
Configuration
,
getMetadataVersion
(
session
.
Version
)
)
if
err
!=
nil
{
continue
// TODO?
}
...
...
irmaclient/session.go
View file @
b73b7df8
...
...
@@ -50,10 +50,19 @@ type SessionDismisser interface {
Dismiss
()
}
// getMetadataVersion maps a chosen protocol version to a metadata version that
// the server will use.
func
getMetadataVersion
(
v
*
irma
.
ProtocolVersion
)
byte
{
if
v
.
Below
(
2
,
3
)
{
return
0x02
// no support for optional attributes
}
return
0x03
// current version
}
type
session
struct
{
Action
irma
.
Action
Handler
Handler
Version
irma
.
Version
Version
*
irma
.
Protocol
Version
choice
*
irma
.
DisclosureChoice
client
*
Client
...
...
@@ -73,24 +82,24 @@ var _ keyshareSessionHandler = (*session)(nil)
// Supported protocol versions. Minor version numbers should be reverse sorted.
var
supportedVersions
=
map
[
int
][]
int
{
2
:
{
2
,
1
},
2
:
{
3
,
2
,
1
},
}
func
calcVersion
(
qr
*
irma
.
Qr
)
(
string
,
error
)
{
func
calcVersion
(
qr
*
irma
.
Qr
)
(
*
irma
.
ProtocolVersion
,
error
)
{
// Parse range supported by server
var
minmajor
,
minminor
,
maxmajor
,
maxminor
int
var
err
error
if
minmajor
,
err
=
strconv
.
Atoi
(
string
(
qr
.
ProtocolVersion
[
0
]));
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
if
minminor
,
err
=
strconv
.
Atoi
(
string
(
qr
.
ProtocolVersion
[
2
]));
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
if
maxmajor
,
err
=
strconv
.
Atoi
(
string
(
qr
.
ProtocolMaxVersion
[
0
]));
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
if
maxminor
,
err
=
strconv
.
Atoi
(
string
(
qr
.
ProtocolMaxVersion
[
2
]));
err
!=
nil
{
return
""
,
err
return
nil
,
err
}
// Iterate supportedVersions in reverse sorted order (i.e. biggest major number first)
...
...
@@ -104,11 +113,11 @@ func calcVersion(qr *irma.Qr) (string, error) {
aboveMinimum
:=
major
>
minmajor
||
(
major
==
minmajor
&&
minor
>=
minminor
)
underMaximum
:=
major
<
maxmajor
||
(
major
==
maxmajor
&&
minor
<=
maxminor
)
if
aboveMinimum
&&
underMaximum
{
return
fmt
.
Sprintf
(
"%d.%d"
,
major
,
minor
),
nil
return
irma
.
NewVersion
(
major
,
minor
),
nil
}
}
}
return
""
,
fmt
.
Errorf
(
"No supported protocol version between %s and %s"
,
qr
.
ProtocolVersion
,
qr
.
ProtocolMaxVersion
)
return
nil
,
fmt
.
Errorf
(
"No supported protocol version between %s and %s"
,
qr
.
ProtocolVersion
,
qr
.
ProtocolMaxVersion
)
}
func
(
session
*
session
)
IsInteractive
()
bool
{
...
...
@@ -220,7 +229,7 @@ func (client *Client) NewManualSession(sigrequestJSONString string, handler Hand
Action
:
irma
.
ActionSigning
,
// TODO hardcoded for now
Handler
:
handler
,
client
:
client
,
Version
:
irma
.
Version
(
"2"
),
// TODO hardcoded for now
Version
:
irma
.
New
Version
(
2
,
0
),
// TODO hardcoded for now
irmaSession
:
sigrequest
,
}
...
...
@@ -268,7 +277,8 @@ func (client *Client) NewSession(qr *irma.Qr, handler Handler) SessionDismisser
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorProtocolVersionNotSupported
,
Err
:
err
})
return
nil
}
session
.
Version
=
irma
.
Version
(
version
)
session
.
Version
=
version
session
.
transport
.
SetHeader
(
"X-IRMA-ProtocolVersion"
,
version
.
String
())
// Check if the action is one of the supported types
switch
session
.
Action
{
...
...
@@ -315,6 +325,7 @@ func (session *session) start() {
session
.
irmaSession
=
session
.
jwt
.
IrmaSession
()
session
.
irmaSession
.
SetContext
(
session
.
info
.
Context
)
session
.
irmaSession
.
SetNonce
(
session
.
info
.
Nonce
)
session
.
irmaSession
.
SetVersion
(
session
.
Version
)
if
session
.
Action
==
irma
.
ActionIssuing
{
ir
:=
session
.
irmaSession
.
(
*
irma
.
IssuanceRequest
)
// Store which public keys the server will use
...
...
@@ -330,7 +341,7 @@ func (session *session) start() {
if
session
.
Action
==
irma
.
ActionIssuing
{
ir
:=
session
.
irmaSession
.
(
*
irma
.
IssuanceRequest
)
for
_
,
credreq
:=
range
ir
.
Credentials
{
info
,
err
:=
credreq
.
Info
(
session
.
client
.
Configuration
)
info
,
err
:=
credreq
.
Info
(
session
.
client
.
Configuration
,
getMetadataVersion
(
session
.
Version
)
)
if
err
!=
nil
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorUnknownCredentialType
,
Err
:
err
})
return
...
...
irmaclient/session_test.go
View file @
b73b7df8
...
...
@@ -137,6 +137,27 @@ func getIssuanceRequest(defaultValidity bool) *irma.IssuanceRequest {
}
}
func
getNameIssuanceRequest
()
*
irma
.
IssuanceRequest
{
expiry
:=
irma
.
Timestamp
(
irma
.
NewMetadataAttribute
(
0
)
.
Expiry
())
credid
:=
irma
.
NewCredentialTypeIdentifier
(
"irma-demo.MijnOverheid.fullName"
)
req
:=
&
irma
.
IssuanceRequest
{
Credentials
:
[]
*
irma
.
CredentialRequest
{
{
Validity
:
&
expiry
,
CredentialTypeID
:
&
credid
,
Attributes
:
map
[
string
]
string
{
"firstnames"
:
"Johan Pieter"
,
"firstname"
:
"Johan"
,
"familyname"
:
"Stuivezand"
,
},
},
},
}
return
req
}
func
getIssuanceJwt
(
name
string
,
defaultValidity
bool
)
interface
{}
{
return
irma
.
NewIdentityProviderJwt
(
name
,
getIssuanceRequest
(
defaultValidity
))
}
...
...
@@ -191,6 +212,26 @@ func TestDefaultCredentialValidity(t *testing.T) {
sessionHelper
(
t
,
jwtcontents
,
"issue"
,
client
)
}
func
TestIssuanceOptionalEmptyAttributes
(
t
*
testing
.
T
)
{
req
:=
getNameIssuanceRequest
()
jwt
:=
irma
.
NewIdentityProviderJwt
(
"testip"
,
req
)
sessionHelper
(
t
,
jwt
,
"issue"
,
nil
)
}
func
TestIssuanceOptionalZeroLengthAttributes
(
t
*
testing
.
T
)
{
req
:=
getNameIssuanceRequest
()
req
.
Credentials
[
0
]
.
Attributes
[
"prefix"
]
=
""
jwt
:=
irma
.
NewIdentityProviderJwt
(
"testip"
,
req
)
sessionHelper
(
t
,
jwt
,
"issue"
,
nil
)
}
func
TestIssuanceOptionalSetAttributes
(
t
*
testing
.
T
)
{
req
:=
getNameIssuanceRequest
()
req
.
Credentials
[
0
]
.
Attributes
[
"prefix"
]
=
"van"
jwt
:=
irma
.
NewIdentityProviderJwt
(
"testip"
,
req
)
sessionHelper
(
t
,
jwt
,
"issue"
,
nil
)
}
func
TestLargeAttribute
(
t
*
testing
.
T
)
{
client
:=
parseStorage
(
t
)
require
.
NoError
(
t
,
client
.
RemoveAllCredentials
())
...
...
@@ -268,7 +309,7 @@ func TestKeyshareEnrollmentAndSessions(t *testing.T) {
enrollKeyshareServer
(
t
,
client
)
id
:=
irma
.
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
)
expiry
:=
irma
.
Timestamp
(
irma
.
NewMetadataAttribute
()
.
Expiry
())
expiry
:=
irma
.
Timestamp
(
irma
.
NewMetadataAttribute
(
0
)
.
Expiry
())
credid
:=
irma
.
NewCredentialTypeIdentifier
(
"test.test.mijnirma"
)
jwt
:=
getCombinedJwt
(
"testip"
,
id
)
jwt
.
(
*
irma
.
IdentityProviderJwt
)
.
Request
.
Request
.
Credentials
=
append
(
...
...
@@ -311,7 +352,7 @@ func TestKeyshareSessions(t *testing.T) {
client
:=
parseStorage
(
t
)
id
:=
irma
.
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
)
expiry
:=
irma
.
Timestamp
(
irma
.
NewMetadataAttribute
()
.
Expiry
())
expiry
:=
irma
.
Timestamp
(
irma
.
NewMetadataAttribute
(
0
)
.
Expiry
())
credid
:=
irma
.
NewCredentialTypeIdentifier
(
"test.test.mijnirma"
)
jwt
:=
getCombinedJwt
(
"testip"
,
id
)
jwt
.
(
*
irma
.
IdentityProviderJwt
)
.
Request
.
Request
.
Credentials
=
append
(
...
...
irmago_test.go
View file @
b73b7df8
...
...
@@ -166,7 +166,7 @@ func TestAttributeDisjunctionMarshaling(t *testing.T) {
}
func
TestMetadataAttribute
(
t
*
testing
.
T
)
{
metadata
:=
NewMetadataAttribute
()
metadata
:=
NewMetadataAttribute
(
0x02
)
if
metadata
.
Version
()
!=
0x02
{
t
.
Errorf
(
"Unexpected metadata version: %d"
,
metadata
.
Version
())
}
...
...
messages.go
View file @
b73b7df8
...
...
@@ -16,8 +16,27 @@ import (
// Status encodes the status of an IRMA session (e.g., connected).
type
Status
string
// Version encodes the IRMA protocol version of an IRMA session.
type
Version
string
// ProtocolVersion encodes the IRMA protocol version of an IRMA session.
type
ProtocolVersion
struct
{
major
int
minor
int
}
func
NewVersion
(
major
,
minor
int
)
*
ProtocolVersion
{
return
&
ProtocolVersion
{
major
,
minor
}
}
func
(
v
*
ProtocolVersion
)
String
()
string
{
return
fmt
.
Sprintf
(
"%d.%d"
,
v
.
major
,
v
.
minor
)
}
// Returns true if v is below the given version.
func
(
v
*
ProtocolVersion
)
Below
(
major
,
minor
int
)
bool
{
if
v
.
major
<
major
{
return
true
}
return
v
.
major
==
major
&&
v
.
minor
<
minor
}
// Action encodes the session type of an IRMA session (e.g., disclosing).
type
Action
string
...
...
requests.go
View file @
b73b7df8
...
...
@@ -20,6 +20,8 @@ type SessionRequest struct {
Choice
*
DisclosureChoice
`json:"-"`
Ids
*
IrmaIdentifierSet
`json:"-"`
version
*
ProtocolVersion
}
func
(
sr
*
SessionRequest
)
SetCandidates
(
candidates
[][]
*
AttributeIdentifier
)
{
...
...
@@ -36,6 +38,16 @@ func (sr *SessionRequest) SetDisclosureChoice(choice *DisclosureChoice) {
sr
.
Choice
=
choice
}
// ...
func
(
sr
*
SessionRequest
)
SetVersion
(
v
*
ProtocolVersion
)
{
sr
.
version
=
v
}
// ...
func
(
sr
*
SessionRequest
)
GetVersion
()
*
ProtocolVersion
{
return
sr
.
version
}
// A DisclosureRequest is a request to disclose certain attributes.
type
DisclosureRequest
struct
{
SessionRequest
...
...
@@ -113,6 +125,7 @@ type IrmaSession interface {
SetNonce
(
*
big
.
Int
)
GetContext
()
*
big
.
Int
SetContext
(
*
big
.
Int
)
SetVersion
(
*
ProtocolVersion
)
ToDisclose
()
AttributeDisjunctionList
DisclosureChoice
()
*
DisclosureChoice
SetDisclosureChoice
(
choice
*
DisclosureChoice
)
...
...
@@ -123,8 +136,8 @@ type IrmaSession interface {
// Timestamp is a time.Time that marshals to Unix timestamps.
type
Timestamp
time
.
Time
func
(
cr
*
CredentialRequest
)
Info
(
conf
*
Configuration
)
(
*
CredentialInfo
,
error
)
{
list
,
err
:=
cr
.
AttributeList
(
conf
)
func
(
cr
*
CredentialRequest
)
Info
(
conf
*
Configuration
,
metadataVersion
byte
)
(
*
CredentialInfo
,
error
)
{
list
,
err
:=
cr
.
AttributeList
(
conf
,
metadataVersion
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -132,8 +145,8 @@ func (cr *CredentialRequest) Info(conf *Configuration) (*CredentialInfo, error)
}
// AttributeList returns the list of attributes from this credential request.
func
(
cr
*
CredentialRequest
)
AttributeList
(
conf
*
Configuration
)
(
*
AttributeList
,
error
)
{
meta
:=
NewMetadataAttribute
()
func
(
cr
*
CredentialRequest
)
AttributeList
(
conf
*
Configuration
,
metadataVersion
byte
)
(
*
AttributeList
,
error
)
{
meta
:=
NewMetadataAttribute
(
metadataVersion
)
meta
.
setKeyCounter
(
cr
.
KeyCounter
)
meta
.
setCredentialTypeIdentifier
(
cr
.
CredentialTypeID
.
String
())
meta
.
setSigningDate
()
...
...
@@ -142,21 +155,41 @@ func (cr *CredentialRequest) AttributeList(conf *Configuration) (*AttributeList,
return
nil
,
err
}
attrs
:=
make
([]
*
big
.
Int
,
len
(
cr
.
Attributes
)
+
1
,
len
(
cr
.
Attributes
)
+
1
)
credtype
:=
conf
.
CredentialTypes
[
*
cr
.
CredentialTypeID
]
if
credtype
==
nil
{
return
nil
,
errors
.
New
(
"Unknown credential type"
)
}
if
len
(
credtype
.
Attributes
)
!=
len
(
cr
.
Attributes
)
{
return
nil
,
errors
.
New
(
"Received unexpected amount of attributes"
)
// Check that there are no attributes in the credential request that aren't
// in the credential descriptor.
for
crName
:=
range
cr
.
Attributes
{
found
:=
false
for
_
,
ad
:=
range
credtype
.
Attributes
{
if
ad
.
ID
==
crName
{
found
=
true
break
}
}
if
!
found
{
return
nil
,
errors
.
New
(
"Unknown CR attribute"
)
}
}
attrs
:=
make
([]
*
big
.
Int
,
len
(
credtype
.
Attributes
)
+
1
)
attrs
[
0
]
=
meta
.
Int
for
i
,
attrtype
:=
range
credtype
.
Attributes
{
attrs
[
i
+
1
]
=
new
(
big
.
Int
)
if
str
,
present
:=
cr
.
Attributes
[
attrtype
.
ID
];
present
{
attrs
[
i
+
1
]
=
new
(
big
.
Int
)
.
SetBytes
([]
byte
(
str
))
// Set attribute to str << 1 + 1
attrs
[
i
+
1
]
.
SetBytes
([]
byte
(
str
))
if
meta
.
Version
()
>=
0x03
{
attrs
[
i
+
1
]
.
Lsh
(
attrs
[
i
+
1
],
1
)
// attr <<= 1
attrs
[
i
+
1
]
.
Add
(
attrs
[
i
+
1
],
big
.
NewInt
(
1
))
// attr += 1
}
}
else
{
return
nil
,
errors
.
New
(
"Unknown attribute"
)
if
(
attrtype
.
Optional
!=
"true"
)
{
return
nil
,
errors
.
New
(
"Required attribute not provided"
)
}
}
}
...
...
testdata/irma_configuration/irma-demo/MijnOverheid/Issues/fullName/description.xml
0 → 100644
View file @
b73b7df8
<IssueSpecification
version=
"4"
>
<Name>
<en>
Name
</en>
<nl>
Naam
</nl>
</Name>
<ShortName>
<en>
Name
</en>
<nl>
Naam
</nl>
</ShortName>
<SchemeManager>
irma-demo
</SchemeManager>
<IssuerID>
MijnOverheid
</IssuerID>
<CredentialID>
fullName
</CredentialID>
<Description>
<en>
Your full name, as it is known to the government
</en>
<nl>
Uw volledige naam, zoals bekend bij de overheid
</nl>
</Description>
<ShouldBeSingleton>
true
</ShouldBeSingleton>
<Attributes>
<Attribute
id=
"firstnames"
>
<Name>
<en>
First names
</en>
<nl>
Voornamen
</nl>
</Name>
<Description>
<en>
All of your first names
</en>
<nl>
Al uw voornamen
</nl>
</Description>
</Attribute>
<Attribute
id=
"firstname"
>
<Name>
<en>
First name
</en>
<nl>
Voornaam
</nl>
</Name>
<Description>
<en>
Your first name
</en>
<nl>
Uw voornaam
</nl>
</Description>
</Attribute>
<Attribute
id=
"familyname"
>
<Name>
<en>
Family name
</en>
<nl>
Achternaam
</nl>
</Name>
<Description>
<en>
Your family name
</en>
<nl>
Uw achternaam
</nl>
</Description>
</Attribute>
<Attribute
id=
"prefix"
optional=
"true"
>
<Name>
<en>
Prefix
</en>
<nl>
Tussenvoegsel
</nl>
</Name>
<Description>
<en>
Family name prefix
</en>
<nl>
Tussenvoegsel van uw achternaam
</nl>
</Description>
</Attribute>
</Attributes>
</IssueSpecification>
testdata/irma_configuration/irma-demo/index
View file @
b73b7df8
230ce9f61beca5f52a6a241592c290baff9bae1066385e4b9bcf3a030f4a3b47 irma-demo/MijnOverheid/Issues/fullName/description.xml
5cef2de223075ea192407d66de274f8bc7104ab3537b455df14aca306b4809f7 irma-demo/MijnOverheid/Issues/root/description.xml
3571e30777cdf5b97acbb0820f1b69983d2dc2b6bae91c8fb67cfc79ef4e2543 irma-demo/MijnOverheid/PublicKeys/0.xml
115bd71b738cd2ba10e832559fc5d35ee8222f4049a0fc10fc18d0853c4aa4d9 irma-demo/MijnOverheid/PublicKeys/1.xml
...
...
testdata/irma_configuration/irma-demo/index.sig
View file @
b73b7df8
No preview for this file type
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