Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for multiple signature suite #68

Merged
merged 41 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
4b18be3
Make delegate API support multiple signature suites.
JSAssassin Mar 1, 2021
f16ad79
Add documentLoader and update zcap context.
JSAssassin Mar 8, 2021
e944528
Use ed25519-signature-2020@2.
mattcollier Apr 26, 2021
6f4329c
Use ed25519-signature-2018@2.
mattcollier Apr 26, 2021
c3c6777
Remove unneeded context modules.
mattcollier Apr 26, 2021
46f0bad
Use jsonld-signatures@9.
mattcollier Apr 26, 2021
4d4a6ba
Use @digitalbazaar/zcapld@4.
mattcollier Apr 26, 2021
9d3f3cc
Update KMS related deps.
mattcollier Apr 26, 2021
ceca420
Use bedrock-security-context@4.1.
mattcollier Apr 26, 2021
8e1698f
Add FIXME related to keyStore referenceId.
mattcollier Apr 26, 2021
c3a136a
Update zcaps implementation.
mattcollier Apr 26, 2021
51b0eec
Remove logging.
mattcollier Apr 26, 2021
b52903f
Address fixme related to keyStore referenceId.
mattcollier Apr 26, 2021
6c63c51
Use bedrock-express@4 in tests.
mattcollier Apr 26, 2021
093dd98
Refactor documentLoader.
mattcollier Apr 26, 2021
fef5b8f
Update copyright notices.
mattcollier Apr 26, 2021
560465e
Use edv-client and bedrock-edv-storage branch.
JSAssassin Apr 27, 2021
d0cd497
Update zcaps in mock data.
JSAssassin Apr 27, 2021
2385dd6
Update mock delegation chain.
mattcollier Apr 27, 2021
7e854a0
Use @digitalbazaar/zcapld@4 in tests.
mattcollier Apr 27, 2021
52e74c2
Remove TODO that has been addressed.
mattcollier Apr 27, 2021
6926f91
Remove commented code.
mattcollier Apr 27, 2021
abaadf3
Add keyType to CapabilityAgent.fromSecret.
JSAssassin Apr 27, 2021
236aeb4
Change verificationMethod to publicAlias in request.
JSAssassin Apr 27, 2021
6644d2e
Remove compactProof.
JSAssassin Apr 27, 2021
4ab3f41
Add @digitalbazaar/ed25519-verification-key-2020.
JSAssassin Apr 27, 2021
1dbc3b1
Change X25519KeyAgreementKey2019 to 2020.
JSAssassin Apr 27, 2021
59bb4e4
Update changelog.
JSAssassin Apr 28, 2021
e325f37
Update did-veres-one.
JSAssassin Apr 30, 2021
2b78405
Update bedrock-did-io.
JSAssassin May 2, 2021
a2ab539
Add additional assertion to check if profileId starts with `did:v1:`.
JSAssassin May 3, 2021
0927b3d
Refactor documentLoader.
JSAssassin May 3, 2021
c7ea2c6
Remove verificationMethod from suite.
JSAssassin May 4, 2021
f2ad3e2
Use edv-client v9.0.
JSAssassin May 4, 2021
fecead1
Use webkms-client v6.0.
JSAssassin May 4, 2021
9331932
Remove forceConstruct in documentLoader.
JSAssassin May 4, 2021
863b9cb
Use crypto-ld v6.0 and bedrock-veres-one-context v11.0.
JSAssassin May 5, 2021
aff2327
Remove referenceId.
JSAssassin May 10, 2021
69ce7f8
Update changelog.
JSAssassin May 10, 2021
9dd10cf
Use bedrock-did-io@2.0.
JSAssassin May 20, 2021
30b78aa
Update changelog and use latest did-veres-one dep.
JSAssassin May 21, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Bedrock Non-Commercial License v1.0
===================================

Copyright (c) 2011-2020 Digital Bazaar, Inc.
Copyright (c) 2011-2021 Digital Bazaar, Inc.
All rights reserved.

Summary
Expand Down
2 changes: 1 addition & 1 deletion lib/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down
27 changes: 27 additions & 0 deletions lib/documentLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*!
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

const {didIo} = require('bedrock-did-io');
const {documentLoader} = require('bedrock-jsonld-document-loader');

