Working with Trust Registries
Overview
This guide demonstrates how to set up an end-to-end example of a Credential Trust Establishment (CTE) trust registry for the Decentralized Identity Foundation (DIF). In this scenario, DIF issues credentials to its members, and members can subsequently issue credentials to individuals. This documentation utilizes the Veramo framework for managing DIDs (Decentralized Identifiers) and issuing Verifiable Credentials.
What is Credential Trust Establishment?
The Credential Trust Establishment (CTE) specification addresses the fundamental question of whether a relying party should trust an issuer. Is the issuer the entity the relying party expects? Are they authoritive sources for the credential issued?
Answering this question requires establishing the participants, roles, credential schemas, and governance metadata of an ecosystem.
The general steps for building and releasing a CTE registry are:
- Determine the trust context: Determine the context of the use case and the relevant natural authorities.
- Determine the credential schemas: Identify the credential schemas that will occur in tracing the authenticity of the credential.
- Identify the participants: In addition to natural authorities, the set of participants includes credential issuers and intermediate authorities.
- Establish roles: Link participants to the credentials they issue and receive.
- Finalize metadata: This includes critical information for consumers of the registry, including versioning information.
- Sign and publish the document: Signing the document allows consumers to confirm the authenticity and integrity of the trust registry itself. The CTE specification describes use of interoperability profiles, which includes cryptographic signature selections.
- Share the URI: Distribute the URI of the published document to ecosystem participants.
Consumers of the registry will add a step to their verification process to additionally check the CTE registry.
Steps
This tit
Prerequisites
Before you begin, follow the prerequisites for installation and configuration instructions.
This tutorial further uses did:web stored in github pages. If you don't have ability to use github pages, you can modify to use another did method.
1. Setting Up DIDs and Keys
Create a DID for DIF
If you have any questions about the following steps, see Veramo's guide to did:web and github pages.
veramo did create
In our sample, we used the following selections, but adapt it to use your web domain.
? Select identifier provider did:web
? Select key management system local
? Enter alias identity.foundation:cte-demo:sample_dids:dif
Resulting in the following output:
┌──────────┬───────────────────────────────────────────┬───────────────────────────────────────────────────┐
│ provider │ alias │ did │
├──────────┼───────────────────────────────────────────┼───────────────────────────────────────────────────┤
│ did:web │ identity.foundation:cte-demo:sample_dids:dif │ did:web:identity.foundation:cte-demo:sample_dids:dif │
└──────────┴───────────────────────────────────────────┴───────────────────────────────────────────────────┘
Add a Key to the DID
veramo did add-key
In our sample, we used the following selections, but adapt it to use your web domain.
? Select DID did:web:identity.foundation:cte-demo:sample_dids:dif
? Select key management system local
? Type Ed25519
Expected output:
Success: { success: true }
Retrieve and Upload DID Document
In our sample, we used the following selections, but adapt it to use your web domain.
veramo server
In a new tab:
curl -o did.json -H "Host: identity.foundation" http://localhost:3332/cte-demo/sample_dids/dif/did.json
This resulted in DIF's sample did.json, uploaded here.
2. Repeat for Sample Organization
Repeat the above steps to create a DID for a sample member organization, resulting in Sample Org's did.json file.
3. Setting Up the Trust Registry
A trust registry defines the roles and rules for credential issuance within the ecosystem. Adapting the Credential Trust Establishment example to use our DIDs created above results in the following participants; note that we're re-using schemas and roles from that example:
{
"participants": {
...
"entries": {
"https://identity.foundation/description.schema.json": {
"did:web:identity.foundation:cte-demo:sample_dids:dif": {
"name": "Decentralized Identity Foundation",
"website": "https://identity.foundation/",
"email": "membership@identity.foundation"
},
"did:web:identity.foundation:cte-demo:sample_dids:sample_org": {
"
name": "Sample Organization",
"website": "https://example.com/",
"email": "contact@example.com"
}
},
"https://identity.foundation/roles.schema.json": {
"did:web:identity.foundation:cte-demo:sample_dids:dif": [
{
"start": "2024-06-21T23:12:19Z",
"role": "dif"
}
],
"did:web:identity.foundation:cte-demo:sample_dids:sample_org": {
"start": "2024-06-21T23:12:19Z",
"role": "dif_member_organization"
}
}
}
}
}
See the resulting governance file.
4. Issuing Credentials
Issue a Credential from DIF to a Member Organization
In our example, we used these options; adapt it to use your web domain.
veramo credential create
? Credential proofFormat lds
? Issuer DID did:web:identity.foundation:cte-demo:sample_dids:dif
? Subject DID did:web:identity.foundation:cte-demo:sample_dids:sample_org
? Credential Type VerifiableCredential,DIFMemberOrganization
? Claim Type memberOf
? Claim Value Decentralized Identity Foundation
Expected output:
{
"issuer": { "id": "did:web:identity.foundation:cte-demo:sample_dids:dif" },
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://veramo.io/contexts/profile/v1"
],
"type": ["VerifiableCredential", "DIFMemberOrganization"],
"issuanceDate": "2024-07-04T19:57:28.833Z",
"credentialSubject": {
"id": "did:web:identity.foundation:cte-demo:sample_dids:sample_org",
"memberOf": "Decentralized Identity Foundation"
},
"proof": {
"type": "Ed25519Signature2018",
"created": "2024-07-04T19:57:29Z",
"verificationMethod": "did:web:identity.foundation:cte-demo:sample_dids:dif#6e6b416461e001f17961bbb0df763ed46cd9dcb64a2f37ade0f85579520de5f9",
"proofPurpose": "assertionMethod",
"jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..otV6CmxxWkp7xz6h3IpeEZeMVvHhSykE2Uj_JFpmE59ekTIB28VD2a48xgxwNP9I--yv3xDQcKtD4OC4-P8tCQ"
}
}
Issue a Credential from a Member Organization to an Individual
Create a DID for the individual:
veramo did create
? Select identifier provider did:ethr
? Select key management system local
? Enter alias sample employee
Expected output should resemble:
┌──────────┬─────────────────┬───────────────────────────────────────────────────────────────────────────────┐
│ provider │ alias │ did │
├──────────┼─────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ did:ethr │ sample employee │ did:ethr:0x03b2860e39a808df9da8786edd8503c63a48a782aba06e5a4882317d1f252f7446 │
└──────────┴─────────────────┴───────────────────────────────────────────────────────────────────────────────┘
Issue the employee credential:
veramo credential create
? Credential proofFormat jwt
? Issuer DID did:web:identity.foundation:cte-demo:sample_dids:sample_org
? Subject DID did:ethr:0x03b2860e39a808df9da8786edd8503c63a48a782aba06e5a4882317d1f252f7446
? Credential Type VerifiableCredential,DIFMemberIndividual
? Claim Type memberOf
? Claim Value Decentralized Identity Foundation
The result will look like the following:
{
credentialSubject: {
memberOf: 'Decentralized Identity Foundation',
id: 'did:ethr:0x03b2860e39a808df9da8786edd8503c63a48a782aba06e5a4882317d1f252f7446'
},
issuer: { id: 'did:web:identity.foundation:cte-demo:sample_dids:sample_org' },
type: [ 'VerifiableCredential', 'DIFMemberIndividual' ],
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://veramo.io/contexts/profile/v1'
],
issuanceDate: '2024-07-04T20:03:55.000Z',
proof: {
type: 'JwtProof2020',
jwt: 'eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vdmVyYW1vLmlvL2NvbnRleHRzL3Byb2ZpbGUvdjEiXSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIkRJRk1lbWJlckluZGl2aWR1YWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsibWVtYmVyT2YiOiJEZWNlbnRyYWxpemVkIElkZW50aXR5IEZvdW5kYXRpb24ifX0sInN1YiI6ImRpZDpldGhyOjB4MDNiMjg2MGUzOWE4MDhkZjlkYTg3ODZlZGQ4NTAzYzYzYTQ4YTc4MmFiYTA2ZTVhNDg4MjMxN2QxZjI1MmY3NDQ2IiwibmJmIjoxNzIwMTIzNDM1LCJpc3MiOiJkaWQ6d2ViOmlkZW50aXR5LmZvdW5kYXRpb246Y3RlLWRlbW86c2FtcGxlX2RpZHM6c2FtcGxlX29yZyJ9.2SXnsWqh0hRarTO_KJ6Jz6HOFKIiBqv1v4WERZIhtKleQVGqn-V2-MLOvpiYDUC-1jr5Lj6ZOOj8jKyEyul2Ng'
}
}
5. Verifying Credentials
Verification of issued credentials is crucial to ensure their authenticity and validity. Using Veramo, you can verify credentials easily.
Verify a Credential
Supposing an individual has a DIFMemberIndividual credential, at verification time, DIF's verification would perform the usual verification:
veramo credential verify
The result should say
Credential was verified successfully.
But would also modify to also check that the issuer of the credential is listed in the trust registry. This involves checking that the issuer's DID is present in the trust registry and that they have the appropriate roles and permissions to issue the specific type of credential being verified. Here is an example of how you can incorporate this check into your verification logic:
- Retrieve Trust Registry: Fetch the trust registry to get the list of authorized issuers.
- Check Issuer Authorization: Ensure the issuer's DID is listed in the trust registry with the correct role.
Example Code:
import fetch from "node-fetch";
const credential = // ypir credential
const trustRegistryUrl = // your registry
const rolesUri = // your uri
// our internal mapping of types; replace as needed
const credentialTypeMap = {}
async function fetchTrustRegistry() {
const response = await fetch(trustRegistryUrl);
const trustRegistry = await response.json();
return trustRegistry;
}
// Function to check if the issuer is authorized in the trust registry
function checkIssuerAuthorization(trustRegistry, issuerDid, credentialType) {
const issuerEntry =
trustRegistry.participants.entries[rolesUri][issuerDid];
if (!issuerEntry) {
return false;
}
// Check if the issuer has the correct role to issue the credential
const roles = trustRegistry.roles[issuerEntry.role];
const mappedCredentialType = credentialTypeMap[credentialType];
if (!roles || !roles.issue.includes(mappedCredentialType)) {
return false;
}
return true;
}
async function verifyCredential(credential) {
const trustRegistry = await fetchTrustRegistry();
// Extract issuer DID and credential type from the credential
const issuerDid = credential.issuer.id;
const credentialType = credential.type[1]; // Assuming the second type is the specific credential type
// Check if the issuer is authorized in the trust registry
const isAuthorized = checkIssuerAuthorization(
trustRegistry,
issuerDid,
credentialType
);
if (!isAuthorized) {
throw new Error("Issuer is not authorized in the trust registry");
}
// Proceed with standard Veramo credential verification
const verificationResult = await veramo.verifyCredential({ credential });
return verificationResult;
}
// Example usage
verifyCredential(credential)
.then((result) => {
console.log("Credential verification result:", result);
})
.catch((error) => {
console.error("Error verifying credential:", error);
});