可核实的身份证件 (@数字集市/vc)
一个 Javascript 库,用于发布和验证可验证的证书.
目录
警卫
同大多数与安全和密码学有关的工具一样 您的系统将在很大程度上取决于您的设计决定( 哪些关键类型) 你将使用,你将储存 私钥,你放进你的 证书等. )
背景情况
此库是 Javascript (Node.js 和浏览器) 执行 可核实的证书数据模型 1.0 规格(目前不支持JWT序列化).
它允许您执行以下基本操作:
- 签署(签发)可核证的证书.
- 创建可验证的演示文稿(VP),签名或未签名
- 正在验证 VP
- 核查独立的《维也纳公约》
先决条件: 这个图书馆的使用假设你有能力做 目标如下:
- 生成 LD 密钥对和签名套件
- 将相应的公钥发布到可供用户访问的地方 审取者.
- 确定您的习惯
@contexts,核查方法(如公用钥匙) 及其相应的控制文档,以及任何其他可解决的 对象,可通过documentLoader。 。 。 .
安装
- 浏览器和Node.js 18+得到支持.
从国家预防机制安装:
npm install @digitalbazaar/vc
在当地安装(用于开发):
git clone https://github.com/digitalbazaar/vc.git
cd vc
npm install
使用量
建立一个签名套房
签字时,设置签名套房时,需要通过 包含私钥的密钥对.
import * as vc from '@digitalbazaar/vc';
// Required to set up a suite instance with private key
import {Ed25519VerificationKey2020} from
'@digitalbazaar/ed25519-verification-key-2020';
import {Ed25519Signature2020} from '@digitalbazaar/ed25519-signature-2020';
const keyPair = await Ed25519VerificationKey2020.generate();
const suite = new Ed25519Signature2020({key: keyPair});
签发一份可核证的证书
先决条件:
- 您有私人密钥( 带有 ID 和控制器) 和相应的套件
- 如果你使用习惯
@context,确保它可以解决 - (建议) 你有一个策略 在哪里发布你的主计长 文档和公钥
import * as vc from '@digitalbazaar/vc';
// Sample unsigned credential
const credential = {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "https://example.com/credentials/1872",
"type": ["VerifiableCredential", "AlumniCredential"],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2010-01-01T19:23:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"alumniOf": "Example University"
}
};
const signedVC = await vc.issue({credential, suite, documentLoader});
console.log(JSON.stringify(signedVC, null, 2));
发布选择性披露
先决条件:
- 您有私人密钥( 带有 ID 和控制器) 和相应的套件
- 您正在使用一个密码套件 支持选择性的披露,例如
作为
ecdsa-sd-2023或者说bbs-2023 - 如果你使用习惯
@context,确保它可以解决 - (建议) 你有一个策略 在哪里发布你的主计长 文档和公钥
使用 ecdsa-sd-2023数字 :
import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey';
import * as ecdsaSd2023Cryptosuite from
'@digitalbazaar/ecdsa-sd-2023-cryptosuite';
import * as vc from '@digitalbazaar/vc';
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
const ecdsaKeyPair = await EcdsaMultikey.generate({
curve: 'P-256',
id: 'https://example.edu/issuers/keys/2',
controller: 'https://example.edu/issuers/565049'
});
// sample exported key pair
/*
{
"@context": "https://w3id.org/security/multikey/v1",
"id": "https://example.edu/issuers/keys/2",
"type": "Multikey",
"controller": "https://example.edu/issuers/565049",
"publicKeyMultibase": "zDnaeWJjGpXnQAbEpRur3kSWFapGZbwGnFCkzyhiq7nDeXXrM",
"secretKeyMultibase": "z42trzSpncjWFaB9cKE2Gg5hxtbuAQa5mVJgGwjrugHMacdM"
}
*/
// sample unsigned credential
const credential = {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "https://example.com/credentials/1872",
"type": ["VerifiableCredential", "AlumniCredential"],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2010-01-01T19:23:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"alumniOf": "Example University"
}
};
// setup ecdsa-sd-2023 suite for signing selective disclosure VCs
const suite = new DataIntegrityProof({
signer: ecdsaKeyPair.signer(),
cryptosuite: createSignCryptosuite({
// require the `issuer` and `issuanceDate` fields to always be disclosed
// by the holder (presenter)
mandatoryPointers: [
'/issuanceDate',
'/issuer'
]
})
});
// use a proof ID to enable it to be found and transformed into a disclosure
// proof by the holder later
const proofId = `urn:uuid:${uuid()}`;
suite.proof = {id: proofId};
const signedVC = await vc.issue({credential, suite, documentLoader});
console.log(JSON.stringify(signedVC, null, 2));
使用 bbs-2023数字 :
import * as bbs2023Cryptosuite from '@digitalbazaar/bbs-2023-cryptosuite';
import * as bls12381Multikey from '@digitalbazaar/bls12-381-multikey';
import * as vc from '@digitalbazaar/vc';
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
const bbsKeyPair = await bls12381Multikey.generate({
algorithm: 'BBS-BLS12-381-SHA-256';
id: 'https://example.edu/issuers/keys/3',
controller: 'https://example.edu/issuers/565049'
});
// sample exported key pair
/*
{
"@context": "https://w3id.org/security/multikey/v1",
"id": "https://example.edu/issuers/keys/3",
"type": "Multikey",
"controller": "https://example.edu/issuers/565049",
"publicKeyMultibase": "zUC72jQrt2BfyE57AVgHgThKCsH6HNo85X9SLNpAJaHb42cNDXhsRWL2KkrFtaiztPbbZjfDVQnQQMw2nMqAPUHnaQ3xEr7kUmcnBgv7S2wQSbRbr7mqsP153nU7yMh3ZN4ZryL",
"secretKeyMultibase": "z488y1niFCWnaV2i86q1raaa7qwBWZ6WTLeS1W1PrsbcsoNg"
}
*/
// sample unsigned credential
const credential = {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
// omit `id` to enable unlinkable disclosure
"type": ["VerifiableCredential", "AlumniCredential"],
"issuer": "https://example.edu/issuers/565049",
// use less precise date that is shared by a sufficiently large group
// of VCs to enable unlinkable disclosure
"issuanceDate": "2010-01-01T01:00:00Z",
"credentialSubject": {
// omit `id` to enable unlinkable disclosure
"alumniOf": "Example University"
}
};
// setup bbs-2023 suite for signing unlinkable selective disclosure VCs
const suite = new DataIntegrityProof({
signer: bbsKeyPair.signer(),
cryptosuite: createSignCryptosuite({
// require the `issuer` and `issuanceDate` fields to always be disclosed
// by the holder (presenter)
mandatoryPointers: [
'/issuanceDate',
'/issuer'
]
})
});
// note: do not include a proof ID to enable unlinkable selective disclosure
const signedVC = await vc.issue({credential, suite, documentLoader});
console.log(JSON.stringify(signedVC, null, 2));
衍生出一种选择性披露
说明: 这一步骤是作为可核查证书的持有者履行的,而不是作为 一个发行商.
先决条件:
- 你有一个可核查的证书 发行使用密码套件
支持选择性披露,例如:
ecdsa-sd-2023或者说bbs-2023 - 如果你使用习惯
@context,确保它可以解决
使用 ecdsa-sd-2023数字 :
import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey';
import * as ecdsaSd2023Cryptosuite from
'@digitalbazaar/ecdsa-sd-2023-cryptosuite';
import * as vc from '@digitalbazaar/vc';
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
const {
createDiscloseCryptosuite,
createSignCryptosuite,
createVerifyCryptosuite
} = ecdsaSd2023Cryptosuite;
// sample VC
const verifiableCredential = {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
"https://w3id.org/security/data-integrity/v2"
],
"id": "http://example.edu/credentials/1872",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2010-01-01T19:23:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"alumniOf": "<span lang=\"en\">Example University</span>"
},
"proof": {
"id": "urn:uuid:318d9dce-bc7b-40b9-a956-c9160bf910db",
"type": "DataIntegrityProof",
"created": "2024-01-12T21:53:11Z",
"verificationMethod": "https://example.edu/issuers/keys/2",
"cryptosuite": "ecdsa-sd-2023",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0AhVhAsl6PQKYE15R0O5Qd267ntwHGNH6JRvZ1y8A-fTCQLUoupP8SCZzzmyc0a1AnabHEVKhpHtYV8j9Kapp-fHFBtFgjgCQCIMn2L1R7D5VPnNn_2foxdj8qvsuUTGFqA34YBkguzCpYILfJ-qNQpn6_dJGpkG24FynqbHpnzoHWVJc2kiLqEKHRglhAUmZtstR9MOLrZjcR8J303MXFvRiE6J3bbaPT1_I9-6578-Wj-eydv2TEGBq_dmsjxsOh4_2Va0etw8CXXMAzaVhA9fr7_Sl9D67AfvLhkJTZ0uJCAXcbL2MaS-DmoC7K-ABxroL1_wj119J8yTMlazxzYBwYkihrdp4ZWJZxraX9tIJtL2lzc3VhbmNlRGF0ZWcvaXNzdWVy"
}
};
// note no `signer` needed; the selective disclosure credential will be
// derived from the base proof already provided by the issuer
const suite = new DataIntegrityProof({
cryptosuite: createDiscloseCryptosuite({
// the ID of the base proof to convert to a disclosure proof
proofId: 'urn:uuid:da088899-3439-41ea-a580-af3f1cf98cd3',
// selectively disclose the entire credential subject; different JSON
// pointers could be provided to selectively disclose different information;
// the issuer will have mandatory fields that will be automatically
// disclosed such as the `issuer` and `issuanceDate` fields
selectivePointers: [
'/credentialSubject'
]
})
});
const derivedVC = await vc.derive({
verifiableCredential, suite, documentLoader
});
console.log(JSON.stringify(derivedVC, null, 2));
使用 bbs-2023数字 :
import * as bbs2023Cryptosuite from '@digitalbazaar/bbs-2023-cryptosuite';
import * as bls12381Multikey from '@digitalbazaar/bls12-381-multikey';
import * as vc from '@digitalbazaar/vc';
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
const {
createDiscloseCryptosuite,
createSignCryptosuite,
createVerifyCryptosuite
} = bbs2023Cryptosuite;
// sample VC
const verifiableCredential = {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
"https://w3id.org/security/data-integrity/v2"
],
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2010-01-01T01:00:00Z",
"credentialSubject": {
"alumniOf": "<span lang=\"en\">Example University</span>"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "https://example.edu/issuers/keys/3",
"cryptosuite": "bbs-2023",
"proofPurpose": "assertionMethod",
"proofValue": "u2V0ChVhQp1smqO-Qmc-1KpNkShjevTeylTdVlpH_RNXeJ_cNniErWPbEWILvsoH5mYjnun5ibZHq0m7BEIaLv8sfMtLfcmgPj6tbAFwDWvEcbRWg7CFYQGWqCAnvTpL_Aao3aVCg5svdzFuvKqnvneA0UwaN0lagvGpWT7fCDGgcYPyNPKaCX94Xo06aTcSwOXgyGUbtN1xYYIU6t5wv20lVdESfzkYOFXTxIZa1HSBAZYWDyEgQ3A3ajzWX5qeFc3cwmnnrGUfJYwawgGLQAY3vBi3LTM2i3jCOPvxCEJALPIjK4tEmWb6uFjT4PWLlIEeTtYj_0yEv91ggsm9vw1PPlK6q8wQiw2i2joZ-OKkvHz7rDSxPYfmQNrqCbS9pc3N1YW5jZURhdGVnL2lzc3Vlcg"
}
};
// note no `signer` needed; the selective disclosure credential will be
// derived from the base proof already provided by the issuer
const suite = new DataIntegrityProof({
cryptosuite: createDiscloseCryptosuite({
// selectively disclose the entire credential subject; different JSON
// pointers could be provided to selectively disclose different information;
// the issuer will have mandatory fields that will be automatically
// disclosed such as the `issuer` and `issuanceDate` fields
selectivePointers: [
'/credentialSubject'
]
})
});
const derivedVC = await vc.derive({
verifiableCredential, suite, documentLoader
});
console.log(JSON.stringify(derivedVC, null, 2));
创建可验证的演示文稿
先决条件:
- 您拥有必要的私人密钥( 带有 ID 和控制器) 和 相应套间
- 如果你使用习惯
@context,确保它可以解决 - (建议) 你有一个策略 在哪里发布你的主计长 文件和公用钥匙
创建未签名的演示文稿
要从一个或多个可核查的证书创建演示文稿,您可以
使用该 createPresentation() 方便功能. 或者,你可以
手动创建演示文稿对象(不要忘记设置) @context 财务报告和审定财务报表
type 属性).
用自定义创建可核查的演示文稿 @context 字段使用 a
自定义文档Loader
const verifiableCredential = [vc1, vc2]; // either array or single object
// optional `id` and `holder`
const id = 'ebc6f1c2';
const holder = 'did:ex:12345';
const presentation = vc.createPresentation({
verifiableCredential, id, holder
});
console.log(JSON.stringify(presentation, null, 2));
// ->
{
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": [
"VerifiablePresentation"
],
"id": "ebc6f1c2",
"holder": "did:ex:12345",
"verifiableCredential": [
// vc1:
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "http://example.edu/credentials/1872",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2010-01-01T19:23:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"alumniOf": "<span lang=\"en\">Example University</span>"
},
"proof": {
"type": "Ed25519Signature2018",
"created": "2020-02-03T17:23:49Z",
"jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..AUQ3AJ23WM5vMOWNtYKuqZBekRAOUibOMH9XuvOd39my1sO-X9R4QyAXLD2ospssLvIuwmQVhJa-F0xMOnkvBg",
"proofPurpose": "assertionMethod",
"verificationMethod": "https://example.edu/issuers/keys/1"
}
},
// vc2 goes here ...
]
}
请注意,这会造成 未签名 演示文稿( 可能有效) (有些情况).
自定义文档Loader
先决条件:
- 您有一个有效的 JSON- LD
@context。 。 。 . - 您的自定义上下文可以在地址中解决 .
// jsonld-signatures has a secure context loader
// by requiring this first you ensure security
// contexts are loaded from jsonld-signatures
// and not an insecure source.
import * as vc from '@digitalbazaar/vc';
const {extendContextLoader} = require('jsonld-signatures');
// @digitalbazaar/vc exports its own secure documentLoader.
const {defaultDocumentLoader} = vc;
// a valid json-ld @context.
const myCustomContext = require('./myCustomContext');
const documentLoader = extendContextLoader(async url => {
if(url === 'did:test:context:foo') {
return {
contextUrl: null,
documentUrl: url,
document: myCustomContext
};
}
return defaultDocumentLoader(url);
});
// you can now use your custom documentLoader
// with multiple vc methods such as:
const vp = await vc.signPresentation({
presentation, suite, challenge, documentLoader
});
// or
const signedVC = await vc.issue({credential, suite, documentLoader});
// or
const result = await vc.verifyCredential({credential: signedVC, suite, documentLoader});
签署陈述
一旦你创建了演示文稿(或者通过 createPresentation() 或者说
手动,可以使用 signPresentation()数字 :
import * as vc from '@digitalbazaar/vc';
const vp = await vc.signPresentation({
presentation, suite, challenge, documentLoader
});
console.log(JSON.stringify(vp, null, 2));
// ->
{
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": [
"VerifiablePresentation"
],
"verifiableCredential": [
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "http://example.edu/credentials/1872",
"type": [
"VerifiableCredential",
"AlumniCredential"
],
"issuer": "https://example.edu/issuers/565049",
"issuanceDate": "2010-01-01T19:23:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"alumniOf": "<span lang=\"en\">Example University</span>"
},
"proof": {
"type": "Ed25519Signature2018",
"created": "2020-02-03T17:23:49Z",
"jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..AUQ3AJ23WM5vMOWNtYKuqZBekRAOUibOMH9XuvOd39my1sO-X9R4QyAXLD2ospssLvIuwmQVhJa-F0xMOnkvBg",
"proofPurpose": "assertionMethod",
"verificationMethod": "https://example.edu/issuers/keys/1"
}
}
],
"id": "ebc6f1c2",
"holder": "did:ex:holder123",
"proof": {
"type": "Ed25519Signature2018",
"created": "2019-02-03T17:23:49Z",
"challenge": "12ec21",
"jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..ZO4Lkq8-fOruE4oUvuMaxepGX-vLD2gPyNIsz-iA7X0tzC3_96djaBYDxxl6wD1xKrx0h60NjI9i9p_MxoXkDQ",
"proofPurpose": "authentication",
"verificationMethod": "https://example.edu/issuers/keys/1"
}
}
验证可验证的演示文稿
先决条件:
- 您的风俗
@contexts、核查方法(如公用钥匙)及其 相应的控制器文档可以通过一个documentLoader。 。 。 .
为核实可核查的列报:
import * as vc from '@digitalbazaar/vc';
// challenge has been received from the requesting party - see 'challenge'
// section below
const result = await vc.verify({presentation, challenge, suite, documentLoader});
// {valid: true}
默认, verify() 如果出现错误,则会投出错误 proof 区域缺失.
为了验证未签名的演示文稿,您必须设置 unsignedPresentation
旗帜 :
import * as vc from '@digitalbazaar/vc';
const result = await vc.verify({
presentation, suite, documentLoader, unsignedPresentation: true
});
// {valid: true}
challenge 参数
可核查的演示文稿通常用于认证目的.
A 类 challenge parm (类似于 nonce 在 OAuth2/ OpenID 连接中提供
并阻止节目重播
攻击。 工作流程如下:
- 接收方要求提供可核实的陈述,并提供
challenge参数. - 创建 VP 的客户端代码在此挑战中通过(来自请求) 党),并被包括在"副总统"中.
- 客户端代码将VP传递给接收方,接收方随后检查到
确保
challenge与请求中提供的相同 在1页.
验证可验证的证书
在大多数情况下,可核查的全权证书将用可核查的 演示文稿和整个副总统应加以核实。 然而,这个图书馆 提供一种功能来验证可验证的证书.
先决条件:
- 您的风俗
@contexts、核查方法(如公用钥匙)及其 相应的控制器文档可以通过一个documentLoader。 。 。 .
核查可核查的证明:
const result = await vc.verifyCredential({credential, suite, documentLoader});
// {valid: true}
核查可核查的选择性披露证书,确保套件 支持,例如:
import * as ecdsaSd2023Cryptosuite from
'@digitalbazaar/ecdsa-sd-2023-cryptosuite';
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
const {
createDiscloseCryptosuite,
createSignCryptosuite,
createVerifyCryptosuite
} = ecdsaSd2023Cryptosuite;
const suite = new DataIntegrityProof({
cryptosuite: createVerifyCryptosuite()
});
const result = await vc.verifyCredential({credential, suite, documentLoader});
// {valid: true}
以习惯验证可核查的证书 @context 字段使用 a
自定义文档Loader
国 际
要在命令行上使用, 请见
vc-js-cli。 。 。 .
测试
进行Mocha测试:
npm run test-node
进行Karma(浏览器)测试:
npm run test-karma
贡献
见 贡献文件来啊!
公关接受.
注:如果编辑Readme,请遵照 标准读取 规格.
商业支助
该图书馆的商务支助可应下列请求提供: 数字集市: 支持@ digitalbazaar.com