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 (
"math/big"
"time"
"fmt"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
......@@ -20,24 +18,6 @@ const (
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 (
versionField = metadataField{1, 0}
signingDateField = metadataField{3, 1}
......@@ -357,68 +337,50 @@ type AttributeDisjunction struct {
Values map[AttributeTypeIdentifier]*string
selected *AttributeTypeIdentifier
}
// AttributeDisjunction with the disclosed value that is used to satisfy the disjunction
type DisclosedAttributeDisjunction struct {
AttributeDisjunction
DisclosedValue TranslatedString
DisclosedId AttributeTypeIdentifier
ProofStatus AttributeProofStatus
value *string
index *int
}
// An AttributeDisjunctionList is a list of AttributeDisjunctions.
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
// that should be satisfied.
func (disjunction *AttributeDisjunction) HasValues() bool {
return disjunction.Values != nil && len(disjunction.Values) != 0
}
// Satisfied indicates if this disjunction has a valid chosen attribute
// to be disclosed.
func (disjunction *AttributeDisjunction) Satisfied() bool {
if disjunction.selected == nil {
return false
}
for _, attr := range disjunction.Attributes {
if *disjunction.selected == attr {
return true
// attemptSatisfy tries to match the specified attribute type and value against the current disjunction,
// returning true if the disjunction contains the specified attribute type. Note that if the disjunction
// has required values, then it is only considered satisfied by the specified attribute type and value
// if the required value matches the specified value.
func (disjunction *AttributeDisjunction) attemptSatisfy(id AttributeTypeIdentifier, value *string) bool {
var found bool
for index, attr := range disjunction.Attributes {
if attr == id {
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
// We return true if one of the attributes in the disjunction is satisfied
func (disjunction *AttributeDisjunction) SatisfyDisclosed(disclosed DisclosedCredentialList, conf *Configuration) (bool, *DisclosedAttributeDisjunction) {
var attributeResult *AttributeResult
for _, attr := range disjunction.Attributes {
requestedValue := disjunction.Values[attr]
var isSatisfied bool
isSatisfied, attributeResult = disclosed.isAttributeSatisfied(attr, requestedValue)
if isSatisfied {
return true, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
}
// satisfied indicates if this disjunction has a valid attribute type and value selected,
// matching one of the attributes in the disjunction and possibly also the corresponding required value.
func (disjunction *AttributeDisjunction) satisfied() bool {
if disjunction.index == nil {
return false
}
// Nothing satisfied, attributeResult will contain the last attribute of the original request
// TODO: do we want this?
return false, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
attr := disjunction.Attributes[*disjunction.index]
return !disjunction.HasValues() || disjunction.value == disjunction.Values[attr]
return false
}
// MatchesConfig returns true if all attributes contained in the disjunction are
......@@ -436,10 +398,10 @@ func (disjunction *AttributeDisjunction) MatchesConfig(conf *Configuration) bool
return true
}
// Satisfied indicates whether each contained attribute disjunction has a chosen attribute.
func (dl AttributeDisjunctionList) Satisfied() bool {
// satisfied indicates whether each contained attribute disjunction has a chosen attribute.
func (dl AttributeDisjunctionList) satisfied() bool {
for _, disjunction := range dl {
if !disjunction.Satisfied() {
if !disjunction.satisfied() {
return false
}
}
......@@ -481,27 +443,6 @@ func (disjunction *AttributeDisjunction) MarshalJSON() ([]byte, error) {
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.
func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error {
if disjunction.Values == nil {
......@@ -554,19 +495,3 @@ func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error {
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) {
sig, err := entry.GetSignedMessage()
require.NoError(t, err)
require.NotNil(t, sig)
status, list := sig.VerifyWithoutRequest(client.Configuration)
require.Equal(t, irma.ProofStatusValid, status)
require.NotEmpty(t, list)
require.Contains(t, list[0].Attributes, attrid)
require.Equal(t, "s1234567", list[0].Attributes[attrid]["en"])
result := sig.Verify(client.Configuration, nil)
require.Equal(t, irma.ProofStatusValid, result.Status)
require.NotEmpty(t, result.Attributes)
require.Equal(t, result.Attributes[0].Identifier, attrid)
require.Equal(t, "s1234567", result.Attributes[0].Value["en"])
test.ClearTestStorage(t)
}
......
......@@ -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
if init {
client = parseStorage(t)
......@@ -35,9 +35,13 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req
require.NoError(t, result.Err)
}
verifyasRequest := &irma.SignatureRequest{}
err := json.Unmarshal([]byte(verifyAs), verifyasRequest)
require.NoError(t, err)
var verifyasRequest *irma.SignatureRequest
if verifyAs != "" {
verifyasRequest = &irma.SignatureRequest{}
err := json.Unmarshal([]byte(verifyAs), verifyasRequest)
require.NoError(t, err)
}
if corrupt {
// Interesting: modifying C results in INVALID_CRYPTO; modifying A or an attribute results in INVALID_TIMESTAMP
i := result.Result.Signature[0].(*gabi.ProofD).C
......@@ -49,10 +53,14 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req
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\"]}]}"
ms := createManualSessionHandler(t, nil)
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)
require.Equal(t, irma.AttributeProofStatusPresent, result.ToAttributeResultList()[0].AttributeProofStatus)
result = manualSessionHelper(t, nil, ms, request, "", false)
require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[0].Status)
test.ClearTestStorage(t)
}
......@@ -64,7 +72,7 @@ func TestManualSessionInvalidNonce(t *testing.T) {
ms := createManualSessionHandler(t, nil)
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)
}
......@@ -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\"]}]}"
ms := createManualSessionHandler(t, nil)
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
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
require.Equal(t, irma.AttributeProofStatusExtra, list[1].AttributeProofStatus)
require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[1].Status)
test.ClearTestStorage(t)
}
......@@ -93,8 +100,8 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) {
ms := createManualSessionHandler(t, nil)
result := manualSessionHelper(t, nil, ms, request, invalidRequest, false)
require.Equal(t, irma.ProofStatusMissingAttributes, result.ProofStatus)
require.Equal(t, irma.AttributeProofStatusInvalidValue, result.ToAttributeResultList()[0].AttributeProofStatus)
require.Equal(t, irma.ProofStatusMissingAttributes, result.Status)
require.Equal(t, irma.AttributeProofStatusInvalidValue, result.Attributes[0].Status)
test.ClearTestStorage(t)
}
......@@ -102,9 +109,12 @@ func TestManualSessionInvalidAttributeValue(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\"]}]}"
ms := createManualSessionHandler(t, nil)
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)
}
......@@ -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\"]}]}"
ms := createManualSessionHandler(t, client)
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)
list := result.ToAttributeResultList()
require.Equal(t, irma.AttributeProofStatusPresent, list[0].AttributeProofStatus)
require.Equal(t, irma.AttributeProofStatusPresent, list[1].AttributeProofStatus)
result = manualSessionHelper(t, client, ms, request, "", false)
require.Equal(t, irma.ProofStatusValid, result.Status)
require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[0].Status)
require.Equal(t, irma.AttributeProofStatusExtra, result.Attributes[1].Status)
test.ClearTestStorage(t)
}
......@@ -135,7 +149,9 @@ func TestManualSessionInvalidProof(t *testing.T) {
ms := createManualSessionHandler(t, nil)
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)
}
// TODO test verification without request (also with multiproof)
......@@ -193,9 +193,11 @@ func TestAttributeDisjunctionMarshaling(t *testing.T) {
require.True(t, disjunction.MatchesConfig(conf))
require.False(t, disjunction.Satisfied())
require.False(t, disjunction.satisfied())
index := 0
disjunction.selected = &disjunction.Attributes[0]
require.True(t, disjunction.Satisfied())
disjunction.index = &index
require.True(t, disjunction.satisfied())
}
func TestMetadataAttribute(t *testing.T) {
......@@ -288,12 +290,11 @@ func TestVerifyValidSig(t *testing.T) {
require.Equal(t, sigRequest.Context, big.NewInt(1337))
// Test if we can verify it with the original request
sigProofResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, sigProofResult.ProofStatus, ProofStatusValid)
attributeList := sigProofResult.ToAttributeResultList()
require.Len(t, attributeList, 1)
require.Equal(t, attributeList[0].AttributeProofStatus, AttributeProofStatusPresent)
require.Equal(t, attributeList[0].AttributeValue["en"], "456")
verificationResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, verificationResult.Status, ProofStatusValid)
require.Len(t, verificationResult.Attributes, 1)
require.Equal(t, verificationResult.Attributes[0].Status, AttributeProofStatusPresent)
require.Equal(t, verificationResult.Attributes[0].Value["en"], "456")
// 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\"]}]}"
......@@ -305,12 +306,11 @@ func TestVerifyValidSig(t *testing.T) {
require.Equal(t, stringSigRequest.Context, big.NewInt(1337))
// Test if we can verify it with the original request
stringSigProofResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, stringSigProofResult.ProofStatus, ProofStatusValid)
stringAttributeList := sigProofResult.ToAttributeResultList()
require.Len(t, stringAttributeList, 1)
require.Equal(t, stringAttributeList[0].AttributeProofStatus, AttributeProofStatusPresent)
require.Equal(t, stringAttributeList[0].AttributeValue["en"], "456")
verificationResult = irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, verificationResult.Status, ProofStatusValid)
require.Len(t, verificationResult.Attributes, 1)
require.Equal(t, verificationResult.Attributes[0].Status, AttributeProofStatusPresent)
require.Equal(t, verificationResult.Attributes[0].Value["en"], "456")
// 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\"]}]}"
......@@ -318,13 +318,13 @@ func TestVerifyValidSig(t *testing.T) {
unmatchedSigRequest := &SignatureRequest{}
json.Unmarshal(unmatchedSigRequestJSON, 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
proofStatus, disclosed := irmaSignedMessage.VerifyWithoutRequest(conf)
require.Equal(t, proofStatus, ProofStatusValid)
require.Len(t, disclosed, 1)
require.Equal(t, disclosed[0].Attributes[NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")]["en"], "456")
verificationResult = irmaSignedMessage.Verify(conf, nil)
require.Equal(t, verificationResult.Status, ProofStatusValid)
require.Len(t, verificationResult.Attributes, 1)
require.Equal(t, verificationResult.Attributes[0].Value["en"], "456")
}
func TestVerifyInValidSig(t *testing.T) {
......@@ -341,11 +341,10 @@ func TestVerifyInValidSig(t *testing.T) {
json.Unmarshal(sigRequestJSON, sigRequest)
sigProofResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, sigProofResult.ProofStatus, ProofStatusInvalidCrypto)
require.Equal(t, sigProofResult.Status, ProofStatusInvalidCrypto)
proofStatus, disclosed := irmaSignedMessage.VerifyWithoutRequest(conf)
require.Equal(t, proofStatus, ProofStatusInvalidCrypto)
require.Nil(t, disclosed)
verificationResult := irmaSignedMessage.Verify(conf, nil)
require.Equal(t, verificationResult.Status, ProofStatusInvalidCrypto)
}
func TestVerifyInValidNonce(t *testing.T) {
......@@ -363,11 +362,10 @@ func TestVerifyInValidNonce(t *testing.T) {
json.Unmarshal(sigRequestJSON, sigRequest)
sigProofResult := irmaSignedMessage.Verify(conf, sigRequest)
require.Equal(t, sigProofResult.ProofStatus, ProofStatusInvalidCrypto)
require.Equal(t, sigProofResult.Status, ProofStatusInvalidCrypto)
proofStatus, disclosed := irmaSignedMessage.VerifyWithoutRequest(conf)
require.Equal(t, proofStatus, ProofStatusInvalidCrypto)
require.Nil(t, disclosed)
verificationResult := irmaSignedMessage.Verify(conf, nil)
require.Equal(t, verificationResult.Status, ProofStatusInvalidCrypto)
}
// Test attribute decoding with both old and new metadata versions
......
package irma
import (
"fmt"
"math/big"
"time"
......@@ -12,6 +11,9 @@ import (
// ProofStatus is the status of the complete proof
type ProofStatus string
// Status is the proof status of a single attribute
type AttributeProofStatus string
const (
ProofStatusValid = ProofStatus("VALID")
ProofStatusInvalidCrypto = ProofStatus("INVALID_CRYPTO")
......@@ -22,18 +24,12 @@ const (
// The contained attributes are currently expired, but it is not certain if they already were expired
// during creation of the ABS.
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 {
*ProofResult
Message string `json:"message"`
}
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
)
// DisclosedCredential contains raw disclosed credentials, without any extra parsing information
type DisclosedCredential struct {
......@@ -44,68 +40,17 @@ type DisclosedCredential struct {
type DisclosedCredentialList []*DisclosedCredential
// Helper function to check if an attribute is satisfied against a list of disclosed attributes
// This is the case if:
// attribute is contained in disclosed AND if a value is present: equal to that value
// al can be nil if you don't want to include attribute status for proof
func (disclosed DisclosedCredentialList) isAttributeSatisfied(attributeId AttributeTypeIdentifier, requestedValue *string) (bool, *AttributeResult) {
ar := AttributeResult{
AttributeId: attributeId,
}
for _, cred := range disclosed {
disclosedAttributeValue := cred.Attributes[attributeId]
// Continue to next credential if requested attribute isn't disclosed in this credential
if disclosedAttributeValue == nil || len(disclosedAttributeValue) == 0 {
continue
}
// If this is the disclosed attribute, check if value matches
// Attribute is satisfied if:
// - Attribute is disclosed (i.e. not nil)
// - Value is empty OR value equal to disclosedValue
ar.AttributeValue = disclosedAttributeValue
if requestedValue == nil || *cred.rawAttributes[attributeId] == *requestedValue {
ar.AttributeProofStatus = AttributeProofStatusPresent
return true, &ar
} else {
// If attribute is disclosed and present, but not equal to required value, mark it as invalid_value
// We won't return true and continue searching in other disclosed attributes
ar.AttributeProofStatus = AttributeProofStatusInvalidValue
}
}
// If there is never a value assigned, then this attribute isn't disclosed, and thus missing
if len(ar.AttributeValue) == 0 {
ar.AttributeProofStatus = AttributeProofStatusMissing
}
return false, &ar
// VerificationResult is a result of verification of a SignedMessage or disclosure proof, containing all the disclosed attributes
type VerificationResult struct {
Attributes []*DisclosedAttribute
Status ProofStatus
}
// Create a signature proof result and check disclosed credentials against a signature request
func (disclosed DisclosedCredentialList) createAndCheckSignatureProofResult(configuration *Configuration, sigRequest *SignatureRequest) *SignatureProofResult {
signatureProofResult := SignatureProofResult{
ProofResult: &ProofResult{},
Message: sigRequest.Message,
}
for _, content := range sigRequest.Content {
isSatisfied, disjunction := content.SatisfyDisclosed(disclosed, configuration)
signatureProofResult.Disjunctions = append(signatureProofResult.Disjunctions, disjunction)
// If satisfied, continue to next one
if isSatisfied {
continue
}
// Else, set proof status to missing_attributes, but check other as well to add other disjunctions to result
// (so user also knows attribute status of other disjunctions)
signatureProofResult.ProofStatus = ProofStatusMissingAttributes
}
signatureProofResult.Disjunctions = addExtraAttributes(disclosed, signatureProofResult.ProofResult)
return &signatureProofResult
// DisclosedAttribute represents a disclosed attribute.
type DisclosedAttribute struct {
Value TranslatedString `json:"value"` // Value of the disclosed attribute
Identifier AttributeTypeIdentifier `json:"id"`
Status AttributeProofStatus `json:"status"`
}
// Returns true if one of the disclosed credentials is expired at the specified time
......@@ -118,39 +63,29 @@ func (disclosed DisclosedCredentialList) IsExpired(t time.Time) bool {
return false
}
func (proofResult *ProofResult) ToAttributeResultList() AttributeResultList {
var resultList AttributeResultList
for _, v := range proofResult.Disjunctions {
result := AttributeResult{
AttributeValue: v.DisclosedValue,
AttributeId: v.DisclosedId,
AttributeProofStatus: v.ProofStatus,
}
resultList = append(resultList, &result)
}
return resultList
}
func ExtractDisclosedCredentials(conf *Configuration, proofList gabi.ProofList) (DisclosedCredentialList, error) {
var credentials = make(DisclosedCredentialList, 0, len(proofList))
// Returns true if this attrId is present in one of the disjunctions
func (proofResult *ProofResult) ContainsAttribute(attrId AttributeTypeIdentifier) bool {
for _, disj := range proofResult.Disjunctions {
for _, attr := range disj.Attributes {
if attr == attrId {
return true
}
for _, v := range proofList {
switch v.(type) {
case *gabi.ProofD:
proof := v.(*gabi.ProofD)
cred := newDisclosedCredential(proof.ADisclosed, conf)
credentials = append(credentials, cred)
case *gabi.ProofU: // nop
default:
return nil, errors.New("Cannot extract credentials from proof, not a disclosure proofD")
}
}
return false
return credentials, nil
}
func (cred *DisclosedCredential) IsExpired(t time.Time) bool {
return cred.metadataAttribute.Expiry().Before(t)
}
func NewDisclosedCredentialFromADisclosed(aDisclosed map[int]*big.Int, configuration *Configuration) *DisclosedCredential {
func newDisclosedCredential(aDisclosed map[int]*big.Int, configuration *Configuration) *DisclosedCredential {
rawAttributes := make(map[AttributeTypeIdentifier]*string)
attributes := make(map[AttributeTypeIdentifier]TranslatedString)
......@@ -175,6 +110,9 @@ func NewDisclosedCredentialFromADisclosed(aDisclosed map[int]*big.Int, configura
}
}
// extractPublicKeys returns the public keys of each proof in the proofList, in the same order,
// for later use in verification of the proofList. If one of the proofs is not a ProofD
// an error is returned.
func extractPublicKeys(configuration *Configuration, proofList gabi.ProofList) ([]*gabi.PublicKey, error) {
var publicKeys = make([]*gabi.PublicKey, 0, len(proofList))
......@@ -195,169 +133,139 @@ func extractPublicKeys(configuration *Configuration, proofList gabi.ProofList) (
return publicKeys, nil
}