Skip to content
GitLab
Menu
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
e2a426af
Commit
e2a426af
authored
Nov 18, 2019
by
Sietse Ringers
Browse files
feat: when revocation state cannot be updated, report to verifier but continue session
parent
67169d8a
Changes
3
Hide whitespace changes
Inline
Side-by-side
requests.go
View file @
e2a426af
...
...
@@ -302,7 +302,7 @@ func (ar *AttributeRequest) Satisfy(attr AttributeTypeIdentifier, val *string) b
// Satisfy returns if each of the attributes specified by proofs and indices satisfies each of
// the contained AttributeRequests's. If so it also returns a list of the disclosed attribute values.
func
(
c
AttributeCon
)
Satisfy
(
proofs
gabi
.
ProofList
,
indices
[]
*
DisclosedAttributeIndex
,
conf
*
Configuration
)
(
bool
,
[]
*
DisclosedAttribute
,
error
)
{
func
(
c
AttributeCon
)
Satisfy
(
proofs
gabi
.
ProofList
,
indices
[]
*
DisclosedAttributeIndex
,
revocation
map
[
int
]
*
time
.
Time
,
conf
*
Configuration
)
(
bool
,
[]
*
DisclosedAttribute
,
error
)
{
if
len
(
indices
)
<
len
(
c
)
{
return
false
,
nil
,
nil
}
...
...
@@ -313,7 +313,7 @@ func (c AttributeCon) Satisfy(proofs gabi.ProofList, indices []*DisclosedAttribu
for
j
:=
range
c
{
index
:=
indices
[
j
]
attr
,
val
,
err
:=
extractAttribute
(
proofs
,
index
,
conf
)
attr
,
val
,
err
:=
extractAttribute
(
proofs
,
index
,
revocation
[
index
.
CredentialIndex
],
conf
)
if
err
!=
nil
{
return
false
,
nil
,
err
}
...
...
@@ -340,9 +340,9 @@ func (dc AttributeDisCon) Validate() error {
// Satisfy returns true if the attributes specified by proofs and indices satisfies any one of the
// contained AttributeCon's. If so it also returns a list of the disclosed attribute values.
func
(
dc
AttributeDisCon
)
Satisfy
(
proofs
gabi
.
ProofList
,
indices
[]
*
DisclosedAttributeIndex
,
conf
*
Configuration
)
(
bool
,
[]
*
DisclosedAttribute
,
error
)
{
func
(
dc
AttributeDisCon
)
Satisfy
(
proofs
gabi
.
ProofList
,
indices
[]
*
DisclosedAttributeIndex
,
revocation
map
[
int
]
*
time
.
Time
,
conf
*
Configuration
)
(
bool
,
[]
*
DisclosedAttribute
,
error
)
{
for
_
,
con
:=
range
dc
{
satisfied
,
attrs
,
err
:=
con
.
Satisfy
(
proofs
,
indices
,
conf
)
satisfied
,
attrs
,
err
:=
con
.
Satisfy
(
proofs
,
indices
,
revocation
,
conf
)
if
satisfied
||
err
!=
nil
{
return
true
,
attrs
,
err
}
...
...
@@ -371,7 +371,7 @@ func (cdc AttributeConDisCon) Validate(conf *Configuration) error {
// Satisfy returns true if each of the contained AttributeDisCon is satisfied by the specified disclosure.
// If so it also returns the disclosed attributes.
func
(
cdc
AttributeConDisCon
)
Satisfy
(
disclosure
*
Disclosure
,
conf
*
Configuration
)
(
bool
,
[][]
*
DisclosedAttribute
,
error
)
{
func
(
cdc
AttributeConDisCon
)
Satisfy
(
disclosure
*
Disclosure
,
revocation
map
[
int
]
*
time
.
Time
,
conf
*
Configuration
)
(
bool
,
[][]
*
DisclosedAttribute
,
error
)
{
if
len
(
disclosure
.
Indices
)
<
len
(
cdc
)
{
return
false
,
nil
,
nil
}
...
...
@@ -379,7 +379,7 @@ func (cdc AttributeConDisCon) Satisfy(disclosure *Disclosure, conf *Configuratio
complete
:=
true
for
i
,
discon
:=
range
cdc
{
satisfied
,
attrs
,
err
:=
discon
.
Satisfy
(
disclosure
.
Proofs
,
disclosure
.
Indices
[
i
],
conf
)
satisfied
,
attrs
,
err
:=
discon
.
Satisfy
(
disclosure
.
Proofs
,
disclosure
.
Indices
[
i
],
revocation
,
conf
)
if
err
!=
nil
{
return
false
,
nil
,
err
}
...
...
revocation.go
View file @
e2a426af
...
...
@@ -42,7 +42,11 @@ type (
RevocationSetting
struct
{
Mode
RevocationMode
`json:"mode"`
PostURLs
[]
string
`json:"post_urls" mapstructure:"post_urls"`
updated
time
.
Time
// set to now whenever a new revocation record is received, or when the RA indicates
// there are no new records. Thus it specifies up to what time our nonrevocation
// guarantees lasts.
updated
time
.
Time
}
// RevocationMode specifies for a given credential type what revocation operations are
...
...
@@ -97,6 +101,12 @@ const (
// revocationUpdateCount specifies how many revocation records are attached to session requests
// for the client to update its revocation state.
revocationUpdateCount
=
5
// revocationMaxAccumulatorAge is the default maximum for the 'accumulator age', which we
// define to be the amount of time since the last confirmation from the RA that the latest
// accumulator that we know is still the latest one: clients should prove nonrevocation
// against a 'younger' accumulator.
revocationMaxAccumulatorAge
=
5
*
time
.
Minute
)
// Revocation record methods
...
...
@@ -340,11 +350,19 @@ func (rs *RevocationStorage) UpdateDB(typ CredentialTypeIdentifier) error {
if
err
!=
nil
{
return
err
}
return
rs
.
AddRevocationRecords
(
records
)
if
err
=
rs
.
AddRevocationRecords
(
records
);
err
!=
nil
{
return
err
}
// bump updated even if no new records were added
rs
.
getSettings
(
typ
)
.
updated
=
time
.
Now
()
return
nil
}
func
(
rs
*
RevocationStorage
)
UpdateIfOld
(
typ
CredentialTypeIdentifier
)
error
{
if
rs
.
getSettings
(
typ
)
.
updated
.
Before
(
time
.
Now
()
.
Add
(
-
5
*
time
.
Minute
))
{
// update 10 seconds before the maximum, to stay below it
if
rs
.
getSettings
(
typ
)
.
updated
.
Before
(
time
.
Now
()
.
Add
(
-
revocationMaxAccumulatorAge
+
10
*
time
.
Second
))
{
if
err
:=
rs
.
UpdateDB
(
typ
);
err
!=
nil
{
return
err
}
...
...
@@ -440,7 +458,18 @@ func (rs *RevocationStorage) SetRevocationRecords(b *BaseRequest) error {
b
.
RevocationUpdates
=
make
(
map
[
CredentialTypeIdentifier
][]
*
RevocationRecord
,
len
(
b
.
Revocation
))
for
_
,
credid
:=
range
b
.
Revocation
{
if
err
=
rs
.
UpdateIfOld
(
credid
);
err
!=
nil
{
return
err
updated
:=
rs
.
getSettings
(
credid
)
.
updated
if
!
updated
.
IsZero
()
{
Logger
.
Warnf
(
"failed to fetch revocation updates for %s, nonrevocation is guaranteed only until %s ago:"
,
credid
,
time
.
Now
()
.
Sub
(
updated
)
.
String
())
Logger
.
Warn
(
err
)
}
else
{
Logger
.
Errorf
(
"revocation is disabled for %s: failed to fetch revocation updates and none are known locally"
,
credid
)
Logger
.
Warn
(
err
)
// We can offer no nonrevocation guarantees at all while the requestor explicitly
// asked for it; fail the session by returning an error
return
err
}
}
b
.
RevocationUpdates
[
credid
],
err
=
rs
.
LatestRevocationRecords
(
credid
,
revocationUpdateCount
)
if
err
!=
nil
{
...
...
verify.go
View file @
e2a426af
...
...
@@ -31,11 +31,12 @@ const (
// DisclosedAttribute represents a disclosed attribute.
type
DisclosedAttribute
struct
{
RawValue
*
string
`json:"rawvalue"`
Value
TranslatedString
`json:"value"`
// Value of the disclosed attribute
Identifier
AttributeTypeIdentifier
`json:"id"`
Status
AttributeProofStatus
`json:"status"`
IssuanceTime
Timestamp
`json:"issuancetime"`
RawValue
*
string
`json:"rawvalue"`
Value
TranslatedString
`json:"value"`
// Value of the disclosed attribute
Identifier
AttributeTypeIdentifier
`json:"id"`
Status
AttributeProofStatus
`json:"status"`
IssuanceTime
Timestamp
`json:"issuancetime"`
NotRevokedBefore
*
Timestamp
`json:"notrevokedbefore,omitempty"`
}
// ProofList is a gabi.ProofList with some extra methods.
...
...
@@ -89,7 +90,7 @@ func (pl ProofList) Expired(configuration *Configuration, t *time.Time) bool {
return
false
}
func
extractAttribute
(
pl
gabi
.
ProofList
,
index
*
DisclosedAttributeIndex
,
conf
*
Configuration
)
(
*
DisclosedAttribute
,
*
string
,
error
)
{
func
extractAttribute
(
pl
gabi
.
ProofList
,
index
*
DisclosedAttributeIndex
,
notrevoked
*
time
.
Time
,
conf
*
Configuration
)
(
*
DisclosedAttribute
,
*
string
,
error
)
{
if
len
(
pl
)
<
index
.
CredentialIndex
{
return
nil
,
nil
,
errors
.
New
(
"Credential index out of range"
)
}
...
...
@@ -101,7 +102,7 @@ func extractAttribute(pl gabi.ProofList, index *DisclosedAttributeIndex, conf *C
}
metadata
:=
MetadataFromInt
(
proofd
.
ADisclosed
[
1
],
conf
)
// index 1 is metadata attribute
return
parseAttribute
(
index
.
AttributeIndex
,
metadata
,
proofd
.
ADisclosed
[
index
.
AttributeIndex
])
return
parseAttribute
(
index
.
AttributeIndex
,
metadata
,
proofd
.
ADisclosed
[
index
.
AttributeIndex
]
,
notrevoked
)
}
// VerifyProofs verifies the proofs cryptographically.
...
...
@@ -111,22 +112,22 @@ func (pl ProofList) VerifyProofs(
publickeys
[]
*
gabi
.
PublicKey
,
revRecords
map
[
CredentialTypeIdentifier
][]
*
RevocationRecord
,
isSig
bool
,
)
(
bool
,
error
)
{
)
(
bool
,
map
[
int
]
*
time
.
Time
,
error
)
{
// Empty proof lists are allowed (if consistent with the session request, which is checked elsewhere)
if
len
(
pl
)
==
0
{
return
true
,
nil
return
true
,
nil
,
nil
}
if
publickeys
==
nil
{
var
err
error
publickeys
,
err
=
pl
.
ExtractPublicKeys
(
configuration
)
if
err
!=
nil
{
return
false
,
err
return
false
,
nil
,
err
}
}
if
len
(
pl
)
!=
len
(
publickeys
)
{
return
false
,
errors
.
New
(
"Insufficient public keys to verify the proofs"
)
return
false
,
nil
,
errors
.
New
(
"Insufficient public keys to verify the proofs"
)
}
// Compute slice to inform gabi of which proofs should be verified to share the same secret key
...
...
@@ -141,28 +142,29 @@ func (pl ProofList) VerifyProofs(
}
if
!
gabi
.
ProofList
(
pl
)
.
Verify
(
publickeys
,
context
,
nonce
,
isSig
,
keyshareServers
)
{
return
false
,
nil
return
false
,
nil
,
nil
}
// Perform per-proof verifications for each proof:
// - verify that any singleton credential occurs at most once in the prooflist
// - verify that all required nonrevocation proofs are present
singletons
:=
map
[
CredentialTypeIdentifier
]
bool
{}
for
_
,
proof
:=
range
pl
{
revocation
:=
map
[
int
]
*
time
.
Time
{}
// per proof, store up to what time it is known to be not revoked
for
i
,
proof
:=
range
pl
{
proofd
,
ok
:=
proof
.
(
*
gabi
.
ProofD
)
if
!
ok
{
continue
}
typ
:=
MetadataFromInt
(
proofd
.
ADisclosed
[
1
],
configuration
)
.
CredentialType
()
if
typ
==
nil
{
return
false
,
errors
.
New
(
"Received unknown credential type"
)
return
false
,
nil
,
errors
.
New
(
"Received unknown credential type"
)
}
id
:=
typ
.
Identifier
()
if
typ
.
IsSingleton
{
if
!
singletons
[
id
]
{
// Seen for the first time
singletons
[
id
]
=
true
}
else
{
// Seen for the second time
return
false
,
nil
return
false
,
nil
,
nil
}
}
...
...
@@ -173,17 +175,24 @@ func (pl ProofList) VerifyProofs(
// OR a newer one included in the proofs itself.
r
:=
revRecords
[
id
]
if
len
(
r
)
==
0
{
// no nonrevocation proof was requested for this credential
return
true
,
nil
return
true
,
nil
,
nil
}
if
!
proofd
.
HasNonRevocationProof
()
{
return
false
,
nil
return
false
,
nil
,
nil
}
if
proofd
.
NonRevocationProof
.
Accumulator
.
Index
<
r
[
len
(
r
)
-
1
]
.
EndIndex
{
return
false
,
errors
.
New
(
"nonrevocation proof used wrong accumulator"
)
ours
,
theirs
:=
proofd
.
NonRevocationProof
.
Accumulator
.
Index
,
r
[
len
(
r
)
-
1
]
.
EndIndex
if
ours
<
theirs
{
return
false
,
nil
,
errors
.
New
(
"nonrevocation proof used wrong accumulator"
)
}
if
ours
==
theirs
{
accAge
:=
configuration
.
RevocationStorage
.
getSettings
(
id
)
.
updated
if
time
.
Now
()
.
Sub
(
accAge
)
>
revocationMaxAccumulatorAge
{
revocation
[
i
]
=
&
accAge
}
}
}
return
true
,
nil
return
true
,
revocation
,
nil
}
func
(
d
*
Disclosure
)
extraIndices
(
condiscon
AttributeConDisCon
)
[]
*
DisclosedAttributeIndex
{
...
...
@@ -226,8 +235,8 @@ func (d *Disclosure) extraIndices(condiscon AttributeConDisCon) []*DisclosedAttr
// is included, then the first attributes in the returned slice match with the disjunction list in
// the disjunction list. The first return parameter of this function indicates whether or not all
// disjunctions (if present) are satisfied.
func
(
d
*
Disclosure
)
DisclosedAttributes
(
configuration
*
Configuration
,
condiscon
AttributeConDisCon
)
(
bool
,
[][]
*
DisclosedAttribute
,
error
)
{
complete
,
list
,
err
:=
condiscon
.
Satisfy
(
d
,
configuration
)
func
(
d
*
Disclosure
)
DisclosedAttributes
(
configuration
*
Configuration
,
condiscon
AttributeConDisCon
,
revocation
map
[
int
]
*
time
.
Time
)
(
bool
,
[][]
*
DisclosedAttribute
,
error
)
{
complete
,
list
,
err
:=
condiscon
.
Satisfy
(
d
,
revocation
,
configuration
)
if
err
!=
nil
{
return
false
,
nil
,
err
}
...
...
@@ -235,7 +244,7 @@ func (d *Disclosure) DisclosedAttributes(configuration *Configuration, condiscon
var
extra
[]
*
DisclosedAttribute
indices
:=
d
.
extraIndices
(
condiscon
)
for
_
,
index
:=
range
indices
{
attr
,
_
,
err
:=
extractAttribute
(
d
.
Proofs
,
index
,
configuration
)
attr
,
_
,
err
:=
extractAttribute
(
d
.
Proofs
,
index
,
revocation
[
index
.
CredentialIndex
],
configuration
)
if
err
!=
nil
{
return
false
,
nil
,
err
}
...
...
@@ -249,7 +258,7 @@ func (d *Disclosure) DisclosedAttributes(configuration *Configuration, condiscon
return
complete
,
list
,
nil
}
func
parseAttribute
(
index
int
,
metadata
*
MetadataAttribute
,
attr
*
big
.
Int
)
(
*
DisclosedAttribute
,
*
string
,
error
)
{
func
parseAttribute
(
index
int
,
metadata
*
MetadataAttribute
,
attr
*
big
.
Int
,
notrevoked
*
time
.
Time
)
(
*
DisclosedAttribute
,
*
string
,
error
)
{
var
attrid
AttributeTypeIdentifier
var
attrval
*
string
credtype
:=
metadata
.
CredentialType
()
...
...
@@ -269,11 +278,12 @@ func parseAttribute(index int, metadata *MetadataAttribute, attr *big.Int) (*Dis
status
=
AttributeProofStatusNull
}
return
&
DisclosedAttribute
{
Identifier
:
attrid
,
RawValue
:
attrval
,
Value
:
NewTranslatedString
(
attrval
),
Status
:
status
,
IssuanceTime
:
Timestamp
(
metadata
.
SigningDate
()),
Identifier
:
attrid
,
RawValue
:
attrval
,
Value
:
NewTranslatedString
(
attrval
),
Status
:
status
,
IssuanceTime
:
Timestamp
(
metadata
.
SigningDate
()),
NotRevokedBefore
:
(
*
Timestamp
)(
notrevoked
),
},
attrval
,
nil
}
...
...
@@ -293,13 +303,13 @@ func (d *Disclosure) VerifyAgainstRequest(
}
// Cryptographically verify all included IRMA proofs
valid
,
err
:=
ProofList
(
d
.
Proofs
)
.
VerifyProofs
(
configuration
,
context
,
nonce
,
publickeys
,
revRecords
,
issig
)
valid
,
revocation
,
err
:=
ProofList
(
d
.
Proofs
)
.
VerifyProofs
(
configuration
,
context
,
nonce
,
publickeys
,
revRecords
,
issig
)
if
!
valid
||
err
!=
nil
{
return
nil
,
ProofStatusInvalid
,
err
}
// Next extract the contained attributes from the proofs, and match them to the signature request if present
allmatched
,
list
,
err
:=
d
.
DisclosedAttributes
(
configuration
,
required
)
allmatched
,
list
,
err
:=
d
.
DisclosedAttributes
(
configuration
,
required
,
revocation
)
if
err
!=
nil
{
return
nil
,
ProofStatusInvalid
,
err
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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