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

Some fixes in verify code after discussion

parent c9c8d085
......@@ -90,9 +90,7 @@ func (al *AttributeList) Hash() string {
if al.h == "" {
bytes := []byte{}
for _, i := range al.Ints {
if i != nil {
bytes = append(bytes, i.Bytes()...)
}
bytes = append(bytes, i.Bytes()...)
}
shasum := sha256.Sum256(bytes)
al.h = hex.EncodeToString(shasum[:])
......@@ -105,11 +103,7 @@ func (al *AttributeList) Strings() []TranslatedString {
if al.strings == nil {
al.strings = make([]TranslatedString, len(al.Ints)-1)
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
......@@ -325,9 +319,10 @@ type DisclosedAttributeDisjunction struct {
// An AttributeDisjunctionList is a list of AttributeDisjunctions.
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{
AttributeDisjunction: *ad,
AttributeDisjunction: *disjunction,
DisclosedValue: ar.AttributeValue,
DisclosedId: ar.AttributeId,
ProofStatus: ar.AttributeProofStatus,
......@@ -354,64 +349,24 @@ func (disjunction *AttributeDisjunction) Satisfied() bool {
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
// 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
for _, attr := range disjunction.Attributes {
requestedValue := disjunction.Values[attr]
var isSatisfied bool
isSatisfied, attributeResult = isAttributeSatisfied(attr, requestedValue, disclosed)
isSatisfied, attributeResult = disclosed.isAttributeSatisfied(attr, requestedValue)
if isSatisfied {
return true, NewDisclosedDisjunctionFromList(disjunction, attributeResult)
return true, disjunction.ToDisclosedAttributeDisjunction(attributeResult)
}
}
// Nothing satisfied, attributeResult will contain the last attribute of the original request
// 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
......
......@@ -37,12 +37,8 @@ func corruptProofString(proof string) string {
if invalidate {
proofBytes := []byte(proof)
flipLoc := 15
if proofBytes[flipLoc] == 0x33 {
proofBytes[flipLoc] = 0x32
} else {
proofBytes[flipLoc] = 0x33
}
// 15 because this is somewhere in a bigint in the json string
proofBytes[15] ^= 0x02
return string(proofBytes)
}
return proof
......
......@@ -26,7 +26,7 @@ type ProofResult struct {
}
type SignatureProofResult struct {
ProofResult
*ProofResult
message string
}
......@@ -36,6 +36,82 @@ type DisclosedCredential struct {
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 {
var resultList AttributeResultList
......@@ -99,10 +175,10 @@ func NewDisclosedCredentialFromADisclosed(aDisclosed map[int]*big.Int, configura
}
}
func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList) ([]*gabi.PublicKey, error) {
var publicKeys []*gabi.PublicKey
func extractPublicKeys(configuration *Configuration, proofList gabi.ProofList) ([]*gabi.PublicKey, error) {
var publicKeys = make([]*gabi.PublicKey, 0, len(proofList))
for _, v := range *proofList {
for _, v := range proofList {
switch v.(type) {
case *gabi.ProofD:
proof := v.(*gabi.ProofD)
......@@ -112,7 +188,6 @@ func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList)
return nil, err
}
publicKeys = append(publicKeys, publicKey)
default:
return nil, errors.New("Cannot extract public key, not a disclosure proofD!")
}
......@@ -120,10 +195,10 @@ func extractPublicKeys(configuration *Configuration, proofList *gabi.ProofList)
return publicKeys, nil
}
func extractDisclosedCredentials(conf *Configuration, proofList *gabi.ProofList) ([]*DisclosedCredential, error) {
var credentials []*DisclosedCredential
func extractDisclosedCredentials(conf *Configuration, proofList gabi.ProofList) (DisclosedCredentialList, error) {
var credentials = make(DisclosedCredentialList, 0, len(proofList))
for _, v := range *proofList {
for _, v := range proofList {
switch v.(type) {
case *gabi.ProofD:
proof := v.(*gabi.ProofD)
......@@ -138,10 +213,11 @@ func extractDisclosedCredentials(conf *Configuration, proofList *gabi.ProofList)
}
// Add extra disclosed attributes to an existing and checked ProofResult in 'dummy disjunctions'
func addExtraAttributes(credentials []*DisclosedCredential, proofResult *ProofResult) []*DisclosedAttributeDisjunction {
returnDisjunctions := append(proofResult.disjunctions)
func addExtraAttributes(disclosed DisclosedCredentialList, proofResult *ProofResult) []*DisclosedAttributeDisjunction {
returnDisjunctions := make([]*DisclosedAttributeDisjunction, len(proofResult.disjunctions))
copy(returnDisjunctions, proofResult.disjunctions)
for _, cred := range credentials {
for _, cred := range disclosed {
for attrId := range cred.Attributes {
if proofResult.ContainsAttribute(attrId) {
continue
......@@ -159,43 +235,20 @@ func addExtraAttributes(credentials []*DisclosedCredential, proofResult *ProofRe
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
func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofList, sigRequest *SignatureRequest) *SignatureProofResult {
credentials, err := extractDisclosedCredentials(configuration, proofList)
func checkProofWithRequest(configuration *Configuration, proofList gabi.ProofList, sigRequest *SignatureRequest) *SignatureProofResult {
disclosed, err := extractDisclosedCredentials(configuration, proofList)
if err != nil {
fmt.Println(err)
return &SignatureProofResult{
ProofResult: ProofResult{
ProofResult: &ProofResult{
ProofStatus: INVALID_CRYPTO,
},
}
}
signatureProofResult := createAndCheckSignatureProofResult(configuration, credentials, sigRequest)
signatureProofResult := disclosed.createAndCheckSignatureProofResult(configuration, sigRequest)
// Return MISSING_ATTRIBUTES as proofstatus if one attribute is missing
// This status takes priority over 'EXPIRED'
......@@ -204,11 +257,9 @@ func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofLi
}
// If all disjunctions are satisfied, check if a credential is expired
for _, cred := range credentials {
if cred.IsExpired() {
signatureProofResult.ProofStatus = EXPIRED
return signatureProofResult
}
if disclosed.IsExpired() {
signatureProofResult.ProofStatus = EXPIRED
return signatureProofResult
}
// All disjunctions satisfied and nothing expired, proof is valid!
......@@ -217,7 +268,7 @@ func checkProofWithRequest(configuration *Configuration, proofList *gabi.ProofLi
}
// 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
pks, err := extractPublicKeys(configuration, proofList)
if err != nil {
......@@ -237,21 +288,21 @@ func VerifySig(configuration *Configuration, proofString string, sigRequest *Sig
err := proofList.UnmarshalJSON(proofBytes)
if err != nil {
return &SignatureProofResult{
ProofResult: ProofResult{
ProofResult: &ProofResult{
ProofStatus: INVALID_SYNTAX,
},
}
}
// 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{
ProofResult: ProofResult{
ProofResult: &ProofResult{
ProofStatus: INVALID_CRYPTO,
},
}
}
// 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