module.exports = async url => {
let document;
if(url.startsWith('did:')) {
document = await didIo.get({did: url, forceConstruct: true});
JSAssassin marked this conversation as resolved.
Show resolved Hide resolved
mattcollier marked this conversation as resolved.
Show resolved Hide resolved
// FIXME: Remove the startsWith() logic once did-io.get() return signature
// is updated.
if(url.startsWith('did:v1:')) {
document = document.doc;
}
return {
contextUrl: null,
documentUrl: url,
document
};
}

// finally, try the bedrock document loader
return documentLoader(url);
};
2 changes: 1 addition & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down
7 changes: 5 additions & 2 deletions lib/kms.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand All @@ -12,7 +12,7 @@ const {
KeystoreAgent,
KeyAgreementKey,
KmsClient
} = require('webkms-client');
} = require('@digitalbazaar/webkms-client');
const {util: {clone, BedrockError}} = bedrock;

exports.createKeystore = async ({
Expand Down Expand Up @@ -77,6 +77,9 @@ exports.generateKey = async (
} else if(type === 'Ed25519VerificationKey2018') {
type = 'Ed25519VerificationKey2018';
Class = AsymmetricKey;
} else if(type === 'Ed25519VerificationKey2020') {
type = 'Ed25519VerificationKey2020';
Class = AsymmetricKey;
} else if(type === 'keyAgreement' || type === 'X25519KeyAgreementKey2019') {
type = 'X25519KeyAgreementKey2019';
Class = KeyAgreementKey;
Expand Down
2 changes: 1 addition & 1 deletion lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down
18 changes: 13 additions & 5 deletions lib/profileAgents.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

const assert = require('assert-plus');
const base64url = require('base64url-universal');
const bedrock = require('bedrock');
const crypto = require('crypto');
const {CapabilityAgent} = require('webkms-client');
const {CapabilityAgent} = require('@digitalbazaar/webkms-client');
const database = require('bedrock-mongodb');
const {promisify} = require('util');
const kms = require('./kms');
Expand Down Expand Up @@ -92,7 +92,11 @@ exports.create = async ({
const handle = 'primary';
// 2. Generate capability agent to represent controller of profile agent
// (and its zcap key)
const controller = await CapabilityAgent.fromSecret({handle, secret});
const controller = await CapabilityAgent.fromSecret({
handle,
keyType: 'Ed25519VerificationKey2020',
secret,
});
// 3. Create keystore in order to create the zCap key for the profile agent.
// This keystore must be in the private KMS because it is accessed by a
// capabilityAgent that is generated from a secret that is stored in the
Expand All @@ -110,7 +114,7 @@ exports.create = async ({
const keystoreAgent = kms.getKeystoreAgent(
{capabilityAgent: controller, keystore});
const key = await keystoreAgent.generateKey(
{type: 'Ed25519VerificationKey2018', kmsModule: KMS_MODULE});
{type: 'Ed25519VerificationKey2020', kmsModule: KMS_MODULE});
// 5. Use the zCap key to create the DID for the profile agent
key.id = await utils.computeKeyId({key, didMethod: 'key'});
// 6. Generate profile agent's CapabilityAgent instance
Expand Down Expand Up @@ -450,7 +454,11 @@ exports.getAgents = async ({profileAgent, secrets} = {}) => {
} = profileAgent;
const {seed} = secrets;
const controller =
await CapabilityAgent.fromSecret({handle: 'primary', secret: seed});
await CapabilityAgent.fromSecret({
handle: 'primary',
keyType: 'Ed25519VerificationKey2020',
secret: seed
});
const keystore = await kms.getKeystore({id: keystoreId});
const keystoreAgent = kms.getKeystoreAgent(
{capabilityAgent: controller, keystore});
Expand Down
10 changes: 5 additions & 5 deletions lib/profiles.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down Expand Up @@ -52,12 +52,11 @@ module.exports.create = async ({
const profileKeystore = await kms.createKeystore({
capabilityAgent: paZcapAgent,
kmsBaseUrl: publicKmsBaseUrl,
referenceId: 'primary',
});
const profileKeystoreAgent = kms.getKeystoreAgent(
{capabilityAgent: paZcapAgent, keystore: profileKeystore});
const key = await profileKeystoreAgent.generateKey(
{type: 'Ed25519VerificationKey2018', kmsModule: KMS_MODULE});
{type: 'Ed25519VerificationKey2020', kmsModule: KMS_MODULE});
// 2. Use the ProfileZcapKey to generate the Profile DID
key.id = await utils.computeKeyId({key, didMethod, didOptions});
// 3. Delegate a capability from the Profile DID to the ProfileAgent to
Expand All @@ -70,9 +69,9 @@ module.exports.create = async ({
controller: paZcapAgent.id,
invocationTarget: {
id: (await key.getKeyDescription()).id,
type: 'Ed25519VerificationKey2018',
type: 'Ed25519VerificationKey2020',
proofPurpose: 'capabilityInvocation',
verificationMethod: key.id
publicAlias: key.id
}
};
const zcap = await delegateCapability(
Expand All @@ -84,6 +83,7 @@ module.exports.create = async ({
// DID#KEY_IDENTIFIER
const profileDid = key.id.split('#')[0];
profileKeystore.controller = profileDid;
profileKeystore.referenceId = 'primary';
mattcollier marked this conversation as resolved.
Show resolved Hide resolved
await kms.updateKeystoreConfig({
keystoreAgent: profileKeystoreAgent,
keystoreConfig: profileKeystore,
Expand Down
18 changes: 13 additions & 5 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

const database = require('bedrock-mongodb');
const {LDKeyPair} = require('crypto-ld');
const {CryptoLD} = require('crypto-ld');
const v1 = require('did-veres-one');
const didKey = require('did-method-key');
const didKey = require('@digitalbazaar/did-method-key');
const {Ed25519VerificationKey2018} =
require('@digitalbazaar/ed25519-verification-key-2018');
const {Ed25519VerificationKey2020} =
require('@digitalbazaar/ed25519-verification-key-2020');

const cryptoLd = new CryptoLD();
cryptoLd.use(Ed25519VerificationKey2018);
cryptoLd.use(Ed25519VerificationKey2020);

exports.getCollection = collectionName => database.collections[collectionName];

Expand All @@ -25,13 +33,13 @@ exports.computeKeyId = async ({
key, didMethod = 'key', didOptions = {}} = {}) => {
// the keyDescription is required to get publicKeyBase58
const keyDescription = await key.getKeyDescription();
const publicKey = await LDKeyPair.from(keyDescription);
const publicKey = await cryptoLd.from(keyDescription);
let driver;
let keyId;

if(didMethod === 'key') {
driver = didKey.driver();
keyId = await driver.computeKeyId({key: publicKey});
keyId = await driver.computeId({keyPair: publicKey});
} else if(didMethod === 'v1') {
// For v1 dids, mode is set to test or live.
const mode = didOptions.mode || 'live';
Expand Down
50 changes: 34 additions & 16 deletions lib/zcaps.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

const {CapabilityDelegation} = require('ocapld');
const documentLoader = require('./documentLoader');
const {CapabilityDelegation, constants: {ZCAP_CONTEXT_URL}} =
require('@digitalbazaar/zcapld');
const {EdvClient} = require('edv-client');
const jsigs = require('jsonld-signatures');
const {Ed25519Signature2018} = require('@digitalbazaar/ed25519-signature-2018');
const {Ed25519Signature2020} = require('@digitalbazaar/ed25519-signature-2020');
const {sign} = require('jsonld-signatures');

const {SECURITY_CONTEXT_V2_URL, sign, suites} = jsigs;
const {Ed25519Signature2018} = suites;
const SUPPORTED_KEY_TYPES = [
'Ed25519VerificationKey2018',
'Ed25519VerificationKey2020',
'Sha256HmacKey2019',
'X25519KeyAgreementKey2019'
];
Expand All @@ -27,8 +30,14 @@ exports.delegateCapability = async (
'"invocationTarget" must be an object that includes a "type".');
}
// TODO: Look into requiring an invoker or controller on a zcap
JSAssassin marked this conversation as resolved.
Show resolved Hide resolved
let contextUrl;
if(signer.type === 'Ed25519VerificationKey2018') {
contextUrl = [ZCAP_CONTEXT_URL, Ed25519Signature2018.CONTEXT_URL];
} else if(signer.type === 'Ed25519VerificationKey2020') {
contextUrl = [ZCAP_CONTEXT_URL, Ed25519Signature2020.CONTEXT_URL];
}
let zcap = {
'@context': SECURITY_CONTEXT_V2_URL,
'@context': contextUrl,
// use 128-bit random multibase encoded value
id: await exports.id()
};
Expand All @@ -54,21 +63,21 @@ exports.delegateCapability = async (
zcap.expires = expires;
}
let {parentCapability} = request;
const {id: target, type: targetType, verificationMethod} = invocationTarget;
const {id: target, type: targetType, publicAlias} = invocationTarget;
if(SUPPORTED_KEY_TYPES.includes(targetType)) {
if(!target) {
throw new TypeError(
'"invocationTarget.id" must be set for Web KMS capabilities.');
}
if(!verificationMethod) {
throw new TypeError('"invocationTarget.verificationMethod" is required.');
if(!publicAlias) {
throw new TypeError('"invocationTarget.publicAlias" is required.');
}
// TODO: fetch `target` from a key mapping document in the profile's
// edv to get public key ID to set as `referenceId`
zcap.invocationTarget = {
id: target,
type: targetType,
verificationMethod,
publicAlias,
};
zcap.parentCapability = parentCapability || target;
zcap = await exports.delegate({zcap, signer});
Expand Down Expand Up @@ -184,16 +193,25 @@ exports.id = async () => `urn:zcap:${await EdvClient.generateId()}`;
exports.delegate = async ({zcap, signer, capabilityChain}) => {
capabilityChain =
Array.isArray(capabilityChain) ? capabilityChain : [zcap.parentCapability];
// attach capability delegation proof
return sign(zcap, {
// TODO: map `signer.type` to signature suite
suite: new Ed25519Signature2018({
let suite;
if(signer.type === 'Ed25519VerificationKey2018') {
suite = new Ed25519Signature2018({
signer,
verificationMethod: signer.id
}),
});
} else if(signer.type === 'Ed25519VerificationKey2020') {
suite = new Ed25519Signature2020({
signer,
verificationMethod: signer.id
});
}
// attach capability delegation proof
return sign(zcap, {
suite,
purpose: new CapabilityDelegation({
capabilityChain
}),
compactProof: false
compactProof: false,
JSAssassin marked this conversation as resolved.
Show resolved Hide resolved
documentLoader
});
};
21 changes: 13 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,26 @@
},
"homepage": "https://github.com/digitalbazaar/bedrock-profile",
"dependencies": {
"@digitalbazaar/did-method-key": "^1.0.0",
"@digitalbazaar/ed25519-signature-2018": "^2.0.1",
"@digitalbazaar/ed25519-signature-2020": "^2.1.0",
"@digitalbazaar/ed25519-verification-key-2018": "^3.1.1",
JSAssassin marked this conversation as resolved.
Show resolved Hide resolved
"@digitalbazaar/webkms-client": "digitalbazaar/webkms-client#use-webkms-context",
"@digitalbazaar/zcapld": "^4.0.0",
"assert-plus": "^1.0.0",
"base64url-universal": "^1.1.0",
"crypto-ld": "^3.7.0",
"did-method-key": "^0.7.0",
"crypto-ld": "^5.1.0",
mattcollier marked this conversation as resolved.
Show resolved Hide resolved
"did-veres-one": "^12.1.1",
"edv-client": "^6.0.1",
"jsonld-signatures": "^5.1.0",
"ocapld": "^2.0.0",
"webkms-client": "^3.0.0"
"edv-client": "digitalbazaar/edv-client#support-ed25519-signature-2020",
"jsonld-signatures": "^9.0.2"
},
"peerDependencies": {
"bedrock": "^4.1.1",
"bedrock-edv-storage": "^4.1.1",
"bedrock-did-io": "^1.0.0",
"bedrock-edv-storage": "digitalbazaar/bedrock-edv-storage#update-to-use-ed25519-2020",
"bedrock-https-agent": "^2.0.0",
"bedrock-mongodb": "^8.0.0"
"bedrock-jsonld-document-loader": "^1.0.1",
"bedrock-mongodb": "^8.2.0"
},
"directories": {
"lib": "./lib"
Expand Down
2 changes: 1 addition & 1 deletion test/mocha/10-profile-agents.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down
2 changes: 1 addition & 1 deletion test/mocha/12-profile-agents-get-by-token.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down
3 changes: 2 additions & 1 deletion test/mocha/20-profiles.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down Expand Up @@ -84,6 +84,7 @@ describe('profiles API', () => {
'id', 'sequence', 'controller', 'referenceId'
]);
a.config.controller.should.equal(profile.id);
a.config.referenceId.should.equal('primary');
});
it('should throw error if didMethod is not `key` or `v1`', async () => {
const accountId = uuid();
Expand Down
2 changes: 1 addition & 1 deletion test/mocha/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down
Loading