Commit f3c31341 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Refactor and simplify ABS verification API

parent 94b9d8ce
...@@ -8,8 +8,6 @@ import ( ...@@ -8,8 +8,6 @@ import (
"math/big" "math/big"
"time" "time"
"fmt"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/mhe/gabi" "github.com/mhe/gabi"
) )
...@@ -20,24 +18,6 @@ const ( ...@@ -20,24 +18,6 @@ const (
metadataLength = 1 + 3 + 2 + 2 + 16 metadataLength = 1 + 3 + 2 + 2 + 16
) )
type AttributeResult struct {
AttributeValue TranslatedString `json:"value"` // Value of the disclosed attribute
AttributeId AttributeTypeIdentifier `json:"id"`
AttributeProofStatus AttributeProofStatus `json:"status"`
}
type AttributeResultList []*AttributeResult
// AttributeProofStatus is the proof status of a single attribute
type AttributeProofStatus string
const (
AttributeProofStatusPresent = AttributeProofStatus("PRESENT") // Attribute is disclosed and matches the value
AttributeProofStatusExtra = AttributeProofStatus("EXTRA") // Attribute is disclosed, but wasn't requested in request
AttributeProofStatusMissing = AttributeProofStatus("MISSING") // Attribute is NOT disclosed, but should be according to request
AttributeProofStatusInvalidValue = AttributeProofStatus("INVALID_VALUE") // Attribute is disclosed, but has invalid value according to request
)
var ( var (
versionField = metadataField{1, 0} versionField = metadataField{1, 0}
signingDateField = metadataField{3, 1} signingDateField = metadataField{3, 1}
...@@ -357,68 +337,50 @@ type AttributeDisjunction struct { ...@@ -357,68 +337,50 @@ type AttributeDisjunction struct {
Values map[AttributeTypeIdentifier]*string Values map[AttributeTypeIdentifier]*string
selected *AttributeTypeIdentifier selected *AttributeTypeIdentifier
} value *string
index *int
// AttributeDisjunction with the disclosed value that is used to satisfy the disjunction
type DisclosedAttributeDisjunction struct {
AttributeDisjunction
DisclosedValue TranslatedString
DisclosedId AttributeTypeIdentifier
ProofStatus AttributeProofStatus
} }
// An AttributeDisjunctionList is a list of AttributeDisjunctions. // An AttributeDisjunctionList is a list of AttributeDisjunctions.
type AttributeDisjunctionList []*AttributeDisjunction type AttributeDisjunctionList []*AttributeDisjunction
// Convert disjunction to a DisclosedAttributeDisjunction that contains disclosed attribute+value
func (disjunction *AttributeDisjunction) ToDisclosedAttributeDisjunction(ar *AttributeResult) *DisclosedAttributeDisjunction {
return &DisclosedAttributeDisjunction{
AttributeDisjunction: *disjunction,
DisclosedValue: ar.AttributeValue,
DisclosedId: ar.AttributeId,
ProofStatus: ar.AttributeProofStatus,
}
}
// HasValues indicates if the attributes of this disjunction have values // HasValues indicates if the attributes of this disjunction have values
// that should be satisfied. // that should be satisfied.
func (disjunction *AttributeDisjunction) HasValues() bool { func (disjunction *AttributeDisjunction) HasValues() bool {
return disjunction.Values != nil && len(disjunction.Values) != 0 return disjunction.Values != nil && len(disjunction.Values) != 0
} }
// Satisfied indicates if this disjunction has a valid chosen attribute // attemptSatisfy tries to match the specified attribute type and value against the current disjunction,
// to be disclosed. // returning true if the disjunction contains the specified attribute type. Note that if the disjunction
func (disjunction *AttributeDisjunction) Satisfied() bool { // has required values, then it is only considered satisfied by the specified attribute type and value
if disjunction.selected == nil { // if the required value matches the specified value.
return false func (disjunction *AttributeDisjunction) attemptSatisfy(id AttributeTypeIdentifier, value *string) bool {
} var found bool
for _, attr := range disjunction.Attributes { for index, attr := range disjunction.Attributes {
if *disjunction.selected == attr { if attr == id {
return true found = true
disjunction.selected = &id
disjunction.index = &index
disjunction.value = value
if !disjunction.HasValues() || disjunction.Values[id] == value {
return true
}
} }
} }
return false return found
} }
// Check whether specified attributedisjunction satisfy a list of disclosed attributes // satisfied indicates if this disjunction has a valid attribute type and value selected,
// We return true if one of the attributes in the disjunction is satisfied // matching one of the attributes in the disjunction and possibly also the corresponding required value.
func (disjunction *AttributeDisjunction) SatisfyDisclosed(disclosed DisclosedCredentialList, conf *Configuration) (bool, *DisclosedAttributeDisjunction) { func (disjunction *AttributeDisjunction) satisfied() bool {
var attributeResult *AttributeResult if disjunction.index == nil {
for _, attr := range disjunction.Attributes { return false
requestedValue := disjunction.Values[attr]
var isSatisfied bool
isSatisfied, attributeResult = disclosed.isAttributeSatisfied(attr, requestedValue)
if isSatisfied {
return true, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
}
} }
// Nothing satisfied, attributeResult will contain the last attribute of the original request attr := disjunction.Attributes[*disjunction.index]
// TODO: do we want this? return !disjunction.HasValues() || disjunction.value == disjunction.Values[attr]
return false, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
return false
} }
// MatchesConfig returns true if all attributes contained in the disjunction are // MatchesConfig returns true if all attributes contained in the disjunction are
...@@ -436,10 +398,10 @@ func (disjunction *AttributeDisjunction) MatchesConfig(conf *Configuration) bool ...@@ -436,10 +398,10 @@ func (disjunction *AttributeDisjunction) MatchesConfig(conf *Configuration) bool
return true return true
} }
// Satisfied indicates whether each contained attribute disjunction has a chosen attribute. // satisfied indicates whether each contained attribute disjunction has a chosen attribute.
func (dl AttributeDisjunctionList) Satisfied() bool { func (dl AttributeDisjunctionList) satisfied() bool {
for _, disjunction := range dl { for _, disjunction := range dl {
if !disjunction.Satisfied() { if !disjunction.satisfied() {
return false return false
} }
} }
...@@ -481,27 +443,6 @@ func (disjunction *AttributeDisjunction) MarshalJSON() ([]byte, error) { ...@@ -481,27 +443,6 @@ func (disjunction *AttributeDisjunction) MarshalJSON() ([]byte, error) {
return json.Marshal(temp) return json.Marshal(temp)
} }
// Since we have a custom MarshalJSON for AttributeDisjunction, we also need one for every struct that extends AttributeDisjunction...
func (disclosedAttributeDisjunction *DisclosedAttributeDisjunction) MarshalJSON() ([]byte, error) {
temp := struct {
Label string `json:"label"`
Attributes []AttributeTypeIdentifier `json:"attributes"`
DisclosedValue TranslatedString `json:"disclosedValue"`
DisclosedId AttributeTypeIdentifier `json:"disclosedId"`
ProofStatus AttributeProofStatus `json:"proofStatus"`
}{
Label: disclosedAttributeDisjunction.Label,
Attributes: disclosedAttributeDisjunction.Attributes,
DisclosedValue: disclosedAttributeDisjunction.DisclosedValue,
DisclosedId: disclosedAttributeDisjunction.DisclosedId,
ProofStatus: disclosedAttributeDisjunction.ProofStatus,
}
return json.Marshal(temp)
}
// UnmarshalJSON unmarshals an attribute disjunction from JSON. // UnmarshalJSON unmarshals an attribute disjunction from JSON.
func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error { func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error {
if disjunction.Values == nil { if disjunction.Values == nil {
...@@ -554,19 +495,3 @@ func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error { ...@@ -554,19 +495,3 @@ func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error {
return nil return nil
} }
func (al *AttributeResultList) String() string {
// TODO: pretty print?
str := "Attribute --- Value --- ProofStatus:"
for _, v := range *al {
str = str + "\n" + v.String()
}
return str
}
func (ar *AttributeResult) String() string {
return fmt.Sprintf("%v --- %v --- %v",
ar.AttributeId,
ar.AttributeValue,
ar.AttributeProofStatus)
}
...@@ -172,11 +172,11 @@ func TestLogging(t *testing.T) { ...@@ -172,11 +172,11 @@ func TestLogging(t *testing.T) {
sig, err := entry.GetSignedMessage() sig, err := entry.GetSignedMessage()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, sig) require.NotNil(t, sig)
status, list := sig.VerifyWithoutRequest(client.Configuration) result := sig.Verify(client.Configuration, nil)
require.Equal(t, irma.ProofStatusValid, status) require.Equal(t, irma.ProofStatusValid, result.Status)
require.NotEmpty(t, list) require.NotEmpty(t, result.Attributes)
require.Contains(t, list[0].Attributes, attrid) require.Equal(t, result.Attributes[0].Identifier, attrid)
require.Equal(t, "s1234567", list[0].Attributes[attrid]["en"]) require.Equal(t, "s1234567", result.Attributes[0].Value["en"])
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
......
...@@ -22,7 +22,7 @@ func createManualSessionHandler(t *testing.T, client *Client) *ManualTestHandler ...@@ -22,7 +22,7 @@ func createManualSessionHandler(t *testing.T, client *Client) *ManualTestHandler
} }
} }
func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, request string, verifyAs string, corrupt bool) *irma.SignatureProofResult { func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, request string, verifyAs string, corrupt bool) *irma.VerificationResult {
init := client == nil init := client == nil
if init { if init {
client = parseStorage(t) client = parseStorage(t)
...@@ -35,9 +35,13 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req ...@@ -35,9 +35,13 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req
require.NoError(t, result.Err) require.NoError(t, result.Err)
} }
verifyasRequest := &irma.SignatureRequest{} var verifyasRequest *irma.SignatureRequest
err := json.Unmarshal([]byte(verifyAs), verifyasRequest) if verifyAs != "" {
require.NoError(t, err) verifyasRequest = &irma.SignatureRequest{}
err := json.Unmarshal([]byte(verifyAs), verifyasRequest)
require.NoError(t, err)
}
if corrupt { if corrupt {
// Interesting: modifying C results in INVALID_CRYPTO; modifying A or an attribute results in INVALID_TIMESTAMP // Interesting: modifying C results in INVALID_CRYPTO; modifying A or an attribute results in INVALID_TIMESTAMP
i := result.Result.Signature[0].(*gabi.ProofD).C i := result.Result.Signature[0].(*gabi.ProofD).C
...@@ -49,10 +53,14 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req ...@@ -49,10 +53,14 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req
func TestManualSession(t *testing.T) { func TestManualSession(t *testing.T) {
request := "{\"nonce\": 42, \"context\": 1337, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}" request := "{\"nonce\": 42, \"context\": 1337, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, request, false) result := manualSessionHelper(t, nil, ms, request, request, false)
require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.AttributeProofStatusPresent, result.Attributes[0].Status)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) result = manualSessionHelper(t, nil, ms, request, "", false)
require.Equal(t, irma.AttributeProofStatusPresent, result.ToAttributeResultList()[0].AttributeProofStatus) require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[0].Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -64,7 +72,7 @@ func TestManualSessionInvalidNonce(t *testing.T) { ...@@ -64,7 +72,7 @@ func TestManualSessionInvalidNonce(t *testing.T) {
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, invalidRequest, false) result := manualSessionHelper(t, nil, ms, request, invalidRequest, false)
require.Equal(t, irma.ProofStatusUnmatchedRequest, result.ProofStatus) require.Equal(t, irma.ProofStatusUnmatchedRequest, result.Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -75,13 +83,12 @@ func TestManualSessionInvalidRequest(t *testing.T) { ...@@ -75,13 +83,12 @@ func TestManualSessionInvalidRequest(t *testing.T) {
invalidRequest := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.university\"]}]}" invalidRequest := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.university\"]}]}"
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, invalidRequest, false) result := manualSessionHelper(t, nil, ms, request, invalidRequest, false)
list := result.ToAttributeResultList()
require.Equal(t, irma.ProofStatusMissingAttributes, result.ProofStatus) require.Equal(t, irma.ProofStatusMissingAttributes, result.Status)
// First attribute result is MISSING, because it is in the request but not disclosed // First attribute result is MISSING, because it is in the request but not disclosed
require.Equal(t, irma.AttributeProofStatusMissing, list[0].AttributeProofStatus) require.Equal(t, irma.AttributeProofStatusMissing, result.Attributes[0].Status)
// Second attribute result is EXTRA, since it is disclosed, but not matching the sigrequest // Second attribute result is EXTRA, since it is disclosed, but not matching the sigrequest
require.Equal(t, irma.AttributeProofStatusExtra, list[1].AttributeProofStatus) require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[1].Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -93,8 +100,8 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) { ...@@ -93,8 +100,8 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) {
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, invalidRequest, false) result := manualSessionHelper(t, nil, ms, request, invalidRequest, false)
require.Equal(t, irma.ProofStatusMissingAttributes, result.ProofStatus) require.Equal(t, irma.ProofStatusMissingAttributes, result.Status)
require.Equal(t, irma.AttributeProofStatusInvalidValue, result.ToAttributeResultList()[0].AttributeProofStatus) require.Equal(t, irma.AttributeProofStatusInvalidValue, result.Attributes[0].Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -102,9 +109,12 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) { ...@@ -102,9 +109,12 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) {
func TestManualKeyShareSession(t *testing.T) { func TestManualKeyShareSession(t *testing.T) {
request := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"test.test.mijnirma.email\"]}]}" request := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"test.test.mijnirma.email\"]}]}"
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, request, false) result := manualSessionHelper(t, nil, ms, request, request, false)
require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) result = manualSessionHelper(t, nil, ms, request, "", false)
require.Equal(t, irma.ProofStatusValid, result.Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -120,12 +130,16 @@ func TestManualSessionMultiProof(t *testing.T) { ...@@ -120,12 +130,16 @@ func TestManualSessionMultiProof(t *testing.T) {
request := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]},{\"label\":\"BSN\",\"attributes\":[\"irma-demo.MijnOverheid.root.BSN\"]}]}" request := "{\"nonce\": 0, \"context\": 0, \"type\": \"signing\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]},{\"label\":\"BSN\",\"attributes\":[\"irma-demo.MijnOverheid.root.BSN\"]}]}"
ms := createManualSessionHandler(t, client) ms := createManualSessionHandler(t, client)
result := manualSessionHelper(t, client, ms, request, request, false) result := manualSessionHelper(t, client, ms, request, request, false)
require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.AttributeProofStatusPresent, result.Attributes[0].Status)
require.Equal(t, irma.AttributeProofStatusPresent, result.Attributes[1].Status)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) result = manualSessionHelper(t, client, ms, request, "", false)
list := result.ToAttributeResultList() require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.AttributeProofStatusPresent, list[0].AttributeProofStatus) require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[0].Status)
require.Equal(t, irma.AttributeProofStatusPresent, list[1].AttributeProofStatus) require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[1].Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
...@@ -135,7 +149,9 @@ func TestManualSessionInvalidProof(t *testing.T) { ...@@ -135,7 +149,9 @@ func TestManualSessionInvalidProof(t *testing.T) {
ms := createManualSessionHandler(t, nil) ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, request, true) result := manualSessionHelper(t, nil, ms, request, request, true)
require.Equal(t, irma.ProofStatusInvalidCrypto, result.ProofStatus) require.Equal(t, irma.ProofStatusInvalidCrypto, result.Status)
test.ClearTestStorage(t) test.ClearTestStorage(t)
} }
// TODO test verification without request (also with multiproof)
...@@ -193,9 +193,11 @@ func TestAttributeDisjunctionMarshaling(t *testing.T) { ...@@ -193,9 +193,11 @@ func TestAttributeDisjunctionMarshaling(t *testing.T) {
require.True(t, disjunction.MatchesConfig(conf)) require.True(t, disjunction.MatchesConfig(conf))
require.False(t, disjunction.Satisfied()) require.False(t, disjunction.satisfied())
index := 0
disjunction.selected = &disjunction.Attributes[0] disjunction.selected = &disjunction.Attributes[0]
require.True(t, disjunction.Satisfied()) disjunction.index = &index
require.True(t, disjunction.satisfied())
} }
func TestMetadataAttribute(t *testing.T) { func TestMetadataAttribute(t *testing.T) {
...@@ -288,12 +290,11 @@ func TestVerifyValidSig(t *testing.T) { ...@@ -288,12 +290,11 @@ func TestVerifyValidSig(t *testing.T) {
require.Equal(t, sigRequest.Context, big.NewInt(1337)) require.Equal(t, sigRequest.Context, big.NewInt(1337))
// Test if we can verify it with the original request // Test if we can verify it with the original request
sigProofResult := irmaSignedMessage.Verify(conf, sigRequest) verificationResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, sigProofResult.ProofStatus, ProofStatusValid) require.Equal(t, verificationResult.Status, ProofStatusValid)
attributeList := sigProofResult.ToAttributeResultList() require.Len(t, verificationResult.Attributes, 1)
require.Len(t, attributeList, 1) require.Equal(t, verificationResult.Attributes[0].Status, AttributeProofStatusPresent)
require.Equal(t, attributeList[0].AttributeProofStatus, AttributeProofStatusPresent) require.Equal(t, verificationResult.Attributes[0].Value["en"], "456")
require.Equal(t, attributeList[0].AttributeValue["en"], "456")
// Test if we can verify it with a request that contains strings instead of ints for nonce and context // Test if we can verify it with a request that contains strings instead of ints for nonce and context
stringRequest := "{\"nonce\": \"42\", \"context\": \"1337\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}" stringRequest := "{\"nonce\": \"42\", \"context\": \"1337\", \"message\":\"I owe you everything\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
...@@ -305,12 +306,11 @@ func TestVerifyValidSig(t *testing.T) { ...@@ -305,12 +306,11 @@ func TestVerifyValidSig(t *testing.T) {
require.Equal(t, stringSigRequest.Context, big.NewInt(1337)) require.Equal(t, stringSigRequest.Context, big.NewInt(1337))
// Test if we can verify it with the original request // Test if we can verify it with the original request
stringSigProofResult := irmaSignedMessage.Verify(conf, sigRequest) verificationResult = irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, stringSigProofResult.ProofStatus, ProofStatusValid) require.Equal(t, verificationResult.Status, ProofStatusValid)
stringAttributeList := sigProofResult.ToAttributeResultList() require.Len(t, verificationResult.Attributes, 1)
require.Len(t, stringAttributeList, 1) require.Equal(t, verificationResult.Attributes[0].Status, AttributeProofStatusPresent)
require.Equal(t, stringAttributeList[0].AttributeProofStatus, AttributeProofStatusPresent) require.Equal(t, verificationResult.Attributes[0].Value["en"], "456")
require.Equal(t, stringAttributeList[0].AttributeValue["en"], "456")
// Test verify against unmatched request (i.e. different nonce, context or message) // Test verify against unmatched request (i.e. different nonce, context or message)
unmatched := "{\"nonce\": 42, \"context\": 1337, \"message\":\"I owe you NOTHING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}" unmatched := "{\"nonce\": 42, \"context\": 1337, \"message\":\"I owe you NOTHING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
...@@ -318,13 +318,13 @@ func TestVerifyValidSig(t *testing.T) { ...@@ -318,13 +318,13 @@ func TestVerifyValidSig(t *testing.T) {
unmatchedSigRequest := &SignatureRequest{} unmatchedSigRequest := &SignatureRequest{}
json.Unmarshal(unmatchedSigRequestJSON, unmatchedSigRequest) json.Unmarshal(unmatchedSigRequestJSON, unmatchedSigRequest)
unmatchedResult := irmaSignedMessage.Verify(conf, unmatchedSigRequest) unmatchedResult := irmaSignedMessage.Verify(conf, unmatchedSigRequest)
require.Equal(t, unmatchedResult.ProofStatus, ProofStatusUnmatchedRequest) require.Equal(t, unmatchedResult.Status, ProofStatusUnmatchedRequest)
// Test if we can also verify it without using the original request // Test if we can also verify it without using the original request
proofStatus, disclosed := irmaSignedMessage.VerifyWithoutRequest(conf) verificationResult = irmaSignedMessage.Verify(conf, nil)
require.Equal(t, proofStatus, ProofStatusValid) require.Equal(t, verificationResult.Status, ProofStatusValid)
require.Len(t, disclosed, 1) require.Len(t, verificationResult.Attributes, 1)
require.Equal(t, disclosed[0].Attributes[NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")]["en"], "456") require.Equal(t, verificationResult.Attributes[0].Value["en"], "456")
} }
func TestVerifyInValidSig(t *testing.T) { func TestVerifyInValidSig(t *testing.T) {
...@@ -341,11 +341,10 @@ func TestVerifyInValidSig(t *testing.T) { ...@@ -341,11 +341,10 @@ func TestVerifyInValidSig(t *testing.T) {
json.Unmarshal(sigRequestJSON, sigRequest) json.Unmarshal(sigRequestJSON, sigRequest)
sigProofResult := irmaSignedMessage.Verify(conf, sigRequest) sigProofResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, sigProofResult.ProofStatus, ProofStatusInvalidCrypto) require.Equal(t, sigProofResult.Status, ProofStatusInvalidCrypto)
proofStatus, disclosed := irmaSignedMessage.VerifyWithoutRequest(conf) verificationResult := irmaSignedMessage.Verify(conf, nil)
require.Equal(t, proofStatus, ProofStatusInvalidCrypto) require.Equal(t, verificationResult.Status, ProofStatusInvalidCrypto)
require.Nil(t, disclosed)
} }
func TestVerifyInValidNonce(t *testing.T) { func TestVerifyInValidNonce(t *testing.T) {
...@@ -363,11 +362,10 @@ func TestVerifyInValidNonce(t *testing.T) { ...@@ -363,11 +362,10 @@ func TestVerifyInValidNonce(t *testing.T) {
json.Unmarshal(sigRequestJSON, sigRequest) json.Unmarshal(sigRequestJSON, sigRequest)
sigProofResult := irmaSignedMessage.Verify(conf, sigRequest) sigProofResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, sigProofResult.ProofStatus, ProofStatusInvalidCrypto) require.Equal(t, sigProofResult.Status, ProofStatusInvalidCrypto)
proofStatus, disclosed := irmaSignedMessage.VerifyWithoutRequest(conf) verificationResult := irmaSignedMessage.Verify(conf, nil)
require.Equal(t, proofStatus, ProofStatusInvalidCrypto) require.Equal(t, verificationResult.Status, ProofStatusInvalidCrypto)
require.Nil(t, disclosed)
} }
// Test attribute decoding with both old and new metadata versions // Test attribute decoding with both old and new metadata versions
......
package irma package irma
import ( import (
"fmt"
"math/big" "math/big"
"time" "time"
...@@ -12,6 +11,9 @@ import ( ...@@ -12,6 +11,9 @@ import (
// ProofStatus is the status of the complete proof // ProofStatus is the status of the complete proof
type ProofStatus string type ProofStatus string
// Status is the proof status of a single attribute
type AttributeProofStatus string
const ( const (
ProofStatusValid = ProofStatus("VALID") ProofStatusValid = ProofStatus("VALID")
ProofStatusInvalidCrypto = ProofStatus("INVALID_CRYPTO") ProofStatusInvalidCrypto = ProofStatus("INVALID_CRYPTO")
...@@ -22,18 +24,12 @@ const ( ...@@ -22,18 +24,12 @@ const (
// The contained attributes are currently expired, but it is not certain if they already were expired // The contained attributes are currently expired, but it is not certain if they already were expired
// during creation of the ABS. // during creation of the ABS.
ProofStatusExpired = ProofStatus("EXPIRED") ProofStatusExpired = ProofStatus("EXPIRED")
)
// ProofResult is a result of a complete proof, containing all the disclosed attributes and corresponding request
type ProofResult struct {
Disjunctions []*DisclosedAttributeDisjunction `json:"disjunctions"`
ProofStatus ProofStatus
}
type SignatureProofResult struct { AttributeProofStatusPresent = AttributeProofStatus("PRESENT") // Attribute is disclosed and matches the value
*ProofResult AttributeProofStatusExtra = AttributeProofStatus("EXTRA") // Attribute is disclosed, but wasn't requested in request
Message string `json:"message"` AttributeProofStatusMissing = AttributeProofStatus("MISSING") // Attribute is NOT disclosed, but should be according to request
} AttributeProofStatusInvalidValue = AttributeProofStatus("INVALID_VALUE") // Attribute is disclosed, but has invalid value according to request
)
// DisclosedCredential contains raw disclosed credentials, without any extra parsing information // DisclosedCredential contains raw disclosed credentials, without any extra parsing information
type DisclosedCredential struct {