Skip to content

Commit

Permalink
Merge pull request #396 from andrewwhitehead/fix/restrict-self-attest
Browse files Browse the repository at this point in the history
Don't accept self-attested attributes when restrictions are present
  • Loading branch information
andrewwhitehead authored Mar 3, 2020
2 parents c1e88e6 + 28c764d commit de91254
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 37 deletions.
103 changes: 67 additions & 36 deletions aries_cloudagent/verifier/indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging

import indy.anoncreds
from indy.error import IndyError

from ..messaging.util import canon, encode
from .base import BaseVerifier
Expand Down Expand Up @@ -34,7 +35,7 @@ def __init__(self, wallet):
self.wallet = wallet

@staticmethod
def pre_verify(pres_req: dict, pres: dict) -> PreVerifyResult:
def pre_verify(pres_req: dict, pres: dict) -> (PreVerifyResult, str):
"""
Check for essential components and tampering in presentation.
Expand All @@ -50,14 +51,11 @@ def pre_verify(pres_req: dict, pres: dict) -> PreVerifyResult:
"""
if not pres:
LOGGER.debug("No proof provided")
return PreVerifyResult.INCOMPLETE
return (PreVerifyResult.INCOMPLETE, "No proof provided")
if "requested_proof" not in pres:
LOGGER.debug("Missing 'requested_proof'")
return PreVerifyResult.INCOMPLETE
return (PreVerifyResult.INCOMPLETE, "Missing 'requested_proof'")
if "proof" not in pres:
LOGGER.debug("Missing 'proof'")
return PreVerifyResult.INCOMPLETE
return (PreVerifyResult.INCOMPLETE, "Missing 'proof'")

for (uuid, req_pred) in pres_req["requested_predicates"].items():
canon_attr = canon(req_pred["name"])
Expand All @@ -68,15 +66,21 @@ def pre_verify(pres_req: dict, pres: dict) -> PreVerifyResult:
pred = ge_proof["predicate"]
if pred["attr_name"] == canon_attr:
if pred["value"] != req_pred["p_value"]:
LOGGER.debug("Predicate value != p_value")
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Predicate value != p_value: {pred['attr_name']}",
)
break
else:
LOGGER.debug("Missing requested predicate '%s'", uuid)
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Missing requested predicate '{uuid}'",
)
except (KeyError, TypeError):
LOGGER.debug("Missing requested predicate '%s'", uuid)
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Missing requested predicate '{uuid}'",
)

revealed_attrs = pres["requested_proof"].get("revealed_attrs", {})
revealed_groups = pres["requested_proof"].get("revealed_attr_groups", {})
Expand All @@ -86,19 +90,30 @@ def pre_verify(pres_req: dict, pres: dict) -> PreVerifyResult:
if uuid in revealed_attrs:
pres_req_attr_spec = {req_attr["name"]: revealed_attrs[uuid]}
elif uuid in self_attested:
continue
if not req_attr.get("restrictions"):
continue
else:
return (
PreVerifyResult.INCOMPLETE,
"Attribute with restrictions cannot be self-attested "
f"'{req_attr['name']}'",
)
else:
LOGGER.debug("Missing requested attribute '%s'", req_attr["name"])
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Missing requested attribute '{req_attr['name']}'",
)
elif "names" in req_attr:
group_spec = revealed_groups.get(uuid)
if (
group_spec is None
or "sub_proof_index" not in group_spec
or "values" not in group_spec
):
LOGGER.debug("Missing requested attribute group '%s'", uuid)
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Missing requested attribute group '{uuid}'",
)
pres_req_attr_spec = {
attr: {
"sub_proof_index": group_spec["sub_proof_index"],
Expand All @@ -107,24 +122,33 @@ def pre_verify(pres_req: dict, pres: dict) -> PreVerifyResult:
for attr in req_attr["names"]
}
else:
LOGGER.debug("Request attribute missing 'name' and 'names'")
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Request attribute missing 'name' and 'names': '{uuid}'",
)

for (attr, spec) in pres_req_attr_spec.items():
try:
primary_enco = pres["proof"]["proofs"][spec["sub_proof_index"]][
"primary_proof"
]["eq_proof"]["revealed_attrs"][canon(attr)]
except (KeyError, TypeError):
return PreVerifyResult.INCOMPLETE
return (
PreVerifyResult.INCOMPLETE,
f"Missing revealed attribute: '{attr}'",
)
if primary_enco != spec["encoded"]:
LOGGER.debug("Encoded representation mismatch for '%s'", attr)
return PreVerifyResult.ENCODING_MISMATCH
return (
PreVerifyResult.ENCODING_MISMATCH,
f"Encoded representation mismatch for '{attr}'",
)
if primary_enco != encode(spec["raw"]):
LOGGER.debug("Encoded representation mismatch for '%s'", attr)
return PreVerifyResult.ENCODING_MISMATCH
return (
PreVerifyResult.ENCODING_MISMATCH,
f"Encoded representation mismatch for '{attr}'",
)

return PreVerifyResult.OK
return (PreVerifyResult.OK, None)

async def verify_presentation(
self, presentation_request, presentation, schemas, credential_definitions
Expand All @@ -139,21 +163,28 @@ async def verify_presentation(
credential_definitions: credential definition data
"""

pv_result = self.pre_verify(presentation_request, presentation)
(pv_result, pv_msg) = self.pre_verify(presentation_request, presentation)
if pv_result != PreVerifyResult.OK:
LOGGER.error(
f"Presentation on nonce={presentation_request['nonce']} "
f"cannot be validated: {pv_result.value}"
f"cannot be validated: {pv_result.value} [{pv_msg}]"
)
return False

verified = await indy.anoncreds.verifier_verify_proof(
json.dumps(presentation_request),
json.dumps(presentation),
json.dumps(schemas),
json.dumps(credential_definitions),
json.dumps({}), # no revocation
json.dumps({}),
)
try:
verified = await indy.anoncreds.verifier_verify_proof(
json.dumps(presentation_request),
json.dumps(presentation),
json.dumps(schemas),
json.dumps(credential_definitions),
json.dumps({}), # no revocation
json.dumps({}),
)
except IndyError:
LOGGER.exception(
f"Validation of presentation on nonce={presentation_request['nonce']} "
"failed with error"
)
verified = False

return verified
2 changes: 1 addition & 1 deletion aries_cloudagent/verifier/tests/test_indy.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ async def test_verify_presentation(self, mock_verify):

verifier = IndyVerifier("wallet")
with async_mock.patch.object(
verifier, "pre_verify", return_value=PreVerifyResult.OK
verifier, "pre_verify", return_value=(PreVerifyResult.OK, None)
):
verified = await verifier.verify_presentation(
"presentation_request",
Expand Down

0 comments on commit de91254

Please sign in to comment.