Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add DID signature verification and replay protection (#516)
Fixes KILTprotocol/ticket#2553. The main changes are: * Removed half-baked versioning support, to re-introduce a proper one once versioning and version negotiation will be tackeld * Moved most of the logic from the `runtime-common` crate to a new `kilt-dip-support` crate, after making all the types generic over all the runtime configurations * Updated the `pallet-dip-consumer` pallet to have a bunch more details, more info below * Updated the XCM-simulator based tests ## Updates to the `dip-support` crate The `dip-support` does not contain any versioned types anymore. Support for versioning was half-baked and has been removed. Proper thought around versioning and version negotiation will happen in the (short) future. ## New `kilt-dip-support` crate The new `kilt-dip-support` crate contains types and traits that are not generic over ANY DIP deployment, but that can be used by every consumer that relies on the KILT chain as their provider. Hence, types are opinionated towards the way KILT implements the DIP protocol, but generic over the runtime configuration. The most relevant types are `MerkleProofAndDidSignatureVerifier`, exported from the root, `DidMerkleProofVerifier`, exported from the `merkle` module, and `DidSignatureAndCallVerifier`, exported from the `did` module. When they are chained together, they allow a user to submit a Merkle proof revealing parts of their DID Document, and to use one of the revealed keys to sign a specifically-crafted payload which provides authenticity guarantees of the DID subject. The default verification logic for the DID signature is the following: 1. Verify that the block number specified in the signature is no older than `SIGNATURE_VALIDITY` blocks, as specified by the runtime 2. Verify that the signature can be verified over the encoded tuple formed by `(call, identity_details, submitter_address, block_number, genesis_hash, signed_extra)`, where `signed_extra` can be anything more that the runtime might require be included in the signature. 3. Verify that one of the keys revealed in the Merkle proof can be used to verify the provided signature 4. [OPTIONAL] If the type variant which also performs authorization checks on the call itself is used, i.e., the `DidSignatureAndCallVerifier` type, then the verification will also include checking whether the used verification relationship can be used to dispatch the specified call or not, as we do ourselves in our did pallet within the `submit_did_call`, but in a more generic way. The verification logic for Merkle proofs has remained unchanged, and it can now be chained with the DID verification logic. ## Refreshed `pallet-dip-consumer` The pallet has been updated so that now the `dispatch_as` extrinsic takes a generic `Proof` instead of an `IdentityProof`, and internally performs the following checks: 1. Verify the origin is a signed origin (as before) 2. Verify that the call passes a preliminary filter, before any heavy computation is executed on the provided proof, via the `DipCallOriginFilter` type. This step will typically immediately filter out any calls that cannot be called with a Dip origin regardless of the content of the proof. 3. Retrieves the identity details from storage, if they exist 4. Delegate everything to the `ProofVerifier`, which has a mutable reference to the details fetched at step 3, in case they need to update some values that will be written to storage (e.g., the nonce) 5. The maybe mutated details are written back into storage 6. The call is dispatched with the new `DipOrigin`, which carries the additional information as returned by the `ProofVerifier`. In the demo runtime, this will be the set of keys revealed as part of the Merkle proof, that have been verified, parsed, and used for verifying the DID signature provided as part of the proof. The pallet logic is very simple, and most of the (complex) logic lies in the types that have been exposed as part of the `kilt-dip-support` crate. This makes the pallet easier to understand, and more generic to be used in different contexts potentially for different identity providers as well, where each provider might require users to provide a different identity proof. ## Minor changes Other things have been updated to reflect the relocation of some files into the new `kilt-dip-support` crate. ## How to test 1. Build [this version](KILTprotocol/sdk-js#751) of the SDK 2. Clone and `yarn install && yarn build` [this version](https://github.com/KILTprotocol/polkadot-apps/pull/8) of the PolkadotJS apps 3. Copy-paste the `@kiltprotocol/type-definitions` output into the root `node_modules` folder of the PolkadotJS apps 4. Follow the steps to set up the HRMP channels, create the DIDs, and push the identity commitment from provider to consumer 5. Use [this version](KILTprotocol/kilt-did-utilities#14) of the kilt-did-utilities CLI tool to generate a valid DIP DID signature. 6. Enjoy ☀️☀️☀️
- Loading branch information