Skip to content

Commit b92df8d

Browse files
authored
Merge branch 'main' into fix/base-model-unknown
2 parents 8845436 + abcc96d commit b92df8d

93 files changed

Lines changed: 1776 additions & 451 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AnoncredsProofValidation.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Anoncreds Proof Validation in Aca-Py
2+
3+
Aca-Py does some pre-validation when verifying Anoncreds presentations (proofs), some scenarios are rejected (things that are indicative of tampering, for example) and some attributes are removed before running the anoncreds validation (for example removing superfluous non-revocation timestamps). Any Aca-Py validations or presentation modifications are indicated by the "verify_msgs" attribute in the final presentation exchange object
4+
5+
The list of possible verification messages is [here](https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/indy/verifier.py#L24), and consists of:
6+
7+
```
8+
class PresVerifyMsg(str, Enum):
9+
"""Credential verification codes."""
10+
11+
RMV_REFERENT_NON_REVOC_INTERVAL = "RMV_RFNT_NRI"
12+
RMV_GLOBAL_NON_REVOC_INTERVAL = "RMV_GLB_NRI"
13+
TSTMP_OUT_NON_REVOC_INTRVAL = "TS_OUT_NRI"
14+
CT_UNREVEALED_ATTRIBUTES = "UNRVL_ATTR"
15+
PRES_VALUE_ERROR = "VALUE_ERROR"
16+
PRES_VERIFY_ERROR = "VERIFY_ERROR"
17+
```
18+
19+
If there is additional information, it will be included like this: `TS_OUT_NRI::19_uuid` (which means the attribute identified by `19_uuid` contained a timestamp outside of the non-revocation interval (which is just a warning)).
20+
21+
A presentation verification may include multiple messages, for example:
22+
23+
```
24+
...
25+
"verified": "true",
26+
"verified_msgs": [
27+
"TS_OUT_NRI::18_uuid",
28+
"TS_OUT_NRI::18_id_GE_uuid",
29+
"TS_OUT_NRI::18_busid_GE_uuid"
30+
],
31+
...
32+
```
33+
34+
... or it may include a single message, for example:
35+
36+
```
37+
...
38+
"verified": "false",
39+
"verified_msgs": [
40+
"VALUE_ERROR::Encoded representation mismatch for 'Preferred Name'"
41+
],
42+
...
43+
```
44+
45+
... or the `verified_msgs` may be null or an empty array.
46+
47+
## Presentation Modifications and Warnings
48+
49+
The following modifications/warnings may be done by Aca-Py which shouldn't affect the verification of the received proof):
50+
51+
- "RMV_RFNT_NRI": Referent contains a non-revocation interval for a non-revocable credential (timestamp is removed)
52+
- "RMV_GLB_NRI": Presentation contains a global interval for a non-revocable credential (timestamp is removed)
53+
- "TS_OUT_NRI": Presentation contains a non-revocation timestamp outside of the requested non-revocation interval (warning)
54+
- "UNRVL_ATTR": Presentation contains attributes with unrevealed values (warning)
55+
56+
## Presentation Pre-validation Errors
57+
58+
The following pre-verification checks are done, which will fail the proof (before calling anoncreds) and will result in the following message:
59+
60+
```
61+
VALUE_ERROR::<description of the failed validation>
62+
```
63+
64+
These validations are all done within the [Indy verifier class](https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/indy/verifier.py) - to see the detailed validation just look for anywhere a `raise ValueError(...)` appears in the code.
65+
66+
A summary of the possible errors is:
67+
68+
- information missing in presentation exchange record
69+
- timestamp provided for irrevocable credential
70+
- referenced revocation registry not found on ledger
71+
- timestamp outside of reasonable range (future date or pre-dates revocation registry)
72+
- mis-match between provided and requested timestamps for non-revocation
73+
- mis-match between requested and provided attributes or predicates
74+
- self-attested attribute is provided for a requested attribute with restrictions
75+
- encoded value doesn't match raw value
76+
77+
## Anoncreds Verification Exceptions
78+
79+
Typically when you call the anoncreds `verifier_verify_proof()` method, it will return a `True` or `False` based on whether the presentation cryptographically verifies. However in the case where anoncreds throws an exception, the exception text will be included in a verification message as follows:
80+
81+
```
82+
VERIFY_ERROR::<the exception text>
83+
```
84+

CHANGELOG.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,66 @@
1+
# 1.0.0-rc0
2+
3+
## August 18, 2022
4+
5+
1.0.0 is a breaking update to ACA-Py whose version is intended to indicate the
6+
maturity of the implementation. The final 1.0.0 release will be Aries Interop
7+
Profile 2.0-complete, and based on Python 3.7 or higher. The initial (rc0)
8+
release candidate is for early adopters to provide feedback.
9+
10+
### Breaking Changes
11+
12+
As of rc0, there are no breaking updates in the release from the previous v0.7.4.
13+
However, we know that there are some pending updates that will be breaking, hence
14+
the bumps to the major/minor version elements.
15+
16+
### Categorized List of Pull Requests
17+
18+
In rc0, there are not a lot of new features, as the focus is on cleanup and
19+
optimization. The biggest is the inclusion with ACA-Py of a universal resolver
20+
interface, allowing an instance to have both local resolvers for some DID
21+
Methods and a call out to an external universal resolver for other DID Methods.
22+
While some work has been done on moving the default Python version beyond 3.6,
23+
more work is still to be done on that before the final v1.0.0 release.
24+
25+
### Categorized List of Pull Requests
26+
27+
- Verifiable credential and revocation handling updates
28+
- Refactor ledger correction code and insert into revocation error handling [\#1892](https://github.com/hyperledger/aries-cloudagent-python/pull/1892) ([ianco](https://github.com/ianco))
29+
- Indy ledger fixes and cleanups [\#1870](https://github.com/hyperledger/aries-cloudagent-python/pull/1870) ([andrewwhitehead](https://github.com/andrewwhitehead))
30+
- Refactoring of revocation registry creation [\#1813](https://github.com/hyperledger/aries-cloudagent-python/pull/1813) ([andrewwhitehead](https://github.com/andrewwhitehead))
31+
32+
- DID Registration and Resolution related updates
33+
- feat: add universal resolver [\#1866](https://github.com/hyperledger/aries-cloudagent-python/pull/1866) ([dbluhm](https://github.com/dbluhm))
34+
- fix: resolve dids following new endpoint rules [\#1863](https://github.com/hyperledger/aries-cloudagent-python/pull/1863) ([dbluhm](https://github.com/dbluhm))
35+
- fix: didx request cannot be accepted [\#1881](https://github.com/hyperledger/aries-cloudagent-python/pull/1881) ([rmnre](https://github.com/rmnre))
36+
37+
- Internal Aries framework data handling updates
38+
- fix: update RouteManager methods use to pass profile as parameter [\#1902](https://github.com/hyperledger/aries-cloudagent-python/pull/1902) ([chumbert](https://github.com/chumbert))
39+
- Allow fully qualified class names for profile managers [\#1880](https://github.com/hyperledger/aries-cloudagent-python/pull/1880) ([chumbert](https://github.com/chumbert))
40+
- fix: unable to use askar with in memory db [\#1878](https://github.com/hyperledger/aries-cloudagent-python/pull/1878) ([dbluhm](https://github.com/dbluhm))
41+
- Enable manually triggering keylist updates during connection [\#1851](https://github.com/hyperledger/aries-cloudagent-python/pull/1851) ([dbluhm](https://github.com/dbluhm))
42+
- feat: make base wallet route access configurable [\#1836](https://github.com/hyperledger/aries-cloudagent-python/pull/1836) ([dbluhm](https://github.com/dbluhm))
43+
- feat: event and webhook on keylist update stored [\#1769](https://github.com/hyperledger/aries-cloudagent-python/pull/1769) ([dbluhm](https://github.com/dbluhm))
44+
45+
- Unit, Integration and Aries Agent Test Harness Test updates
46+
- Fixes a few AATH failures [\#1897](https://github.com/hyperledger/aries-cloudagent-python/pull/1897) ([ianco](https://github.com/ianco))
47+
- fix: warnings in tests from IndySdkProfile [\#1865](https://github.com/hyperledger/aries-cloudagent-python/pull/1865) ([dbluhm](https://github.com/dbluhm))
48+
- Unit test fixes for python 3.9 [\#1858](https://github.com/hyperledger/aries-cloudagent-python/pull/1858) ([andrewwhitehead](https://github.com/andrewwhitehead))
49+
50+
- Release management pull requests
51+
- Release 1.0.0-rc0 [\#1904](https://github.com/hyperledger/aries-cloudagent-python/pull/1904) ([swcurran](https://github.com/swcurran))
52+
153
# 0.7.4
254

355
## June 30, 2022
456

57+
> :warning: **Existing multitenant JWTs invalidated when a new JWT is
58+
generated**: If you have a pre-existing implementation with existing Admin API
59+
authorization JWTs, invoking the endpoint to get a JWT now invalidates the
60+
existing JWT. Previously an identical JWT would be created. Please see this
61+
[comment on PR \#1725](https://github.com/hyperledger/aries-cloudagent-python/pull/1725#issuecomment-1096172144)
62+
for more details.
63+
564
0.7.4 is a significant release focused on stability and production deployments.
665
As the "patch" release number indicates, there were no breaking changes in the
766
Admin API, but a huge volume of updates and improvements. Highlights of this

DIDResolution.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ In practice, DIDs and DID Documents are used for a variety of purposes but espec
2929

3030
## `DIDResolver`
3131

32-
In ACA-Py, the `DIDResolver` provides the interface to resolve DIDs using registered method resolvers. Method resolver registration happens on startup through the `DIDResolverRegistry`. This registry enables additional resolvers to be loaded via plugin.
32+
In ACA-Py, the `DIDResolver` provides the interface to resolve DIDs using registered method resolvers. Method resolver registration happens on startup in a `did_resolvers` list. This registry enables additional resolvers to be loaded via plugin.
3333

3434
#### Example usage:
3535
```python=
@@ -73,17 +73,17 @@ The following is an example method resolver implementation. In this example, we
7373

7474
```python=
7575
from aries_cloudagent.config.injection_context import InjectionContext
76-
from aries_cloudagent.resolver.did_resolver_registry import DIDResolverRegistry
76+
from ..resolver.did_resolver import DIDResolver
7777
7878
from .example_resolver import ExampleResolver
7979
8080
8181
async def setup(context: InjectionContext):
8282
"""Setup the plugin."""
83-
registry = context.inject(DIDResolverRegistry)
83+
registry = context.inject(DIDResolver)
8484
resolver = ExampleResolver()
8585
await resolver.setup(context)
86-
registry.register(resolver)
86+
registry.append(resolver)
8787
```
8888

8989
#### `example_resolver.py`

Endorser.md

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Transaction Endorser Support
22

3-
Note that the ACA-Py transaction support is in the process of code refactor and cleanup. The following documents the current state, but is subject to change.
4-
53
ACA-Py supports an [Endorser Protocol](https://github.com/hyperledger/aries-rfcs/pull/586), that allows an un-privileged agent (an "Author") to request another agent (the "Endorser") to sign their transactions so they can write these transactions to the ledger. This is required on Indy ledgers, where new agents will typically be granted only "Author" privileges.
64

75
Transaction Endorsement is built into the protocols for Schema, Credential Definition and Revocation, and endorsements can be explicitely requested, or ACA-Py can be configured to automate the endorsement workflow.
@@ -61,3 +59,44 @@ Endorsement:
6159
For Authors, specify whether to automatically promote a DID to the wallet public DID after writing to the ledger.
6260
```
6361

62+
## How Aca-py Handles Endorsements
63+
64+
Internally, the Endorsement functionality is implemented as a protocol, and is implemented consistently with other protocols:
65+
66+
- a [routes.py](https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/protocols/endorse_transaction/v1_0/routes.py) file exposes the admin endpoints
67+
- [handler files](https://github.com/hyperledger/aries-cloudagent-python/tree/main/aries_cloudagent/protocols/endorse_transaction/v1_0/handlers) implement responses to any received Endorse protocol messages
68+
- a [manager.py](https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/protocols/endorse_transaction/v1_0/manager.py) file implements common functionality that is called from both the routes.py and handler classes (as well as from other classes that need to interact with Endorser functionality)
69+
70+
The Endorser makes use of the [Event Bus](https://github.com/hyperledger/aries-cloudagent-python/blob/main/CHANGELOG.md#july-14-2021) (links to the PR which links to a hackmd doc) to notify other protocols of any Endorser events of interest. For example, after a Credential Definition endorsement is received, the TransactionManager writes the endorsed transaction to the ledger and uses the Event Bus to notify the Credential Defintition manager that it can do any required post-processing (such as writing the cred def record to the wallet, initiating the revocation registry, etc.).
71+
72+
The overall architecture can be illustrated as:
73+
74+
![Class Diagram](./docs/assets/endorser-design.png)
75+
76+
### Create Credential Definition and Revocation Registry
77+
78+
An example of an Endorser flow is as follows, showing how a credential definition endorsement is received and processed, and optionally kicks off the revocation registry process:
79+
80+
![Sequence Diagram](./docs/assets/endorse-cred-def.png)
81+
82+
You can see that there is a standard endorser flow happening each time there is a ledger write (illustrated in the "Endorser" process).
83+
84+
At the end of each endorse sequence, the TransactionManager sends a notification via the EventBus so that any dependant processing can continue. Each Router is responsible for listening and responding to these notifications if necessary.
85+
86+
For example:
87+
88+
- Once the credential definition is created, a revocation registry must be created (for revocable cred defs)
89+
- Once the revocation registry is created, a revocation entry must be created
90+
- Potentially, the cred def status could be updated once the revocation entry is completed
91+
92+
Using the EventBus decouples the event sequence. Any functions triggered by an event notification are typically also available directly via Admin endpoints.
93+
94+
### Create DID and Promote to Public
95+
96+
... and an example of creating a DID and promoting it to public (and creating an ATTRIB for the endpoint:
97+
98+
![Sequence Diagram](./docs/assets/endorse-public-did.png)
99+
100+
You can see the same endorsement processes in this sequence.
101+
102+
Once the DID is written, the DID can (optionally) be promoted to the public DID, which will also invoke an ATTRIB transaction to write the endpoint.

aries_cloudagent/config/default_context.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from ..core.protocol_registry import ProtocolRegistry
1313
from ..core.goal_code_registry import GoalCodeRegistry
1414
from ..resolver.did_resolver import DIDResolver
15-
from ..resolver.did_resolver_registry import DIDResolverRegistry
1615
from ..tails.base import BaseTailsServer
1716

1817
from ..protocols.actionmenu.v1_0.base_service import BaseMenuService
@@ -50,12 +49,8 @@ async def build_context(self) -> InjectionContext:
5049
# Global event bus
5150
context.injector.bind_instance(EventBus, EventBus())
5251

53-
# Global did resolver registry
54-
did_resolver_registry = DIDResolverRegistry()
55-
context.injector.bind_instance(DIDResolverRegistry, did_resolver_registry)
56-
5752
# Global did resolver
58-
context.injector.bind_instance(DIDResolver, DIDResolver(did_resolver_registry))
53+
context.injector.bind_instance(DIDResolver, DIDResolver([]))
5954

6055
await self.bind_providers(context)
6156
await self.load_plugins(context)

aries_cloudagent/core/tests/test_conductor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from ...protocols.coordinate_mediation.v1_0.models.mediation_record import (
2525
MediationRecord,
2626
)
27-
from ...resolver.did_resolver import DIDResolver, DIDResolverRegistry
27+
from ...resolver.did_resolver import DIDResolver
2828
from ...multitenant.base import BaseMultitenantManager
2929
from ...multitenant.manager import MultitenantManager
3030
from ...storage.base import BaseStorage
@@ -92,7 +92,7 @@ async def build_context(self) -> InjectionContext:
9292
context.injector.bind_instance(ProfileManager, InMemoryProfileManager())
9393
context.injector.bind_instance(ProtocolRegistry, ProtocolRegistry())
9494
context.injector.bind_instance(BaseWireFormat, self.wire_format)
95-
context.injector.bind_instance(DIDResolver, DIDResolver(DIDResolverRegistry()))
95+
context.injector.bind_instance(DIDResolver, DIDResolver([]))
9696
context.injector.bind_instance(EventBus, MockEventBus())
9797
return context
9898

aries_cloudagent/holder/routes.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ async def credentials_remove(request: web.BaseRequest):
274274
async with context.profile.session() as session:
275275
holder = session.inject(IndyHolder)
276276
await holder.delete_credential(credential_id)
277+
topic = "acapy::record::credential::delete"
278+
await context.profile.notify(topic, {"id": credential_id, "state": "deleted"})
277279
except WalletNotFoundError as err:
278280
raise web.HTTPNotFound(reason=err.roll_up) from err
279281

@@ -376,6 +378,10 @@ async def w3c_cred_remove(request: web.BaseRequest):
376378
try:
377379
vc_record = await holder.retrieve_credential_by_id(credential_id)
378380
await holder.delete_credential(vc_record)
381+
topic = "acapy::record::w3c_credential::delete"
382+
await session.profile.notify(
383+
topic, {"id": credential_id, "state": "deleted"}
384+
)
379385
except StorageNotFoundError as err:
380386
raise web.HTTPNotFound(reason=err.roll_up) from err
381387
except StorageError as err:

aries_cloudagent/indy/credx/verifier.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from ...core.profile import Profile
99

10-
from ..verifier import IndyVerifier
10+
from ..verifier import IndyVerifier, PresVerifyMsg
1111

1212
LOGGER = logging.getLogger(__name__)
1313

@@ -33,7 +33,7 @@ async def verify_presentation(
3333
credential_definitions,
3434
rev_reg_defs,
3535
rev_reg_entries,
36-
) -> bool:
36+
) -> (bool, list):
3737
"""
3838
Verify a presentation.
3939
@@ -46,16 +46,21 @@ async def verify_presentation(
4646
rev_reg_entries: revocation registry entries
4747
"""
4848

49+
msgs = []
4950
try:
50-
self.non_revoc_intervals(pres_req, pres, credential_definitions)
51-
await self.check_timestamps(self.profile, pres_req, pres, rev_reg_defs)
52-
await self.pre_verify(pres_req, pres)
51+
msgs += self.non_revoc_intervals(pres_req, pres, credential_definitions)
52+
msgs += await self.check_timestamps(
53+
self.profile, pres_req, pres, rev_reg_defs
54+
)
55+
msgs += await self.pre_verify(pres_req, pres)
5356
except ValueError as err:
57+
s = str(err)
58+
msgs.append(f"{PresVerifyMsg.PRES_VALUE_ERROR.value}::{s}")
5459
LOGGER.error(
5560
f"Presentation on nonce={pres_req['nonce']} "
5661
f"cannot be validated: {str(err)}"
5762
)
58-
return False
63+
return (False, msgs)
5964

6065
try:
6166
presentation = Presentation.load(pres)
@@ -68,11 +73,13 @@ async def verify_presentation(
6873
rev_reg_defs.values(),
6974
rev_reg_entries,
7075
)
71-
except CredxError:
76+
except CredxError as err:
77+
s = str(err)
78+
msgs.append(f"{PresVerifyMsg.PRES_VERIFY_ERROR.value}::{s}")
7279
LOGGER.exception(
7380
f"Validation of presentation on nonce={pres_req['nonce']} "
7481
"failed with error"
7582
)
7683
verified = False
7784

78-
return verified
85+
return (verified, msgs)

0 commit comments

Comments
 (0)