Skip to content

Commit

Permalink
Merge pull request #1923 from blockchain-certificates/feat/proof-purpose
Browse files Browse the repository at this point in the history
Enable proof purpose verification with domain and challenge checks
  • Loading branch information
lemoustachiste authored Dec 9, 2024
2 parents 9a83901 + e9bae53 commit ad4ddcc
Show file tree
Hide file tree
Showing 17 changed files with 351 additions and 52 deletions.
5 changes: 4 additions & 1 deletion bundle-esm-stats.html

Large diffs are not rendered by default.

135 changes: 126 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@
"buffer": "^6.0.3",
"jsonld": "^8.3.2",
"jsonld-checker": "npm:@blockcerts/jsonld-checker@^0.1.9",
"jsonld-signatures": "^11.2.1",
"jsonld-signatures-merkleproof2019": "^2.10.0",
"jsonld-signatures": "^11.3.2",
"jsonld-signatures-merkleproof2019": "^2.11.0",
"lodash.clonedeep": "^4.5.0",
"secp256k1": "^5.0.0",
"sha256": "^0.2.0"
Expand All @@ -87,6 +87,7 @@
"@decentralized-identity/did-common-typescript": "^0.1.19",
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-json": "^6.0.1",
"@rollup/plugin-multi-entry": "^6.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.5",
"@types/node": "^20.4.5",
Expand Down
4 changes: 3 additions & 1 deletion rollup.iife.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import typescript from '@rollup/plugin-typescript';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
import polyfills from 'rollup-plugin-polyfill-node';
import multi from '@rollup/plugin-multi-entry';
import { terser } from 'rollup-plugin-terser';

export default {
input: 'src/index.ts',
input: ['src/index.ts', 'node_modules/setimmediate/setImmediate.js'],
output: [
{
file: 'dist/verifier-iife.js',
Expand All @@ -26,6 +27,7 @@ export default {
}),
typescript(),
commonjs(),
multi(),
json(),
globals(),
builtins(),
Expand Down
11 changes: 9 additions & 2 deletions src/certificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export interface CertificateOptions {
// restricts the verification to (a) specific domain(s) - useful for authentication, should match the domain property in the proof
// https://www.w3.org/TR/vc-data-integrity/#defn-domain
domain?: string | string[];
// the property must match the one provided by the proof
// https://www.w3.org/TR/vc-data-integrity/#defn-challenge
// https://github.com/w3c/vc-data-integrity/issues/324#issuecomment-2521054375
challenge?: string;
}

export interface Signers {
Expand All @@ -56,7 +60,6 @@ export default class Certificate {
public certificateJson: Blockcerts;
public description?: string; // v1, v3.2
public display?: BlockcertsV3Display;
public proofDomain?: string | string[];
public expires: string;
public validFrom: string;
public explorerAPIs: ExplorerAPI[] = [];
Expand All @@ -70,6 +73,8 @@ export default class Certificate {
public name?: string;
public options: CertificateOptions;
public proofPurpose: string;
public proofDomain?: string | string[];
public proofChallenge?: string;
public recipientFullName: string;
public recordLink: string;
public revocationKey: string;
Expand Down Expand Up @@ -133,7 +138,8 @@ export default class Certificate {
revocationKey: this.revocationKey,
explorerAPIs: deepCopy<ExplorerAPI[]>(this.explorerAPIs),
proofPurpose: this.proofPurpose,
proofDomain: this.proofDomain
proofDomain: this.proofDomain,
proofChallenge: this.proofChallenge
});
await this.verifier.init();
this.verificationSteps = this.verifier.getVerificationSteps();
Expand Down Expand Up @@ -189,6 +195,7 @@ export default class Certificate {
this.explorerAPIs = this.options.explorerAPIs ?? [];
this.proofPurpose = this.options.proofPurpose;
this.proofDomain = this.options.domain;
this.proofChallenge = this.options.challenge;

if (options.didResolverUrl) {
domain.did.didResolver.url = options.didResolverUrl;
Expand Down
2 changes: 2 additions & 0 deletions src/models/BlockcertsV3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface VCProof {
proofValue?: string;
jws?: string;
proofPurpose: string;
domain?: string;
challenge?: string;
verificationMethod: string;
chainedProofType?: string;
previousProof?: any;
Expand Down
1 change: 1 addition & 0 deletions src/models/Suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface SuiteAPI {
issuer: Issuer;
proofPurpose?: string;
proofDomain?: string | string[];
proofChallenge?: string;
}

export abstract class Suite {
Expand Down
23 changes: 20 additions & 3 deletions src/suites/EcdsaSd2023.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type { BlockcertsV3, VCProof } from '../models/BlockcertsV3';
import type { IDidDocument } from '../models/DidDocument';
import { VerifierError } from '../models';

const { purposes: { AssertionProofPurpose } } = jsigs;
const { purposes: { AssertionProofPurpose, AuthenticationProofPurpose } } = jsigs;

enum SUB_STEPS {
retrieveVerificationMethodPublicKey = 'retrieveVerificationMethodPublicKey',
Expand All @@ -35,6 +35,10 @@ export default class EcdsaSd2023 extends Suite {
public cryptosuite = 'ecdsa-sd-2023';
public publicKey: string;
public verificationKey: any;
public proofPurpose: string;
public challenge: string;
public domain: string | string[];
private readonly proofPurposeMap: any;

constructor (props: SuiteAPI) {
super(props);
Expand All @@ -44,6 +48,13 @@ export default class EcdsaSd2023 extends Suite {
this.documentToVerify = props.document as BlockcertsV3;
this.issuer = props.issuer;
this.proof = props.proof as VCProof;
this.proofPurpose = props.proofPurpose ?? 'assertionMethod';
this.challenge = props.proofChallenge ?? '';
this.domain = props.proofDomain;
this.proofPurposeMap = {
authentication: AuthenticationProofPurpose,
assertionMethod: AssertionProofPurpose
};
this.validateProofType();
}

Expand Down Expand Up @@ -139,7 +150,7 @@ export default class EcdsaSd2023 extends Suite {
}

private getErrorMessage (verificationStatus): string {
return verificationStatus.results[0].error.cause.message;
return verificationStatus.error.errors[0].message;
}

private getTargetVerificationMethodContainer (): Issuer | IDidDocument {
Expand Down Expand Up @@ -178,9 +189,15 @@ export default class EcdsaSd2023 extends Suite {
cryptosuite: createVerifyCryptosuite({ requiredAlgorithm: 'K-256' })
});
const verificationMethod = (this.documentToVerify.proof as VCProof).verificationMethod;
if (this.proofPurpose === 'authentication' && !this.proof.challenge) {
this.proof.challenge = '';
}
const verificationStatus = await jsigs.verify(this.documentToVerify, {
suite,
purpose: new AssertionProofPurpose(),
purpose: new this.proofPurposeMap[this.proofPurpose]({
challenge: this.challenge,
domain: this.domain
}),
documentLoader: this.generateDocumentLoader([
{
url: verificationMethod,
Expand Down
Loading

0 comments on commit ad4ddcc

Please sign in to comment.