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
d5720003
Commit
d5720003
authored
Oct 17, 2018
by
Sietse Ringers
Browse files
Include new message in disclosure proofs for disclosure choices
parent
2e8a4bd7
Changes
7
Hide whitespace changes
Inline
Side-by-side
internal/sessiontest/handlers_test.go
View file @
d5720003
...
...
@@ -188,10 +188,9 @@ func (th *ManualTestHandler) RequestSchemeManagerPermission(manager *irma.Scheme
th
.
Failure
(
&
irma
.
SessionError
{
Err
:
errors
.
New
(
"Unexpected session type"
)})
}
func
(
th
*
ManualTestHandler
)
RequestVerificationPermission
(
request
irma
.
DisclosureRequest
,
verifierName
string
,
ph
irmaclient
.
PermissionHandler
)
{
var
attributes
[]
*
irma
.
AttributeIdentifier
var
choice
irma
.
DisclosureChoice
for
_
,
cand
:=
range
request
.
Candidates
{
a
ttributes
=
append
(
a
ttributes
,
cand
[
0
])
choice
.
A
ttributes
=
append
(
choice
.
A
ttributes
,
cand
[
0
])
}
c
:=
irma
.
DisclosureChoice
{
attributes
}
ph
(
true
,
&
c
)
ph
(
true
,
&
choice
)
}
irma_signature.go
View file @
d5720003
...
...
@@ -14,11 +14,12 @@ import (
// SignedMessage is a message signed with an attribute-based signature
// The 'realnonce' will be calculated as: SigRequest.GetNonce() = ASN1(nonce, SHA256(message), timestampSignature)
type
SignedMessage
struct
{
Signature
gabi
.
ProofList
`json:"signature"`
Nonce
*
big
.
Int
`json:"nonce"`
Context
*
big
.
Int
`json:"context"`
Message
string
`json:"message"`
Timestamp
*
atum
.
Timestamp
`json:"timestamp"`
Signature
gabi
.
ProofList
`json:"signature"`
Indices
DisclosedAttributeIndices
`json:"indices"`
Nonce
*
big
.
Int
`json:"nonce"`
Context
*
big
.
Int
`json:"context"`
Message
string
`json:"message"`
Timestamp
*
atum
.
Timestamp
`json:"timestamp"`
}
func
(
sm
*
SignedMessage
)
GetNonce
()
*
big
.
Int
{
...
...
@@ -31,6 +32,13 @@ func (sm *SignedMessage) MatchesNonceAndContext(request *SignatureRequest) bool
sm
.
GetNonce
()
.
Cmp
(
request
.
GetNonce
())
==
0
}
func
(
sm
*
SignedMessage
)
Disclosure
()
*
Disclosure
{
return
&
Disclosure
{
Proofs
:
sm
.
Signature
,
Indices
:
sm
.
Indices
,
}
}
// ASN1ConvertSignatureNonce computes the nonce that is used in the creation of the attribute-based signature:
// nonce = SHA256(serverNonce, SHA256(message), timestampSignature)
// where serverNonce is the nonce sent by the signature requestor.
...
...
irmaclient/client.go
View file @
d5720003
...
...
@@ -496,13 +496,16 @@ func (client *Client) CheckSatisfiability(
return
candidates
,
missing
}
func
(
client
*
Client
)
groupCredentials
(
choice
*
irma
.
DisclosureChoice
)
(
map
[
irma
.
CredentialIdentifier
][]
int
,
error
)
{
func
(
client
*
Client
)
groupCredentials
(
choice
*
irma
.
DisclosureChoice
,
disjunctions
irma
.
AttributeDisjunctionList
)
(
map
[
irma
.
CredentialIdentifier
][]
int
,
irma
.
DisclosedAttributeIndices
,
error
,
)
{
grouped
:=
make
(
map
[
irma
.
CredentialIdentifier
][]
int
)
if
choice
==
nil
||
choice
.
Attributes
==
nil
{
return
grouped
,
nil
return
grouped
,
irma
.
DisclosedAttributeIndices
{},
nil
}
for
_
,
attribute
:=
range
choice
.
Attributes
{
attributeIndices
:=
make
(
irma
.
DisclosedAttributeIndices
,
len
(
choice
.
Attributes
))
for
i
,
attribute
:=
range
choice
.
Attributes
{
identifier
:=
attribute
.
Type
ici
:=
attribute
.
CredentialIdentifier
()
...
...
@@ -519,7 +522,11 @@ func (client *Client) groupCredentials(choice *irma.DisclosureChoice) (map[irma.
}
index
,
err
:=
client
.
Configuration
.
CredentialTypes
[
identifier
.
CredentialTypeIdentifier
()]
.
IndexOf
(
identifier
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
attributeIndices
[
i
]
=
[]
*
irma
.
DisclosedAttributeIndex
{
{
AttributeIndex
:
index
+
2
,
Identifier
:
ici
},
}
// These indices will be used in the []*big.Int at gabi.credential.Attributes,
...
...
@@ -527,23 +534,26 @@ func (client *Client) groupCredentials(choice *irma.DisclosureChoice) (map[irma.
grouped
[
ici
]
=
append
(
grouped
[
ici
],
index
+
2
)
}
return
grouped
,
nil
return
grouped
,
attributeIndices
,
nil
}
// ProofBuilders constructs a list of proof builders for the specified attribute choice.
func
(
client
*
Client
)
ProofBuilders
(
choice
*
irma
.
DisclosureChoice
,
request
irma
.
SessionRequest
,
issig
bool
)
(
gabi
.
ProofBuilderList
,
error
)
{
todisclose
,
err
:=
client
.
groupCredentials
(
choice
)
func
(
client
*
Client
)
ProofBuilders
(
choice
*
irma
.
DisclosureChoice
,
request
irma
.
SessionRequest
,
issig
bool
,
)
(
gabi
.
ProofBuilderList
,
irma
.
DisclosedAttributeIndices
,
error
)
{
todisclose
,
disjunctionChoices
,
err
:=
client
.
groupCredentials
(
choice
,
request
.
ToDisclose
())
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
builders
:=
gabi
.
ProofBuilderList
([]
gabi
.
ProofBuilder
{})
for
id
,
list
:=
range
todisclose
{
cred
,
err
:=
client
.
credentialByID
(
id
)
for
i
,
choice
:=
range
disjunctionChoices
{
cred
,
err
:=
client
.
credentialByID
(
choice
[
0
]
.
Identifier
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
builders
=
append
(
builders
,
cred
.
Credential
.
CreateDisclosureProofBuilder
(
list
))
choice
[
0
]
.
CredentialIndex
=
i
builders
=
append
(
builders
,
cred
.
Credential
.
CreateDisclosureProofBuilder
(
todisclose
[
choice
[
0
]
.
Identifier
]))
}
if
issig
{
...
...
@@ -559,21 +569,24 @@ func (client *Client) ProofBuilders(choice *irma.DisclosureChoice, request irma.
r
:=
request
.
(
*
irma
.
SignatureRequest
)
r
.
Timestamp
,
err
=
irma
.
GetTimestamp
(
r
.
Message
,
sigs
,
disclosed
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
}
return
builders
,
nil
return
builders
,
disjunctionChoices
,
nil
}
// Proofs computes disclosure proofs containing the attributes specified by choice.
func
(
client
*
Client
)
Proofs
(
choice
*
irma
.
DisclosureChoice
,
request
irma
.
SessionRequest
,
issig
bool
)
(
gabi
.
ProofList
,
error
)
{
builders
,
err
:=
client
.
ProofBuilders
(
choice
,
request
,
issig
)
func
(
client
*
Client
)
Proofs
(
choice
*
irma
.
DisclosureChoice
,
request
irma
.
SessionRequest
,
issig
bool
)
(
*
irma
.
Disclosure
,
error
)
{
builders
,
choices
,
err
:=
client
.
ProofBuilders
(
choice
,
request
,
issig
)
if
err
!=
nil
{
return
nil
,
err
}
return
builders
.
BuildProofList
(
request
.
GetContext
(),
request
.
GetNonce
(),
issig
),
nil
return
&
irma
.
Disclosure
{
Proofs
:
builders
.
BuildProofList
(
request
.
GetContext
(),
request
.
GetNonce
(),
issig
),
Indices
:
choices
,
},
nil
}
// generateIssuerProofNonce generates a nonce which the issuer must use in its gabi.ProofS.
...
...
@@ -584,40 +597,47 @@ func generateIssuerProofNonce() (*big.Int, error) {
// IssuanceProofBuilders constructs a list of proof builders in the issuance protocol
// for the future credentials as well as possibly any disclosed attributes, and generates
// a nonce against which the issuer's proof of knowledge must verify.
func
(
client
*
Client
)
IssuanceProofBuilders
(
request
*
irma
.
IssuanceRequest
)
(
gabi
.
ProofBuilderList
,
*
big
.
Int
,
error
)
{
func
(
client
*
Client
)
IssuanceProofBuilders
(
request
*
irma
.
IssuanceRequest
,
)
(
gabi
.
ProofBuilderList
,
irma
.
DisclosedAttributeIndices
,
*
big
.
Int
,
error
)
{
issuerProofNonce
,
err
:=
generateIssuerProofNonce
()
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
nil
,
err
}
builders
:=
gabi
.
ProofBuilderList
([]
gabi
.
ProofBuilder
{})
for
_
,
futurecred
:=
range
request
.
Credentials
{
var
pk
*
gabi
.
PublicKey
pk
,
err
=
client
.
Configuration
.
PublicKey
(
futurecred
.
CredentialTypeID
.
IssuerIdentifier
(),
futurecred
.
KeyCounter
)
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
nil
,
err
}
credBuilder
:=
gabi
.
NewCredentialBuilder
(
pk
,
request
.
GetContext
(),
client
.
secretkey
.
Key
,
issuerProofNonce
)
builders
=
append
(
builders
,
credBuilder
)
}
disclosures
,
err
:=
client
.
ProofBuilders
(
request
.
Choice
,
request
,
false
)
disclosures
,
choices
,
err
:=
client
.
ProofBuilders
(
request
.
Choice
,
request
,
false
)
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
nil
,
err
}
builders
=
append
(
disclosures
,
builders
...
)
return
builders
,
issuerProofNonce
,
nil
return
builders
,
choices
,
issuerProofNonce
,
nil
}
// IssueCommitments computes issuance commitments, along with disclosure proofs specified by choice,
// and also returns the credential builders which will become the new credentials upon combination with the issuer's signature.
func
(
client
*
Client
)
IssueCommitments
(
request
*
irma
.
IssuanceRequest
)
(
*
gabi
.
IssueCommitmentMessage
,
gabi
.
ProofBuilderList
,
error
)
{
builders
,
issuerProofNonce
,
err
:=
client
.
IssuanceProofBuilders
(
request
)
func
(
client
*
Client
)
IssueCommitments
(
request
*
irma
.
IssuanceRequest
,
)
(
*
irma
.
IssueCommitmentMessage
,
gabi
.
ProofBuilderList
,
error
)
{
builders
,
choices
,
issuerProofNonce
,
err
:=
client
.
IssuanceProofBuilders
(
request
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
list
:=
builders
.
BuildProofList
(
request
.
GetContext
(),
request
.
GetNonce
(),
false
)
return
&
gabi
.
IssueCommitmentMessage
{
Proofs
:
list
,
Nonce2
:
issuerProofNonce
},
builders
,
nil
return
&
irma
.
IssueCommitmentMessage
{
IssueCommitmentMessage
:
&
gabi
.
IssueCommitmentMessage
{
Proofs
:
builders
.
BuildProofList
(
request
.
GetContext
(),
request
.
GetNonce
(),
false
),
Nonce2
:
issuerProofNonce
,
},
Indices
:
choices
,
},
builders
,
nil
}
// ConstructCredentials constructs and saves new credentials using the specified issuance signature messages
...
...
irmaclient/session.go
View file @
d5720003
...
...
@@ -55,10 +55,11 @@ type session struct {
Version
*
irma
.
ProtocolVersion
ServerName
string
choice
*
irma
.
DisclosureChoice
client
*
Client
request
irma
.
SessionRequest
done
bool
choice
*
irma
.
DisclosureChoice
attrIndices
irma
.
DisclosedAttributeIndices
client
*
Client
request
irma
.
SessionRequest
done
bool
// State for issuance protocol
issuerProofNonce
*
big
.
Int
...
...
@@ -281,7 +282,7 @@ func (session *session) doSession(proceed bool) {
session
.
sendResponse
(
message
)
}
else
{
var
err
error
session
.
builders
,
session
.
issuerProofNonce
,
err
=
session
.
getBuilders
()
session
.
builders
,
session
.
attrIndices
,
session
.
issuerProofNonce
,
err
=
session
.
getBuilders
()
if
err
!=
nil
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorCrypto
,
Err
:
err
})
}
...
...
@@ -411,21 +412,22 @@ func (session *session) managerSession() {
// getBuilders computes the builders for disclosure proofs or secretkey-knowledge proof (in case of disclosure/signing
// and issuing respectively).
func
(
session
*
session
)
getBuilders
()
(
gabi
.
ProofBuilderList
,
*
big
.
Int
,
error
)
{
func
(
session
*
session
)
getBuilders
()
(
gabi
.
ProofBuilderList
,
irma
.
DisclosedAttributeIndices
,
*
big
.
Int
,
error
)
{
var
builders
gabi
.
ProofBuilderList
var
err
error
var
issuerProofNonce
*
big
.
Int
var
choices
irma
.
DisclosedAttributeIndices
switch
session
.
Action
{
case
irma
.
ActionSigning
:
builders
,
err
=
session
.
client
.
ProofBuilders
(
session
.
choice
,
session
.
request
,
true
)
builders
,
choices
,
err
=
session
.
client
.
ProofBuilders
(
session
.
choice
,
session
.
request
,
true
)
case
irma
.
ActionDisclosing
:
builders
,
err
=
session
.
client
.
ProofBuilders
(
session
.
choice
,
session
.
request
,
false
)
builders
,
choices
,
err
=
session
.
client
.
ProofBuilders
(
session
.
choice
,
session
.
request
,
false
)
case
irma
.
ActionIssuing
:
builders
,
issuerProofNonce
,
err
=
session
.
client
.
IssuanceProofBuilders
(
session
.
request
.
(
*
irma
.
IssuanceRequest
))
builders
,
choices
,
issuerProofNonce
,
err
=
session
.
client
.
IssuanceProofBuilders
(
session
.
request
.
(
*
irma
.
IssuanceRequest
))
}
return
builders
,
issuerProofNonce
,
err
return
builders
,
choices
,
issuerProofNonce
,
err
}
// getProofs computes the disclosure proofs or secretkey-knowledge proof (in case of disclosure/signing
...
...
@@ -591,7 +593,20 @@ func (session *session) Dismiss() {
// Keyshare session handler methods
func
(
session
*
session
)
KeyshareDone
(
message
interface
{})
{
session
.
sendResponse
(
message
)
switch
session
.
Action
{
case
irma
.
ActionSigning
:
fallthrough
case
irma
.
ActionDisclosing
:
session
.
sendResponse
(
&
irma
.
Disclosure
{
Proofs
:
message
.
(
gabi
.
ProofList
),
Indices
:
session
.
attrIndices
,
})
case
irma
.
ActionIssuing
:
session
.
sendResponse
(
&
irma
.
IssueCommitmentMessage
{
IssueCommitmentMessage
:
message
.
(
*
gabi
.
IssueCommitmentMessage
),
Indices
:
session
.
attrIndices
,
})
}
}
func
(
session
*
session
)
KeyshareCancelled
()
{
...
...
messages.go
View file @
d5720003
...
...
@@ -12,6 +12,7 @@ import (
"fmt"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
// Status encodes the status of an IRMA session (e.g., connected).
...
...
@@ -240,6 +241,35 @@ func (e *SessionError) Stack() string {
return
""
}
type
Disclosure
struct
{
Proofs
gabi
.
ProofList
`json:"proofs"`
Indices
DisclosedAttributeIndices
`json:"indices"`
}
// DisclosedAttributeIndices contains, for each conjunction of an attribute disclosure request,
// a list of attribute indices, pointing to where the disclosed attributes for that conjunction
// can be found within a gabi.ProofList.
type
DisclosedAttributeIndices
[][]
*
DisclosedAttributeIndex
// DisclosedAttributeIndex points to a specific attribute in a gabi.ProofList.
type
DisclosedAttributeIndex
struct
{
CredentialIndex
int
`json:"cred"`
AttributeIndex
int
`json:"attr"`
Identifier
CredentialIdentifier
`json:"-"`
// credential from which this attribute was disclosed
}
type
IssueCommitmentMessage
struct
{
*
gabi
.
IssueCommitmentMessage
Indices
DisclosedAttributeIndices
`json:"indices"`
}
func
(
i
*
IssueCommitmentMessage
)
Disclosure
()
*
Disclosure
{
return
&
Disclosure
{
Proofs
:
i
.
Proofs
,
Indices
:
i
.
Indices
,
}
}
func
JwtDecode
(
jwt
string
,
body
interface
{})
error
{
jwtparts
:=
strings
.
Split
(
jwt
,
"."
)
if
jwtparts
==
nil
||
len
(
jwtparts
)
<
2
{
...
...
requests.go
View file @
d5720003
...
...
@@ -8,7 +8,6 @@ import (
"github.com/bwesterb/go-atum"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
"github.com/mhe/gabi/big"
"github.com/privacybydesign/irmago/internal/fs"
)
...
...
@@ -362,14 +361,14 @@ func (sr *SignatureRequest) GetNonce() *big.Int {
}
func
(
sr
*
SignatureRequest
)
SignatureFromMessage
(
message
interface
{})
(
*
SignedMessage
,
error
)
{
signature
,
ok
:=
message
.
(
gabi
.
ProofList
)
signature
,
ok
:=
message
.
(
*
Disclosure
)
if
!
ok
{
return
nil
,
errors
.
Errorf
(
"Type assertion failed"
)
}
return
&
SignedMessage
{
Signature
:
signature
,
Signature
:
signature
.
Proofs
,
Nonce
:
sr
.
Nonce
,
Context
:
sr
.
Context
,
Message
:
sr
.
Message
,
...
...
verify.go
View file @
d5720003
...
...
@@ -119,7 +119,7 @@ func (pl ProofList) Expired(configuration *Configuration, t *time.Time) bool {
// with the disjunction list in the disjunction list. If any of the given disjunctions is not matched by one
// of the disclosed attributes, then the corresponding item in the returned slice has status AttributeProofStatusMissing.
// The first return parameter of this function indicates whether or not all disjunctions (if present) are satisfied.
func
(
pl
ProofList
)
DisclosedAttributes
(
configuration
*
Configuration
,
disjunctions
AttributeDisjunctionList
)
(
bool
,
[]
*
DisclosedAttribute
,
error
)
{
func
(
d
*
Disclosure
)
DisclosedAttributes
(
configuration
*
Configuration
,
disjunctions
AttributeDisjunctionList
)
(
bool
,
[]
*
DisclosedAttribute
,
error
)
{
var
list
[]
*
DisclosedAttribute
list
=
make
([]
*
DisclosedAttribute
,
len
(
disjunctions
))
for
i
:=
range
list
{
...
...
@@ -135,7 +135,7 @@ func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctio
// we append these to list just before returning
extraAttrs
:=
map
[
AttributeTypeIdentifier
]
*
DisclosedAttribute
{}
for
_
,
proof
:=
range
pl
{
for
_
,
proof
:=
range
d
.
Proofs
{
proofd
,
ok
:=
proof
.
(
*
gabi
.
ProofD
)
if
!
ok
{
continue
...
...
@@ -198,7 +198,7 @@ func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctio
return
len
(
disjunctions
)
==
0
||
disjunctions
.
satisfied
(),
list
,
nil
}
func
(
pl
ProofList
)
VerifyAgainstDisjunctions
(
func
(
d
*
Disclosure
)
VerifyAgainstDisjunctions
(
configuration
*
Configuration
,
required
AttributeDisjunctionList
,
context
,
nonce
*
big
.
Int
,
...
...
@@ -206,13 +206,13 @@ func (pl ProofList) VerifyAgainstDisjunctions(
issig
bool
,
)
([]
*
DisclosedAttribute
,
ProofStatus
,
error
)
{
// Cryptographically verify the IRMA disclosure proofs in the signature
valid
,
err
:=
pl
.
VerifyProofs
(
configuration
,
context
,
nonce
,
publickeys
,
issig
)
valid
,
err
:=
ProofList
(
d
.
Proofs
)
.
VerifyProofs
(
configuration
,
context
,
nonce
,
publickeys
,
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
:=
pl
.
DisclosedAttributes
(
configuration
,
required
)
allmatched
,
list
,
err
:=
d
.
DisclosedAttributes
(
configuration
,
required
)
if
err
!=
nil
{
return
nil
,
ProofStatusInvalid
,
err
}
...
...
@@ -225,14 +225,14 @@ func (pl ProofList) VerifyAgainstDisjunctions(
return
list
,
ProofStatusValid
,
nil
}
func
(
pl
ProofList
)
Verify
(
configuration
*
Configuration
,
request
*
DisclosureRequest
)
([]
*
DisclosedAttribute
,
ProofStatus
,
error
)
{
list
,
status
,
err
:=
pl
.
VerifyAgainstDisjunctions
(
configuration
,
request
.
Content
,
request
.
Context
,
request
.
Nonce
,
nil
,
false
)
func
(
d
*
Disclosure
)
Verify
(
configuration
*
Configuration
,
request
*
DisclosureRequest
)
([]
*
DisclosedAttribute
,
ProofStatus
,
error
)
{
list
,
status
,
err
:=
d
.
VerifyAgainstDisjunctions
(
configuration
,
request
.
Content
,
request
.
Context
,
request
.
Nonce
,
nil
,
false
)
if
err
!=
nil
{
return
list
,
status
,
err
}
now
:=
time
.
Now
()
if
expired
:=
pl
.
Expired
(
configuration
,
&
now
);
expired
{
if
expired
:=
ProofList
(
d
.
Proofs
)
.
Expired
(
configuration
,
&
now
);
expired
{
return
list
,
ProofStatusExpired
,
nil
}
...
...
@@ -272,12 +272,11 @@ func (sm *SignedMessage) Verify(configuration *Configuration, request *Signature
}
// Now, cryptographically verify the IRMA disclosure proofs in the signature
pl
:=
ProofList
(
sm
.
Signature
)
var
required
AttributeDisjunctionList
if
request
!=
nil
{
required
=
request
.
Content
}
result
,
status
,
err
:=
pl
.
VerifyAgainstDisjunctions
(
configuration
,
required
,
sm
.
Context
,
sm
.
GetNonce
(),
nil
,
true
)
result
,
status
,
err
:=
sm
.
Disclosure
()
.
VerifyAgainstDisjunctions
(
configuration
,
required
,
sm
.
Context
,
sm
.
GetNonce
(),
nil
,
true
)
if
status
!=
ProofStatusValid
||
err
!=
nil
{
return
result
,
status
,
err
}
...
...
@@ -287,7 +286,7 @@ func (sm *SignedMessage) Verify(configuration *Configuration, request *Signature
if
sm
.
Timestamp
!=
nil
{
t
=
time
.
Unix
(
sm
.
Timestamp
.
Time
,
0
)
}
if
expired
:=
pl
.
Expired
(
configuration
,
&
t
);
expired
{
if
expired
:=
ProofList
(
sm
.
Signature
)
.
Expired
(
configuration
,
&
t
);
expired
{
// The ABS contains attributes that were expired at the time of creation of the ABS.
return
result
,
ProofStatusExpired
,
nil
}
...
...
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