Commit 5414cf36 authored by Koen van Ingen's avatar Koen van Ingen
Browse files

Some fixes in verify code after discussion

parent c9c8d085
...@@ -90,10 +90,8 @@ func (al *AttributeList) Hash() string { ...@@ -90,10 +90,8 @@ func (al *AttributeList) Hash() string {
if al.h == "" { if al.h == "" {
bytes := []byte{} bytes := []byte{}
for _, i := range al.Ints { for _, i := range al.Ints {
if i != nil {
bytes = append(bytes, i.Bytes()...) bytes = append(bytes, i.Bytes()...)
} }
}
shasum := sha256.Sum256(bytes) shasum := sha256.Sum256(bytes)
al.h = hex.EncodeToString(shasum[:]) al.h = hex.EncodeToString(shasum[:])
} }
...@@ -105,13 +103,9 @@ func (al *AttributeList) Strings() []TranslatedString { ...@@ -105,13 +103,9 @@ func (al *AttributeList) Strings() []TranslatedString {
if al.strings == nil { if al.strings == nil {
al.strings = make([]TranslatedString, len(al.Ints)-1) al.strings = make([]TranslatedString, len(al.Ints)-1)
for index, num := range al.Ints[1:] { // skip metadata for index, num := range al.Ints[1:] { // skip metadata
if num == nil {
al.strings[index] = nil
} else {
al.strings[index] = map[string]string{"en": string(num.Bytes()), "nl": string(num.Bytes())} // TODO al.strings[index] = map[string]string{"en": string(num.Bytes()), "nl": string(num.Bytes())} // TODO
} }
} }
}
return al.strings return al.strings
} }
...@@ -325,9 +319,10 @@ type DisclosedAttributeDisjunction struct { ...@@ -325,9 +319,10 @@ type DisclosedAttributeDisjunction struct {
// An AttributeDisjunctionList is a list of AttributeDisjunctions. // An AttributeDisjunctionList is a list of AttributeDisjunctions.
type AttributeDisjunctionList []*AttributeDisjunction type AttributeDisjunctionList []*AttributeDisjunction
func NewDisclosedDisjunctionFromList(ad *AttributeDisjunction, ar *AttributeResult) *DisclosedAttributeDisjunction { // Convert disjunction to a DisclosedAttributeDisjunction that contains disclosed attribute+value
func (disjunction *AttributeDisjunction) ToDisclosedAttributeDisjunction(ar *AttributeResult) *DisclosedAttributeDisjunction {
return &DisclosedAttributeDisjunction{ return &DisclosedAttributeDisjunction{
AttributeDisjunction: *ad, AttributeDisjunction: *disjunction,
DisclosedValue: ar.AttributeValue, DisclosedValue: ar.AttributeValue,
DisclosedId: ar.AttributeId, DisclosedId: ar.AttributeId,
ProofStatus: ar.AttributeProofStatus, ProofStatus: ar.AttributeProofStatus,
...@@ -354,64 +349,24 @@ func (disjunction *AttributeDisjunction) Satisfied() bool { ...@@ -354,64 +349,24 @@ func (disjunction *AttributeDisjunction) Satisfied() bool {
return false return false
} }
// 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 isAttributeSatisfied(attributeId AttributeTypeIdentifier, requestedValue string, disclosed []*DisclosedCredential) (bool, *AttributeResult) {
ar := AttributeResult{
AttributeId: attributeId,
}
for _, cred := range disclosed {
disclosedAttributeValue := cred.GetAttributeValue(attributeId)
// Continue to next credential if requested attribute isn't disclosed in this credential
if disclosedAttributeValue == "" {
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 == "" || disclosedAttributeValue == requestedValue {
ar.AttributeProofStatus = PRESENT
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 = INVALID_VALUE
}
}
// If there is never a value assigned, then this attribute isn't disclosed, and thus missing
if ar.AttributeValue == "" {
ar.AttributeProofStatus = MISSING
}
return false, &ar
}
// Check whether specified attributedisjunction satisfy a list of disclosed attributes // Check whether specified attributedisjunction satisfy a list of disclosed attributes
// We return true if one of the attributes in the disjunction is satisfied // We return true if one of the attributes in the disjunction is satisfied
func (disjunction *AttributeDisjunction) SatisfyDisclosed(disclosed []*DisclosedCredential, conf *Configuration) (bool, *DisclosedAttributeDisjunction) { func (disjunction *AttributeDisjunction) SatisfyDisclosed(disclosed DisclosedCredentialList, conf *Configuration) (bool, *DisclosedAttributeDisjunction) {
var attributeResult *AttributeResult var attributeResult *AttributeResult
for _, attr := range disjunction.Attributes { for _, attr := range disjunction.Attributes {
requestedValue := disjunction.Values[attr] requestedValue := disjunction.Values[attr]
var isSatisfied bool var isSatisfied bool
isSatisfied, attributeResult = isAttributeSatisfied(attr, requestedValue, disclosed) isSatisfied, attributeResult = disclosed.isAttributeSatisfied(attr, requestedValue)
if isSatisfied { if isSatisfied {
return true, NewDisclosedDisjunctionFromList(disjunction, attributeResult) return true, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
} }
} }
// Nothing satisfied, attributeResult will contain the last attribute of the original request // Nothing satisfied, attributeResult will contain the last attribute of the original request
// TODO: do we want this? // TODO: do we want this?
return false, NewDisclosedDisjunctionFromList(disjunction, attributeResult) return false, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
} }
// MatchesConfig returns true if all attributes contained in the disjunction are // MatchesConfig returns true if all attributes contained in the disjunction are
......
...@@ -37,12 +37,8 @@ func corruptProofString(proof string) string { ...@@ -37,12 +37,8 @@ func corruptProofString(proof string) string {
if invalidate { if invalidate {
proofBytes := []byte(proof) proofBytes := []byte(proof)
flipLoc := 15 // 15 because this is somewhere in a bigint in the json string
if proofBytes[flipLoc] == 0x33 { proofBytes[15] ^= 0x02
proofBytes[flipLoc] = 0x32
} else {
proofBytes[flipLoc] = 0x33
}
return string(proofBytes) return string(proofBytes)
} }
return proof return proof
......
...@@ -26,7 +26,7 @@ type ProofResult struct { ...@@ -26,7 +26,7 @@ type ProofResult struct {
} }
type SignatureProofResult struct { type SignatureProofResult struct {
ProofResult *ProofResult
message string message string
} }
...@@ -36,6 +36,82 @@ type DisclosedCredential struct { ...@@ -36,6 +36,82 @@ type DisclosedCredential struct {
Attributes map[AttributeTypeIdentifier]*big.Int Attributes map[AttributeTypeIdentifier]*big.Int
} }
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.GetAttributeValue(attributeId)
// Continue to next credential if requested attribute isn't disclosed in this credential
if disclosedAttributeValue == "" {
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 == "" || disclosedAttributeValue == requestedValue {
ar.AttributeProofStatus = PRESENT
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 = INVALID_VALUE
}
}
// If there is never a value assigned, then this attribute isn't disclosed, and thus missing
if ar.AttributeValue == "" {
ar.AttributeProofStatus = MISSING
}
return false, &ar
}
// 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 = MISSING_ATTRIBUTES
}
signatureProofResult.disjunctions = addExtraAttributes(disclosed, signatureProofResult.ProofResult)
return &signatureProofResult
}
// Returns true if one of the disclosed credentials is expired
func (disclosed DisclosedCredentialList) IsExpired() bool {
for _, cred := range disclosed {
if cred.IsExpired() {
return true
}
}
return false
}
func (proofResult *ProofResult) ToAttributeResultList() *AttributeResultList { func (proofResult *ProofResult) ToAttributeResultList() *AttributeResultList {
var resultList AttributeResultList var resultList AttributeResultList
...@@ -99,10 +175,10 @@ func NewDisclosedCredentialFromADisclosed(aDisclosed map[int]*big.Int, configura ...@@ -99,10 +175,10 @@ func NewDisclosedCredentialFromADisclosed(aDisclosed map[int]*big.Int, configura
} }
} }
func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList) ([]*gabi.PublicKey, error) { func extractPublicKeys(configuration *Configuration, proofList gabi.ProofList) ([]*gabi.PublicKey, error) {
var publicKeys []*gabi.PublicKey var publicKeys = make([]*gabi.PublicKey, 0, len(proofList))
for _, v := range *proofList { for _, v := range proofList {
switch v.(type) { switch v.(type) {
case *gabi.ProofD: case *gabi.ProofD:
proof := v.(*gabi.ProofD) proof := v.(*gabi.ProofD)
...@@ -112,7 +188,6 @@ func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList) ...@@ -112,7 +188,6 @@ func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList)
return nil, err return nil, err
} }
publicKeys = append(publicKeys, publicKey) publicKeys = append(publicKeys, publicKey)
default: default:
return nil, errors.New("Cannot extract public key, not a disclosure proofD!") return nil, errors.New("Cannot extract public key, not a disclosure proofD!")
} }
...@@ -120,10 +195,10 @@ func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList) ...@@ -120,10 +195,10 @@ func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList)
return publicKeys, nil return publicKeys, nil
} }
func extractDisclosedCredentials(conf *Configuration, proofList *gabi.ProofList) ([]*DisclosedCredential, error) { func extractDisclosedCredentials(conf *Configuration, proofList gabi.ProofList) (DisclosedCredentialList, error) {
var credentials []*DisclosedCredential var credentials = make(DisclosedCredentialList, 0, len(proofList))
for _, v := range *proofList { for _, v := range proofList {
switch v.(type) { switch v.(type) {
case *gabi.ProofD: case *gabi.ProofD:
proof := v.(*gabi.ProofD) proof := v.(*gabi.ProofD)
...@@ -138,10 +213,11 @@ func extractDisclosedCredentials(conf *Configuration, proofList *gabi.ProofList) ...@@ -138,10 +213,11 @@ func extractDisclosedCredentials(conf *Configuration, proofList *gabi.ProofList)
} }
// Add extra disclosed attributes to an existing and checked ProofResult in 'dummy disjunctions' // Add extra disclosed attributes to an existing and checked ProofResult in 'dummy disjunctions'
func addExtraAttributes(credentials []*DisclosedCredential, proofResult *ProofResult) []*DisclosedAttributeDisjunction { func addExtraAttributes(disclosed DisclosedCredentialList, proofResult *ProofResult) []*DisclosedAttributeDisjunction {
returnDisjunctions := append(proofResult.disjunctions) returnDisjunctions := make([]*DisclosedAttributeDisjunction, len(proofResult.disjunctions))
copy(returnDisjunctions, proofResult.disjunctions)
for _, cred := range credentials { for _, cred := range disclosed {
for attrId := range cred.Attributes { for attrId := range cred.Attributes {
if proofResult.ContainsAttribute(attrId) { if proofResult.ContainsAttribute(attrId) {
continue continue
...@@ -159,43 +235,20 @@ func addExtraAttributes(credentials []*DisclosedCredential, proofResult *ProofRe ...@@ -159,43 +235,20 @@ func addExtraAttributes(credentials []*DisclosedCredential, proofResult *ProofRe
return returnDisjunctions return returnDisjunctions
} }
// Create a signature proof result and check disclosed credentials against a signature request
func createAndCheckSignatureProofResult(configuration *Configuration, credentials []*DisclosedCredential, sigRequest *SignatureRequest) *SignatureProofResult {
signatureProofResult := SignatureProofResult{
message: sigRequest.Message,
}
for _, content := range sigRequest.Content {
isSatisfied, disjunction := content.SatisfyDisclosed(credentials, 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 = MISSING_ATTRIBUTES
}
signatureProofResult.disjunctions = addExtraAttributes(credentials, &signatureProofResult.ProofResult)
return &signatureProofResult
}
// Check an gabi prooflist against a signature proofrequest // Check an gabi prooflist against a signature proofrequest
func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofList, sigRequest *SignatureRequest) *SignatureProofResult { func checkProofWithRequest(configuration *Configuration, proofList gabi.ProofList, sigRequest *SignatureRequest) *SignatureProofResult {
credentials, err := extractDisclosedCredentials(configuration, proofList) disclosed, err := extractDisclosedCredentials(configuration, proofList)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return &SignatureProofResult{ return &SignatureProofResult{
ProofResult: ProofResult{ ProofResult: &ProofResult{
ProofStatus: INVALID_CRYPTO, ProofStatus: INVALID_CRYPTO,
}, },
} }
} }
signatureProofResult := createAndCheckSignatureProofResult(configuration, credentials, sigRequest) signatureProofResult := disclosed.createAndCheckSignatureProofResult(configuration, sigRequest)
// Return MISSING_ATTRIBUTES as proofstatus if one attribute is missing // Return MISSING_ATTRIBUTES as proofstatus if one attribute is missing
// This status takes priority over 'EXPIRED' // This status takes priority over 'EXPIRED'
...@@ -204,12 +257,10 @@ func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofLi ...@@ -204,12 +257,10 @@ func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofLi
} }
// If all disjunctions are satisfied, check if a credential is expired // If all disjunctions are satisfied, check if a credential is expired
for _, cred := range credentials { if disclosed.IsExpired() {
if cred.IsExpired() {
signatureProofResult.ProofStatus = EXPIRED signatureProofResult.ProofStatus = EXPIRED
return signatureProofResult return signatureProofResult
} }
}
// All disjunctions satisfied and nothing expired, proof is valid! // All disjunctions satisfied and nothing expired, proof is valid!
signatureProofResult.ProofStatus = VALID signatureProofResult.ProofStatus = VALID
...@@ -217,7 +268,7 @@ func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofLi ...@@ -217,7 +268,7 @@ func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofLi
} }
// Verify an IRMA proof cryptographically // Verify an IRMA proof cryptographically
func verify(configuration *Configuration, proofList *gabi.ProofList, context *big.Int, nonce *big.Int, isSig bool) bool { func verify(configuration *Configuration, proofList gabi.ProofList, context *big.Int, nonce *big.Int, isSig bool) bool {
// Extract public keys // Extract public keys
pks, err := extractPublicKeys(configuration, proofList) pks, err := extractPublicKeys(configuration, proofList)
if err != nil { if err != nil {
...@@ -237,21 +288,21 @@ func VerifySig(configuration *Configuration, proofString string, sigRequest *Sig ...@@ -237,21 +288,21 @@ func VerifySig(configuration *Configuration, proofString string, sigRequest *Sig
err := proofList.UnmarshalJSON(proofBytes) err := proofList.UnmarshalJSON(proofBytes)
if err != nil { if err != nil {
return &SignatureProofResult{ return &SignatureProofResult{
ProofResult: ProofResult{ ProofResult: &ProofResult{
ProofStatus: INVALID_SYNTAX, ProofStatus: INVALID_SYNTAX,
}, },
} }
} }
// Now, cryptographically verify the signature // Now, cryptographically verify the signature
if !verify(configuration, &proofList, sigRequest.GetContext(), sigRequest.GetNonce(), true) { if !verify(configuration, proofList, sigRequest.GetContext(), sigRequest.GetNonce(), true) {
return &SignatureProofResult{ return &SignatureProofResult{
ProofResult: ProofResult{ ProofResult: &ProofResult{
ProofStatus: INVALID_CRYPTO, ProofStatus: INVALID_CRYPTO,
}, },
} }
} }
// Finally, check whether attribute values in proof satisfy the original signature request // Finally, check whether attribute values in proof satisfy the original signature request
return checkProofWithRequest(configuration, &proofList, sigRequest) return checkProofWithRequest(configuration, proofList, sigRequest)
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment