Coder Social home page Coder Social logo

digitalbazaar / jsonld-signatures Goto Github PK

View Code? Open in Web Editor NEW
136.0 23.0 41.0 732 KB

An implementation of the Linked Data Signatures specification for JSON-LD. Works in the browser and Node.js.

License: BSD 3-Clause "New" or "Revised" License

JavaScript 100.00%

jsonld-signatures's Introduction

JSON-LD Signatures (jsonld-signatures)

Build status Coverage status Dependency Status NPM Version

An implementation of the Linked Data Signatures specification for JSON-LD, for Node.js and browsers.

Table of Contents

Version Compatibility

jsonld-signatures v9.0 is compatible with the following signature suites:

and the following related libraries:

Background

A Linked Data Signature proof is created (or verified) by specifying a signature suite and a proof purpose.

The signature suite performs the cryptographic operation required to sign (or verify) a digital signature and includes information in a proof such as the verificationMethod identifier, the proof's controller, and the date the proof was created.

The proof purpose indicates why the proof was created and what its intended use is. This information can also be used to make sure that the verificationMethod was authorized for the stated purpose in the proof. Using a proof purpose helps to encourage people to authorize certain cryptographic keys (verification methods) for explicit purposes rather than granting them ambient authority. This approach can help prevent people from accidentally signing documents for reasons they did not intend.

This library provides base classes for signature suites and proof purposes so that custom extensions can be written. It also provides some commonly used proof purposes.

Relationship to Verifiable Credentials

jsonld-signatures is a low-level library that is meant to sign any JSON-LD document.

One common use case for creating these signatures is for use with Verifiable Credentials (VCs). If you're working with those, you should use a higher-level library that's specifically made for that purpose, such as vc-js. (Incidentally, vc-js uses this library, jsonld-signatures, under the hood.)

Security

As with most security- and cryptography-related tools, the overall security of your system will largely depend on your design decisions (which key types you will use, where you'll store the private keys, what you put into your credentials, and so on).

Document Loader

During verification, the key and key controller information must be discovered. This library allows for the key and key controller information to be looked up via a documentLoader or it can be provided directly to the API via the signature suite or proof purpose, respectively.

This library's default documentLoader is very strict for security and content integrity purposes. It will only load locally available copies of the context documents that define the terms it uses internally. Any attempt to load any other documents (including other contexts) will throw an error. If other documents such as verification methods (e.g., public key documents), cannot be provided directly to the API and thus need to be loaded, a custom document loader must be passed. For the sake of clarity, the default document loader will only load locally available copies of the following documents:

If you require other documents to be loaded then you will need to provide a documentLoader that can provide them. jsonld.js provides both a node and browser documentLoader you can use, however, depending on your use case, you may increase security by using a custom documentLoader that is similarly strict and will only load a subset of documents that is constrained by some technical, security, or business rules.

Install

  • Browsers and Node.js 14+ are supported.

To install from NPM:

npm install jsonld-signatures

To install locally (for development):

git clone https://github.com/digitalbazaar/jsonld-signatures.git
cd jsonld-signatures
npm install

Usage

jsonld-signatures (version 8.x and above) is not meant for standalone use. Instead, it's generally used through an individual crypto suite. For detailed usage instructions, see the READMEs of the supported suites:

Most of the usages with individual suites and key types will have elements in common. You'll need to:

  • Generate or import cryptographic keys to sign with (see the @digitalbazaar/crypto-ld >=v5.0) library), or use a secure signer() function provided by your secure cryptographic module.
  • Authorize those keys for the specific purpose you're using them for (see section on Proof Purpose below), using a Controller Document (such as a DID Document or similar).
  • Pair those keys with a corresponding cryptographic Signature Suite. For greenfield development, we recommend the Ed25519Signature2020 suite, and for legacy/compatibility work, you can use Ed25519Signature2018 suite. See also the Choosing a Key Type section of crypto-ld documentation.
  • Set up your documentLoader to fetch contexts and documents securely.
  • Lastly, perform the jsigs.sign() or jsigs.verify() operations.

Node.js Native Canonize Bindings

Specialized use cases may wish to use the native canonize bindings. This mode can be enabled by setting the useNativeCanonize option to true. See the jsonld.js notes on this feature and note you should benchmark performance before using it.

Contribute

See the contribute file!

PRs accepted.

If editing the Readme, please conform to the standard-readme specification.

Commercial Support

Commercial support for this library is available upon request from Digital Bazaar: [email protected]

License

New BSD License (3-clause) © Digital Bazaar

jsonld-signatures's People

Contributors

aljones15 avatar cwebber avatar davidlehn avatar dlongley avatar dmitrizagidulin avatar ender503 avatar gannan08 avatar harlantwood avatar kimdhamilton avatar mattcollier avatar msporny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsonld-signatures's Issues

Remove `trust` checking builtins in next version

Any code related to checking whether or not a key or key owner/controller is trusted should be deprecated and removed in the next major version. The next major version should return the key and key key owner/controller/verification parameters that were used to verify a signature to allow the caller to use it in a secondary trust checking step. This will make implementations simpler and remove the need for passing some of the more complex/custom handler functions into the verify call.

Security issue in EcdsaKoblitzSignature2016 codepaths

Tracking as security issue; PR is available.

There is an issue with the EcdsaKoblitzSignature2016 codepaths. _getDataToHash returns an empty string if options.algorithm is EcdsaKoblitzSignature2016. That means it's currently signing (and verifying) the empty message.

This is a security issue for any callers using the EcdsaKoblitzSignature2016 codepath, as any message given to it gets dropped. I.e. when signing, the input message is dropped and the empty message is signed. If the same signed message is tampered with, then it will also continue to verify. Again, this is because the message is being dropped during _getDataToHash, and the empty message will verify.

PR is here: #19

Support for nonce fails

Versions:

"jsonld": "1.0.2",
"jsonld-signatures": "2.3.0"

There are no existing tests to add a nonce to the signing options. When I set my signing options to

export const SigningOptions = {
  privateKeyPem: testPrivateKeyPem,
  algorithm: 'RsaSignature2018',
  creator: TestPublicKeyUrl,
  nonce: 'This-is-a-nonce',
}

Signing fails with Error: The nonce is invalid. As soon as I remove the nonce from the options, the library signs the document correctly.

I added the following to the tests and values to the tests/test-common.js file to verify. The first test passes, the second fails.

index 8108bf5..f968270 100644
--- a/tests/test-common.js
+++ b/tests/test-common.js
@@ -681,6 +681,7 @@ describe('JSON-LD Signatures', function() {

       var testDocument;
       var testDocumentSigned;
+      var testDocumentWithNonceSigned;
       var testDocumentSignedAltered;
       var testDocumentWithProofPurposeSigned;
       var testInvalidPublicKey;
@@ -721,6 +722,22 @@ describe('JSON-LD Signatures', function() {
         testDocumentSignedAltered = clone(testDocumentSigned);
         testDocumentSignedAltered.name = 'Manu Spornoneous';

+        testDocumentWithNonceSigned = clone(testDocument);
+        testDocumentWithNonceSigned
+          ["https://w3id.org/security#proof"] = {
+          "@graph":{
+            "@type":"https://w3id.org/security#RsaSignature2018",
+            "http://purl.org/dc/terms/created": {
+              "@type":"http://www.w3.org/2001/XMLSchema#dateTime",
+              "@value":"2018-08-09T00:41:58Z"
+            },
+            "http://purl.org/dc/terms/creator": {
+              "@id":"https://example.com/i/alice/keys/1"
+            },
+            "https://w3id.org/security#jws" : "eyJhbGciOiJQUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..UeLIzScbCKv8czp-qiGMQ_OjhL_ZtilK--ChgkLjpXRKAKcahXGtU8QGz31ryWsSM3mbAdDj4jl74v9kLpc6UkNoYxf2GDq-gmr_3PU7JExnPznVwedRC7FvvvDlPrNFwDkhU8m2lYAtD62RrKhgv_qMorGdVCIv9CnrQ1Swh90",
+            "https://w3id.org/security#nonce":"this-is-a-nonce"}
+        };
+
         testProofPurpose = 'https://example.org/special-authentication';
         testDocumentWithProofPurposeSigned = clone(testDocument);
         testDocumentWithProofPurposeSigned
@@ -783,6 +800,41 @@ describe('JSON-LD Signatures', function() {
         });
       });

+      it('should successfully sign a local document w/nonce', function(done) {
+        jsigs.sign(testDocument, {
+          algorithm: 'RsaSignature2018',
+          creator: testPublicKeyUrl,
+          privateKeyPem: testPrivateKeyPem,
+          nonce: 'this-is-a-nonce'
+        }, function(err, signedDocument) {
+          assert.ifError(err);
+          assert.notEqual(
+            signedDocument['https://w3id.org/security#proof'], undefined,
+            'signature was not created');
+          assert.equal(
+            signedDocument['https://w3id.org/security#proof']
+             ['@graph']['https://w3id.org/security#nonce'],
            'this-is-a-nonce',
+            'nonce was not added to signature');
+          done();
+        });
+      });
+
+      it('should successfully verify a document w/nonce', function(done){
+        jsigs.verify(testDocumentWithNonceSigned, {
+          publicKey: testPublicKey,
+          publicKeyOwner: testPublicKeyOwner,
+          // timestamp is quite old, do not check it, it is used to ensure
+          // a static document is being checked
+          checkTimestamp: false
+        }, function(err, result) {
+          assert.ifError(err);
+          assert.equal(result.verified, true, 'signature verification failed');
+          done();
+        });
+      });
+

yields:

66 passing (629ms)
1 failing

1) JSON-LD Signatures
       with NO security context
         signing and verify RsaSignature2018
           should successfully verify a document w/nonce:

      signature verification failed
      + expected - actual

      -false
      +true

Support of (and examples of) secp256k1 keys?

This repo is the current best reference implementation of Linked Data Proofs/Signatures. Does it support secp256k1, or is that feature only in other repositories. The README.md does not say.

The BTCR and Ethererum DID communities need some valid examples of JSON-LD Proofs/Signatures signed by secp256k1 keys where we have the private keys to test against.

-- Christopher Allen

Unable to override security context

When I change:

"sec": "https://w3id.org/security#",

to

"sec": "https://identity.foundation/context/security#",

Linked Data Signatures no longer work:

Error: No matching proofs found in the given document.

However... that does not make any sense, since I am just trying to define vocabulary.

I can see in the documentation:

   * Important note: This method assumes that the term `proof` in the given
   * document has the same definition as the `https://w3id.org/security/v2`
   * JSON-LD @context.

This means that in order to properly override the security context, I need to hack node modules and edit security vocab...

This seems like a lot of work to get the document loader to behave as expected...

What is the best way of overriding the security context without editing node_modules?

I don't think its possible to do given the current module structure:

const contexts = require('./contexts');

If you are trying to use a customDocumentLoader, you should be able to control how https://w3id.org/security/v2 is loaded... it should not be using a bundled module.

`ControllerProofPurpose` should have the option to accept `publicKey` term

A controller document that specifies a key as being authorized as a publicKey (which means it can be used for any purpose that a public key can be used for) should not trigger an error when ControllerProofPurpose (or any derivatives) is used. It is more secure for a controller document to link public keys via specific proof purpose relations (i.e., authorize keys for specific purposes), but it isn't a hard requirement. So we need to fix up the framing call that only looks for a verification method (public key) under the specific proof purpose term and instead allow for the term publicKey as well.

Fix Security Context Hosting and Documentation

I propose we change the ownership of https://www.npmjs.com/package/security-context

To not be github.com/w3c-dvcg/security-vocab and instead be digitalbazaar.

We should turn on github pages hosting for the repo above (after its ownership is changed), and use this repo as the central source of truth for jsonld security contexts.

If digitalbazaar will not host the security contexts and human documentation used for jsonld signatures, we should move to the ccg, but add some language around ownership and code responsibility, along with a process for addressing when documentation is marked as sufficiently out of date to warrant marking as deprecated.

Its not safe to recommend implementations with out of date documentation, we need to align incentives to fix this issue.

I'm happy to help with this.

Is it possible to create proof chains?

I would like to create proof chains where multiple parties can sign a proof. For example: If a party is transferring ownership of an asset to another party and both parties need to sign the contract. Is it possible to use proof chains?

Please let me know if there is a way to post questions instead of issues. Thanks.

Switch to more standard bitcore-message

Currently we have in our dependencies:

    "bitcore-message": "github:CoMakery/bitcore-message#dist",

"bitcore-message": "github:CoMakery/bitcore-message#dist",

This was necessary to get a browser bundle which gave us access to Bitcore as well as BitcoreMessage. Including both does not work, by design.

Solution: create a PR in their repo, and use that version instead.

Add documentation for ProofPurposes.

There are a number of ProofPurposes in lib/purposes/. The main documentation should list each and explain what they are for and when to use them.

Readme example out of date

"jsonld-signatures": "^4.4.0",

Signature verification error: Error: Could not verify any proofs; no proofs matched the required suite and purpose.

The following code with corrected keys for reproducing:

const jsigs = require("jsonld-signatures");
const { Ed25519KeyPair } = require("crypto-ld");
const { Ed25519Signature2018 } = jsigs.suites;
const { AssertionProofPurpose, AuthenticationProofPurpose } = jsigs.purposes;

const { documentLoaders } = require("jsonld");

const publicKeyBase58 = "J5QHWFQNREPBnmwCDXZgzy5FjvDGFkLEgWVoEociTfXz";
const privateKeyBase58 =
  "2zFSMA9EHEuEfFNydcMehd8a11PjFwKdTTkHaXKEvoajSAKAMi1zny5Bob4eCgWYUNa7RTkkYydz6CBAS6eqGmLg";

// specify the public key object
const publicKey = {
  "@context": jsigs.SECURITY_CONTEXT_URL,
  type: "Ed25519VerificationKey2018",
  id: "https://example.com/i/alice/keys/2",
  controller: "https://example.com/i/alice",
  publicKeyBase58
};

// specify the public key controller object
const controller = {
  "@context": jsigs.SECURITY_CONTEXT_URL,
  id: "https://example.com/i/alice",
  publicKey: [publicKey],
  // this authorizes this key to be used for authenticating
  authentication: [publicKey.id]
};

// create the JSON-LD document that should be signed
const doc = {
  "@context": {
    schema: "http://schema.org/",
    action: "schema:action"
  },
  action: "AuthenticateMe"
};

describe("ed25519", () => {
  it("sign verify", async () => {
    const signed = await jsigs.sign(doc, {
      suite: new Ed25519Signature2018({
        verificationMethod: publicKey.id,
        key: new Ed25519KeyPair({ privateKeyBase58, publicKeyBase58 })
      }),
      purpose: new AuthenticationProofPurpose({
        challenge: "abc",
        domain: "example.com"
      })
      //   compactProof: false
    });

    console.log("Signed document:", signed);
    // we will need the documentLoader to verify the controller
    const { node: documentLoader } = documentLoaders;

    // verify the signed document
    const result = await jsigs.verify(signed, {
      documentLoader,
      suite: new Ed25519Signature2018({
        key: new Ed25519KeyPair({ publicKeyBase58 })
      }),
      purpose: new AuthenticationProofPurpose({
        controller,
        challenge: "abc",
        domain: "example.com"
      })
      //   compactProof: false
    });

    if (result.verified) {
      console.log("Signature verified.");
    } else {
      console.log("Signature verification error:", result.error);
    }
  });
});

Can't resolve 'bitcore-lib'

I have been using jsonld-signatures for a project I have been working on for some time now. It has involved signing and verifying documents in the browser and has been working fine for a while. However, I recently noticed that when I pull a new instance of my repo to test out the experience of a new user, I am running into the following error at launch time:

ERROR in ./node_modules/jsonld-signatures/node_modules/bitcore-message/lib/message.js
Module not found: Error: Can't resolve 'bitcore-lib' in './node_modules/jsonld-signatures/node_modules/bitcore-message/lib'

I am wondering if this is a relatively new issue attributed to any recent changes made by the team or if anyone else has come across an issue like this. I am willing to share more details and potentially even the project repo for those that are interested in exploring this problem and desire more context.

How a document is resolved and signed?

Hey team,

Great work, However I am a bit confused how a document (object in JS) is serialized and signed. Maybe someone can clear this up?

  1. Do you first have to resolve any @ ie @context?
    Hypothetically couldn't this loop forever if data points back to itself..

  2. How do I know what to sign? It could be the K:V's in alphabetical order then concatenated together? Or a space free JSON blob?
    not sure where in the W3C model or docs this is simply explained

I am hoping to verify a signature from a Rust application and don't know exactly what bytes to check!

Thanks 😀

Add some protections around `sign` invocation

https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/suites/JwsLinkedDataSignature.js#L96

If the provided sign implementation fails silently and return undefined then this is currently throwing an obscure error in the base64 encoding routine that expects data to be an object etc. I think we should test that a valid result has been returned before moving it along the pipeline and throw a meaningful error if not.

Also, since a signer may be associated with arbitrary code, this call should probably be wrapped and errors repackaged or suppressed in some way to provide useful errors and prevent potential leakage private data if a signer is not well implemented.

Design and implement EdDSA signature suite

@tarcieri wrote:

New protocols should NOT be using ECDSA. ECDSA has repeatedly failed in practice, has many failure modes modern signature schemes are not vulnerable to, and now that the Schnorr patents have expired is completely obsolete.
In all of my personal and professional work we are using EdDSA, which is a Schnorr scheme and standardized in RFC 8032.

We've had multiple requests for supporting EdDSA, specifically Ed25519. To implement this, we'd need an implementation of it in https://github.com/digitalbazaar/forge/ and then a simple signature suite to use it in the Linked Data Signatures spec.

UnhandledPromiseRejectionWarning: Error: A URL "https://www.w3.org/ns/did/v1" could not be fetched; you need to pass "documentLoader" or resolve the URL before calling

(node:29197) UnhandledPromiseRejectionWarning: Error: A URL "https://www.w3.org/ns/did/v1" could not be fetched; you need to pass "documentLoader" or resolve the URL before calling "sign".
at Object.sign (/root/did/json-ld-signature/node_modules/jsonld-signatures/lib/jsonld-signatures.js:26:19)
at
at process._tickCallback (internal/process/next_tick.js:188:7)
at Function.Module.runMain (module.js:695:11)
at startup (bootstrap_node.js:188:16)
at bootstrap_node.js:609:3
(node:29197) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)
(node:29197) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Signing and verifying a document to authenticate to a website: << I am not sure why the error is happening in the example here.

Signed document: { '@context': { schema: 'http://schema.org/', action: 'schema:action' },
action: 'AuthenticateMe',
'https://w3id.org/security#proof':
{ '@graph':
{ '@type': 'https://w3id.org/security#Ed25519Signature2018',
'http://purl.org/dc/terms/created': [Object],
'https://w3id.org/security#challenge': 'abc',
'https://w3id.org/security#domain': 'example.com',
'https://w3id.org/security#jws':
'eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..GHywrD9bxIP0_a580kathyOFBUlp3O8vuwMUzwTNH59eeDZh1-v-8uWWwoo31nezb_i4kDIjs2TLzJyoFKZQCw',
'https://w3id.org/security#proofPurpose': [Object],
'https://w3id.org/security#verificationMethod': [Object] } } }
Signature verification error: [ Error: Invalid signature.
at Ed25519Signature2018.verifyProof (D:\nodejs workspace\jsonld_Test\node_modules\jsonld-signatures\lib\suites\LinkedDataSignature.js:162:15)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:757:11)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3) ]

I have an error in the signature validation part, but I do not know why the error occurred.

Optimize `createVerifyData` in LinkedDataSignature

In this method we compact and then canonize:

async createVerifyData(input, options) {
// TODO: frame before getting signature, not just compact? considerations:
// should the assumption be (for this library) that the signature is on
// the top-level object and thus framing is unnecessary?
const jsonld = this.injector.use('jsonld');
const opts = {expansionMap: options.expansionMap};
if(options.documentLoader) {
opts.documentLoader = options.documentLoader;
}
const compacted = await jsonld.compact(
input, constants.SECURITY_CONTEXT_URL, opts);
// TODO: will need to preserve `proof` when chained signature
// option is used and implemented in the future
// delete the existing proofs(s) prior to canonicalization
delete compacted.proof;
// ensure signature values are removed from proof node
const proof = await this.sanitizeProofNode(options.proof, options);
// concatenate hash of c14n proof options and hash of c14n document
const c14nProofOptions = await this.canonize(proof, options);
const c14nDocument = await this.canonize(compacted, options);
return {
data: this._sha256(c14nProofOptions).getBytes() +
this._sha256(c14nDocument).getBytes(),
encoding: 'binary'
};
}

Instead, we could expand, store the expanded value, then compact w/expansion flag turned off and then canonize with expansion turned off, eliminating an extra expansion step by reusing the expanded data.

TODO/FIXME Count 10

  • FIXME: forge supports alternative alphabets now -- use that instead?
    Commit: (3cbcc73) Update test suite and fix related bugs.
    File: lib/util.js:214
    Dave Longley commented a year ago

  • FIXME: forge supports alternative alphabets now -- use that instead?
    Commit: (363eade) Reorganize suites and rework APIs and internals.
    File: lib/util.js:191
    Dave Longley commented a year ago

  • TODO: only require dynamically as needed or according to build
    Commit: (74e1a97) Move suites and utilities to a separate module.
    File: lib/suites.js:9
    Dave Longley commented a year ago

  • TODO: only require dynamically as needed or according to build
    Commit: (2a16a2d) Add CustomSuite test and reorganize exposed suites/purposes.
    File: lib/purposes.js:9
    Dave Longley commented a year ago

  • TODO: support ProofChain
    Commit: (363eade) Reorganize suites and rework APIs and internals.
    File: lib/jsonld-signatures.js:14
    Dave Longley commented a year ago

  • TODO: consider in-place editing to optimize
    Commit: (7ca93f8) Compact input to security context for consistency.
    File: lib/ProofSet.js:301
    Dave Longley commented a year ago

  • TODO: consider in-place editing to optimize when compactProof
    Commit: (fb60a05) Reimplement proofTermDefined as compactProof.
    File: lib/ProofSet.js:240
    Dave Longley commented a year ago

  • TODO: optimize to modify document in place to maximize optimization
    Commit: (7ca93f8) Compact input to security context for consistency.
    File: lib/ProofSet.js:96
    Dave Longley commented a year ago

  • TODO: implement
    Commit: (363eade) Reorganize suites and rework APIs and internals.
    File: lib/ProofChain.js:7
    Dave Longley commented a year ago

  • FIXME: hack to ensure delay is set first
    Commit: (c3e9059) use webpack and karma.
    File: tests/test-karma.js:15
    David I. Lehn commented 3 years ago

EcdsaKoblitzSignature2016 tests mix public keys and addresses dangerously

publicKeyWif: '1LGpGhGK8whX23ZNdxrgtjKrek9rP4xWER'

Looking around I can see a couple instances of EcdsaKoblitzSignature2016, that support hex encoded public keys.

IMO, EcdsaKoblitzSignature2016 should not have anything to do with bitcoin, and reliance on bitcoin names or formats should be minimized.

ecdsa-koblitz-pubkey:1LGpGhGK8whX23ZNdxrgtjKrek9rP4xWER should be discouraged but remain supported, since tests are often what developers will look at it might be best to update to match https://json-ld.org/playground/ Signed with Bitcoin example.

ecdsa-koblitz-pubkey:02234be9bcdf041f7530979b8b88b7dc62dd505a75883c8211f3a8250534f96dc0

A DID example: https://gist.github.com/Exulansis/903ab4a77b4173c2268f7a0ef90521ac#did-document-example

IMO the preferred public key format for EcdsaKoblitzSignature2016 should be publicKeyHex

Livenet addresses should be assumed for verification purposes.

Post Install fix for 4.6.0

"postinstall": "sed -i.bak 's/ controllerId = controller;/else{controllerId = controller}/g' node_modules/jsonld-signatures/lib/purposes/ControllerProofPurpose.js"

I think this may be needed in the latest version.

Getting Public key not found.

I have created a signed document using jsig.sign and the output document is signedDocument

Now here is the problem . When i try to verify the same it gives me an erro saying Public key not found.

jsig.verify(signedDocument, {
			    publicKey: publicKey,
			    publicKeyOwner: publicKeyOwner
			  }, function(err, verified) {
			    if(err) {
			      return console.log('Signature verification error:', err);
			    }
			    console.log('Signature is valid:', verified);
			  });

What am i missing here.
Please find the values which i am using down below

let publicKeyPem = "-----BEGIN PUBLICKEY-----\r\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyFrXjLpXVOh5jghxbtJs\r\nTu/LOTqshrb+Py7ULtN7uIdLzIyflQwExlyUO/dX8qOrK6k046m0aRuUPZVDvfoz\r\nako/BWsYyVXQgrv0pwLmULGOYg9aLXnbSq76sVsxOMz9BxXkVCWp74mIJOvmeclL\r\n5bbY1Svks0u1DidaUU7yuavpS8LUXNzcEOEgJBLc9ZhsKKKLK3d0i2V0Vwk2+AYT\r\nzF0Tkwq2/XCrpTevLEsKcyaUbzrEmtw5/221vS5vgLBASA2fvkak7VhHJpK0vBYK\r\ngq8X+bY+xJX9Nkh2k4cIS74XgypcP6fDe8cvXskB3IHCMy3I3BJc7BkGbPJwlzUZ\r\n3QIDAQAB\r\n-----END PUBLIC KEY-----\r\n";
let privateKeyPem = "-----BEGIN RSA PRIVATE KEY-----\r\nMIIEowIBAAKCAQEAyFrXjLpXVOh5jghxbtJsTu/LOTqshrb+Py7ULtN7uIdLzIyf\r\nlQwExlyUO/dX8qOrK6k046m0aRuUPZVDvfozako/BWsYyVXQgrv0pwLmULGOYg9a\r\nLXnbSq76sVsxOMz9BxXkVCWp74mIJOvmeclL5bbY1Svks0u1DidaUU7yuavpS8LU\r\nXNzcEOEgJBLc9ZhsKKKLK3d0i2V0Vwk2+AYTzF0Tkwq2/XCrpTevLEsKcyaUbzrE\r\nmtw5/221vS5vgLBASA2fvkak7VhHJpK0vBYKgq8X+bY+xJX9Nkh2k4cIS74Xgypc\r\nP6fDe8cvXskB3IHCMy3I3BJc7BkGbPJwlzUZ3QIDAQABAoIBAGY30pj9yOiM4tdP\r\n/29m89MiDDDaeoMQgY6CucZaJ1jxzf5CEHjedOEvAoHFo50rW30fCtjMEDs/0tXI\r\nfZNDP1APKS/+f9rYaVUJx7wdgpvQuq/U3VEuRm9H7qblu6sbCky/Ioq73INVS5xq\r\nrl+cD5jXPLElf7zp9ymNckrhWHzZDS2ss7Jfw7OxmEUzKkgoF+oRswG0yFHcn6Rx\r\nO0pVIGSnpHJsgNKuUOq3QtUXucSDAfAAwxdMX173WHtVOABT/PHs8RtSpbpan20H\r\nFaLLx9c5C7XwaOmNnvkxImVaT2rh0P5UwejKw01zTHvoe7eOtCLBYipxYIibGj5F\r\nb8QMZ4ECgYEA6Zt59GYR/RWmSQ2AYq95iRE8goax2GPmrKzlD+qvi5/WKVyy43z3\r\nlP62IZwkv1G9F1damZwbVNpnjOYu4TJ4gY9k97bdK0HG7UGl2JZBPu3KhCr/PV4w\r\nqTWh7RwbK+nl24MO1tz4WFkkuNrcVP0GVfYxw/DdvZDiScCa7RGlkSkCgYEA249g\r\n2CGE96OhZ+VE6CIl3oL5ZXGoxpTKgXZgjGVSh5vpjT9e0ImTTqBRfUxTI2BnNB6v\r\nPCz4xDoijcL0wAegKzajbUGaSNhe1fYl9NkqEUsUBlMb1X+U0xPaHR/bbJ64FBA7\r\n3CLbLo5bFx9Xp1RUxorK61Epc7MU54nj8o8dVZUCgYAJL4znGFBixEQqoTZIKyA7\r\nTIs1krhRivQaHB5Rtue6NMnGDJgYK+TMXgupXKtxPnSSA2RTn/jPKFtkBfUX89Ub\r\nOxk8SFuABPEeiTNNRfNA1zbcZZhtwFNng+1fFnjXDDZ2oDuoJT46sx6niiuZx+1E\r\n2g5w5vrBJn5PahxtcAEzqQKBgEWmaDxn9bxxRiSlUISrQIQj3GXX9oh4bv0+xkYD\r\nZnjqdt59+eABpJ9OsEslSUJxtIuOKFzYj1oAbzG1ZNr+EEtlG9bu9rihGwSY/1V7\r\nBqNRw9p1xuClhlqnc4vFrV/5wb9rnvGohQtx0We2Y6ILWJFbOiAIMTQo3TrOPWeX\r\nCuE5AoGBANYbw1M5D0D3nfrPjsojkFBsb5pFrN3rL5bhVUBG9Rh3vBxX5RZlIOaF\r\nIT8o1j+NTaZIMo3A32vm2kdwTU4sZDGVDgFELhKOgfB5FBledw/MxMYt4QbuewuP\r\nUScpFQzu5a8YmaASN5mOAfW7VXY+99fFCxsP/DG7KKK2Z1xhjqpI\r\n-----END RSA PRIVATE KEY-----\r\n";

// specify the public key object
let publicKey = {
  "@context": "https://schema.org/",
  "@id": "did:v1:test:nym:nmR9EvCsQ8Jj-OTC7LD9Mb0q5mHqKj_4f75myaR3i5M#authn-key-1",
  "owner": "did:v1:test:nym:nmR9EvCsQ8Jj-OTC7LD9Mb0q5mHqKj_4f75myaR3i5M",
  "publicKeyPem": publicKeyPem
};

// specify the public key owner object
let publicKeyOwner = {
  "@context": "https://schema.org/",
  "@id": "did:v1:test:nym:nmR9EvCsQ8Jj-OTC7LD9Mb0q5mHqKj_4f75myaR3i5M",
  "publicKey": [publicKey]
};

EcdsaKoblitzSignature2016 vs EcdsaPublicKeySecp256k1 Signature Encoding

Its not clear enough how signatures from ethereum / bitcoin private keys are formed.

https://w3c-dvcg.github.io/lds-koblitz2016/#examples

As people encode the result of signatures differently:

https://github.com/uport-project/did-jwt/blob/develop/src/SimpleSigner.js#L27

https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/suites/EcdsaKoblitzSignature2016.js#L24

https://bitcoin.stackexchange.com/questions/38351/ecdsa-v-r-s-what-is-v

https://github.com/ethereumjs/ethereumjs-util/blob/master/index.js#L351

IMO, the part that is missing is the description of how a standard secp256k1 signature should be encoded.

it seems implied that signatureValue is b64 result of secp256k1.sign, which is a concatenation of v,r,s, this should be stated explicitly somewhere to discourage custom encodings.

IMO the signature implementation in this repo would be better if it did not reference bitcoin or ethereum, but was a pure function of secp256k1 and clearly demonstrated the encoding format for signatures, instead of relying on bitMessage.

Here is an example of a clear implementation:

https://github.com/tootsuite/mastodon/blob/cabdbb7f9c1df8007749d07a2e186bb3ad35f62b/app/lib/activitypub/linked_data_signature.rb#L30

Feel free to close this, if its in the wrong place.

Found my answer here:

https://www.reddit.com/r/crypto/comments/7ty5sd/why_does_ecdsakoblitzsignature2016_use_a_magic/

There does not appear to be a linked data signature format for secp256k1 that is not tied to bitcoin or ethereum... seems like this should not have had its name changed here: #10

Since it relies on https://bitcoin.stackexchange.com/questions/68844/explicit-message-length-in-bitcoin-signed-message

https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/suites/EcdsaKoblitzSignature2016.js#L23

https://github.com/ethereumjs/ethereumjs-util/blob/master/index.js#L370

Its worth noting that the spec does not describe any of this behavior. I'd avoid using EcdsaKoblitzSignature2016 because of this ambiguity.

Error: jsonld.InvalidUrl: Dereferencing a URL did not result in a valid JSON-LD object

I have the JSONLD context published and it is valid. below is my code i use to generate signed JSONLD document . I am not sure why I am getting the error.

async function ReviewToJsonLd(doi,ref,soi,runsuccess,rep,notes){

console.log('Starting review...');

const publicKeyBase58 = 'B2NGCFsAJwW9ZamkW9bEDVQo57NniRYhtvLYDVqdpR7A';
const privateKeyBase58 = 'pkeyhere';

//specify public key object
const publicKey = {
  '@context': jsigs.SECURITY_CONTEXT_URL,
  type: 'Ed25519VerificationKey2018',
  id: 'http://www.facultylab.xyz/did.json',
  controller: 'did:web:facultylab.xyz',
  publicKeyBase58
};

//specify public key controller object
const controller = {
  '@context': jsigs.SECURITY_CONTEXT_URL,
  id: 'http://www.facultylab.xyz/did.json',
  publicKey: 'B2NGCFsAJwW9ZamkW9bEDVQo57NniRYhtvLYDVqdpR7A',
  // this authorizes this key to be used for authenticating
  assertionMethod: publicKey.id
};

const doc = fs.readFileSync("./reviewtoJSONLD.json").toString();
console.log(doc);
const docToSign = JSON.parse(doc);
console.log(docToSign);

//const {Ed25519Signature2018} = jsigs.suites;
//const {Ed25519KeyPair} = require('crypto-ld');
const {documentLoaders} = require('jsonld');
//const {AssertionProofPurpose} = jsigs.purposes;

 const signingSuite = new Ed25519Signature2018({
 
  //verificationMethod: getAssertionMethod(issuerKeyDid),
  purpose: new AssertionProofPurpose(),
  key: reviewerKeyPair,
  verificationMethod: reviewerKeyPair.id
});


const signed = await jsigs.sign(docToSign, {
suite: signingSuite,
documentLoader: documentLoader,
purpose: new AssertionProofPurpose()});
console.log('Signed document:', signed);

}

Document Loader code

if (url.startsWith("http://"))
  {
    console.log("here in http:// -------Pulling from: ", url, "\n")
    let docString = await downloadPage(url)
    let doc = JSON.parse(docString);

//    console.log("Fetched from ", url, ":\n", doc, "\n")

    return {
      contextUrl: null,
      documentUrl: url,
      document: doc
    };
  }

JSONLD Context

{
	"@context": {
		"@version": 1.1,
		 "@protected": true,
		"name": "http://schema.org/name",
		"description": "http:/schema.org/description",
		"ReviewerSource": {
			"dateOfExpiration": "schema:dateModified",
			"reviewer": "schema:identifier",
			"name": "schema:accountId"
		},
		"claim": {
			"reviewer": "schema:identifier",
			"dateOfSubmission": "schema:dateCreated",
			"referencesExist": "schema:value",
			"soiExists": "schema:value",
			"taleRunSuccess": "schema:value",
			"TaleRunReproduced": "schema:value",
			"DOIofSubmission": "schema:identifier"
		},
		"id": "@id",
		"issued": "schema:dateCreated",
		"issuer": "schema:identifier"
	}
}

reviewToJSONLD.json

{
  "@context":
   [ "https://w3id.org/security/v2",
     "http://www.facultylab.xyz/custContext.jsonld"],
   "ReviewerSource": {
    "dateOfExpiration": "2020-01-17T00:00:00Z",
    "dateOfIssue": "2018-12-19T09:41:15-05:00",
    "reviewer": "did:web:facultylab.xyz",
    "name": "Reviewer1_Submission"
  },
  "claim": {
    "reviewer": "did:web:facultylab.xyz#z6MkpUdJnW7beUzcg5cTBiZ54axntgee8Jo4awFU3moejdtY",
    "dateOfSubmission": "2016-12-09T00:00:00.000Z",
    "referencesExisti":"Yes",
    "soiExists": "Yes",
    "taleRunSuccess": "Yes",
    "TaleRunReproduced": "Yes",
    "DOIofSubmission" : "testid"
  },
  "id": "did:web:facultylab.xyz#z6MkpUdJnW7beUzcg5cTBiZ54axntgee8Jo4awFU3moejdtY",
  "issued": "2018-12-19T09:41:15-05:00",
  "issuer": "did:web:facultylab.xyz",
  "proofName": "ProofOfExistence",
  "type": "ProofOfExistence"
  
}

Make integrating jsonld-signatures into projects easier

@msporny ... Running the following is resulting in an error. Can you help?

var jsonld = require('jsonld')();
var jsig = require('jsonld-signatures')(jsonld);

var testPublicKeyUrl = 'https://example.com/i/alice/keys/1';
var testPublicKeyPem =
  '-----BEGIN PUBLIC KEY-----\r\n' +
  'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4R1AmYYyE47FMZgo708NhFU+t\r\n' +
  '+VWn133PYGt/WYmD5BnKj679YiUmyrC3hX6oZfo4eVpOkycxZvGgXCLQGuDp45Xf\r\n' +
  'Zkdsjqs3o62En4YjlHWxgeGmkiRqGfZ3sJ3u5WZ2xwapdZY3/2T/oOV5ri8SktTv\r\n' +
  'mVGCyhwFuJC/NbJMEwIDAQAB\r\n' +
  '-----END PUBLIC KEY-----';
var testPrivateKeyPem = '-----BEGIN RSA PRIVATE KEY-----\r\n' +
  'MIICWwIBAAKBgQC4R1AmYYyE47FMZgo708NhFU+t+VWn133PYGt/WYmD5BnKj679\r\n' +
  'YiUmyrC3hX6oZfo4eVpOkycxZvGgXCLQGuDp45XfZkdsjqs3o62En4YjlHWxgeGm\r\n' +
  'kiRqGfZ3sJ3u5WZ2xwapdZY3/2T/oOV5ri8SktTvmVGCyhwFuJC/NbJMEwIDAQAB\r\n' +
  'AoGAZXNdPMQXiFGSGm1S1P0QYzJIW48ZCP4p1TFP/RxeCK5bRJk1zWlq6qBMCb0E\r\n' +
  'rdD2oICupvN8cEYsYAxZXhhuGWZ60vggbqTTa+4LXB+SGCbKMX711ZoQHdY7rnaF\r\n' +
  'b/Udf4wTLD1yAslx1TrHkV56OfuJcEdWC7JWqyNXQoxedwECQQDZvcEmBT/Sol/S\r\n' +
  'AT5ZSsgXm6xCrEl4K26Vyw3M5UShRSlgk12gfqqSpdeP5Z7jdV/t5+vD89OJVfaa\r\n' +
  'Tw4h9BibAkEA2Khe03oYQzqP1V4YyV3QeC4yl5fCBr8HRyOMC4qHHKQqBp2VDUyu\r\n' +
  'RBJhTqqf1ErzUBkXseawNxtyuPmPrMSl6QJAQOgfu4W1EMT2a1OTkmqIWwE8yGMz\r\n' +
  'Q28u99gftQRjAO/s9az4K++WSUDGkU6RnpxOjEymKzNzy2ykpjsKq3RoIQJAA+XL\r\n' +
  'huxsYVE9Yy5FLeI1LORP3rBJOkvXeq0mCNMeKSK+6s2M7+dQP0NBYuPo6i3LAMbi\r\n' +
  'yT2IMAWbY76Bmi8TeQJAfdLJGwiDNIhTVYHxvDz79ANzgRAd1kPKPddJZ/w7Gfhm\r\n' +
  '8Mezti8HCizDxPb+H8HlJMSkfoHx1veWkdLaPWRFrA==\r\n' +
  '-----END RSA PRIVATE KEY-----';
var testPublicKey = {
  '@context': jsig.SECURITY_CONTEXT_URL,
  id: testPublicKeyUrl,
  type: 'CryptographicKey',
  owner: 'https://example.com/i/alice',
  publicKeyPem: testPublicKeyPem
};
var testPublicKeyOwner = {
  '@context': jsig.SECURITY_CONTEXT_URL,
  id: 'https://example.com/i/alice',
  publicKey: [testPublicKey]
};

var doc = {
  '@context': 'http://schema.org',
  'name': 'foo'
};

jsig.sign(doc, {
  privateKeyPem:testPrivateKeyPem,
  creator:testPublicKeyUrl},
  function(err, doc) {
    if (err) throw err;
  }
);
bash-3.2$ node test.js

/Users/james/Projects/activitystreams.js/test.js:50
    if (err) throw err;
                   ^
jsonld.NormalizeError: Could not convert input to RDF dataset before normalization.
    at /Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:787:23
    at /Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:933:14
    at /Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:326:16
    at done (/Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:6258:20)
    at loadDocument (/Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:1665:14)
    at Function.loader (/Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:1761:5)
    at jsonld.loadDocument (/Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:1200:24)
    at /Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:6288:23
    at retrieve (/Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:6292:8)
    at _retrieveContextUrls (/Users/james/Projects/activitystreams.js/node_modules/jsonld/js/jsonld.js:6295:3)

How to generate a public key private key in java language from es25519

The Ed25519 algorithm was used at str4d/ed25519-java#42 in this link.

public class Base58 {
	
	private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
	private static final int BASE_58 = ALPHABET.length;
	private static final int BASE_256 = 256;

	private static final int[] INDEXES = new int[128];
	static {
		for (int i = 0; i < INDEXES.length; i++) {
			INDEXES[i] = -1;
		}
		for (int i = 0; i < ALPHABET.length; i++) {
			INDEXES[ALPHABET[i]] = i;
		}
	}
	
	

	public static String encode(byte[] input) {
		if (input.length == 0) {
			// paying with the same coin
			return "";
		}

		//
		// Make a copy of the input since we are going to modify it.
		//
		input = copyOfRange(input, 0, input.length);

		//
		// Count leading zeroes
		//
		int zeroCount = 0;
		while (zeroCount < input.length && input[zeroCount] == 0) {
			++zeroCount;
		}

		//
		// The actual encoding
		//
		byte[] temp = new byte[input.length * 2];
		int j = temp.length;

		int startAt = zeroCount;
		while (startAt < input.length) {
			byte mod = divmod58(input, startAt);
			if (input[startAt] == 0) {
				++startAt;
			}

			temp[--j] = (byte) ALPHABET[mod];
		}

		//
		// Strip extra '1' if any
		//
		while (j < temp.length && temp[j] == ALPHABET[0]) {
			++j;
		}

		//
		// Add as many leading '1' as there were leading zeros.
		//
		while (--zeroCount >= 0) {
			temp[--j] = (byte) ALPHABET[0];
		}

		byte[] output = copyOfRange(temp, j, temp.length);
		return new String(output);
	}

	public static byte[] decode(String input) {
		if (input.length() == 0) {
			// paying with the same coin
			return new byte[0];
		}

		byte[] input58 = new byte[input.length()];
		//
		// Transform the String to a base58 byte sequence
		//
		for (int i = 0; i < input.length(); ++i) {
			char c = input.charAt(i);

			int digit58 = -1;
			if (c >= 0 && c < 128) {
				digit58 = INDEXES[c];
			}
			if (digit58 < 0) {
				throw new RuntimeException("Not a Base58 input: " + input);
			}

			input58[i] = (byte) digit58;
		}

		//
		// Count leading zeroes
		//
		int zeroCount = 0;
		while (zeroCount < input58.length && input58[zeroCount] == 0) {
			++zeroCount;
		}

		//
		// The encoding
		//
		byte[] temp = new byte[input.length()];
		int j = temp.length;

		int startAt = zeroCount;
		while (startAt < input58.length) {
			byte mod = divmod256(input58, startAt);
			if (input58[startAt] == 0) {
				++startAt;
			}

			temp[--j] = mod;
		}

		//
		// Do no add extra leading zeroes, move j to first non null byte.
		//
		while (j < temp.length && temp[j] == 0) {
			++j;
		}

		return copyOfRange(temp, j - zeroCount, temp.length);
	}

	private static byte divmod58(byte[] number, int startAt) {
		int remainder = 0;
		for (int i = startAt; i < number.length; i++) {
			int digit256 = (int) number[i] & 0xFF;
			int temp = remainder * BASE_256 + digit256;

			number[i] = (byte) (temp / BASE_58);

			remainder = temp % BASE_58;
		}

		return (byte) remainder;
	}

	private static byte divmod256(byte[] number58, int startAt) {
		int remainder = 0;
		for (int i = startAt; i < number58.length; i++) {
			int digit58 = (int) number58[i] & 0xFF;
			int temp = remainder * BASE_58 + digit58;

			number58[i] = (byte) (temp / BASE_256);

			remainder = temp % BASE_256;
		}

		return (byte) remainder;
	}

	private static byte[] copyOfRange(byte[] source, int from, int to) {
		byte[] range = new byte[to - from];
		System.arraycopy(source, from, range, 0, range.length);

		return range;
	}
}

This class was used to convert to base58 and applied to the Ed25519 example. Is this the wrong way?
If you know how to generate public and private keys using the java API, please let me know.

signing only the default graph

  1. I start with a document with a default and one named graph - http://tinyurl.com/z9ojfeq
  2. I sign it - http://tinyurl.com/j257vsy
  3. Now the normalized version of signed document doesn't have default graph any more, now it uses blank node identifier as name for the needs of signature - http://tinyurl.com/jaanxeh

Q: Does this signature also include content from graph named with <https://bob.example/api?path=/card> or just _:c14n0 (originally the default graph) ?

To allow server to add hypermedia controls using named graphs, as explained in http://ruben.verborgh.org/blog/2015/10/06/turtles-all-the-way-down/ I would like to have possibility to sign only the default graph on a client creating the content, server could also sign with different key other named graphs it adds to response but they could also have no signature.

Refactor API option style

A comment from an older PR should still be considered:

Looking at the verify() API I'm wondering if it might make sense to use a different style for async data options such as publicKey:

  • Just name the option publicKey.
  • if it's a function it would have a signature like the getPublicKey that was added.
  • If it's a promise it resolves to the data.
  • If it's an object it's just the data (internally can wrap it in a promise or something as needed).

Advantages are:

  • There is just one obvious name.
  • Simple case of just data is easy for callers.
  • Easy to support the three above styles to pass data.

The code for this is simple but could probably be reused for each option or in other APIs. Does it make sense to use that sort of style here?

LinkedDataSignature.getVerificationMethod limited to w3id.org security context definitions.

Related: digitalbazaar/jsonld.js#392

https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/suites/LinkedDataSignature.js#L233

This prevents suite implementers from relying on the base class, and forces them to comprehend JSON-LD and implement their own getVerificationMethod... here is one example:

async getVerificationMethod({ proof, documentLoader }) {
    if (this.key) {
      return this.key.publicNode();
    }
    // replaces:
    // const verificationMethod = await super.getVerificationMethod({
    //   proof,
    //   documentLoader,
    // });
    // Because hard coding security contexts prevents extension using base class
    // https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/suites/LinkedDataSignature.js#L233
    let controller = (await documentLoader(proof.verificationMethod)).document;
    const verificationMethod = await jsonld.frame(
      controller,
      {
        "@context": [
          "https://w3id.org/security/v2",
          "https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld",
        ],
        "@embed": "@always",
        id: proof.verificationMethod,
      },
      { documentLoader, compactToRelative: false }
    );
    await this.assertVerificationMethod({ verificationMethod });
    return verificationMethod;
  }

Perhaps this is by design... but its feels a bit odd.

controllerId is overriden in ControllerProofPurpose

The problem I'm facing happens at this line: https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/purposes/ControllerProofPurpose.js#L59

If the controller is an object here, controllerId gets set to controller.id but then is overriden by the whole controller object.

This causes this line to fail later on: https://github.com/digitalbazaar/jsonld-signatures/blob/master/lib/purposes/ControllerProofPurpose.js#L72

I think the condition should look something like this instead:

if(typeof controller === 'object') {
  controllerId = controller.id;
} else if(typeof controller !== 'string') {
  throw new TypeError("controller" must be a string representing a URL.');
} else {
  controllerId = controller;
}

Expand Test Coverage

--------------------------------|----------|----------|----------|----------|-------------------|
File                            |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
--------------------------------|----------|----------|----------|----------|-------------------|
All files                       |     79.9 |    65.77 |    85.57 |    79.64 |                   |
 lib                            |    74.09 |    62.31 |    78.72 |    73.41 |                   |
  ProofSet.js                   |    91.74 |    76.47 |    94.74 |     91.3 |... 29,238,330,335 |
  constants.js                  |      100 |      100 |      100 |      100 |                   |
  contexts.js                   |      100 |      100 |      100 |      100 |                   |
  documentLoader.js             |    90.91 |      100 |    66.67 |    90.91 |                66 |
  env.js                        |      100 |    66.67 |      100 |      100 |                 9 |
  expansionMap.js               |    66.67 |       50 |      100 |    66.67 |                 9 |
  jsonld-signatures.js          |    64.29 |    58.33 |      100 |    64.29 |... 41,42,43,46,47 |
  purposes.js                   |      100 |      100 |      100 |      100 |                   |
  suites.js                     |      100 |      100 |      100 |      100 |                   |
  util.js                       |    49.48 |     37.5 |    63.64 |    48.96 |... 23,225,227,228 |
 lib/purposes                   |    88.89 |    72.86 |      100 |    88.89 |                   |
  AssertionProofPurpose.js      |      100 |      100 |      100 |      100 |                   |
  AuthenticationProofPurpose.js |    90.48 |    76.47 |      100 |    90.48 |             15,18 |
  ControllerProofPurpose.js     |    86.84 |    64.29 |      100 |    86.84 |    29,54,56,63,65 |
  ProofPurpose.js               |    86.96 |       75 |      100 |    86.96 |          17,21,27 |
  PublicKeyProofPurpose.js      |      100 |      100 |      100 |      100 |                   |
 lib/suites                     |    82.95 |    65.44 |    88.89 |    82.88 |                   |
  EcdsaKoblitzSignature2016.js  |     91.3 |    57.14 |      100 |     91.3 |             23,45 |
  Ed25519Signature2018.js       |      100 |      100 |      100 |      100 |                   |
  GraphSignature2012.js         |     87.5 |    66.67 |      100 |     87.5 |             48,53 |
  JwsLinkedDataSignature.js     |    83.33 |    70.45 |      100 |    83.33 |... 26,133,169,182 |
  LinkedDataProof.js            |    57.14 |    33.33 |       50 |    57.14 |           9,25,38 |
  LinkedDataSignature.js        |    84.93 |    61.54 |       80 |    84.93 |... 58,263,279,293 |
  LinkedDataSignature2015.js    |    76.81 |    68.75 |      100 |    76.47 |... 65,166,167,171 |
  RsaSignature2018.js           |      100 |        0 |      100 |      100 |                32 |
--------------------------------|----------|----------|----------|----------|-------------------|

JsonLD Signatures is a pretty important part of the current tech stack.

Currently test coverage is hovering around 65~79% with all of those tests failing in an incoming branch from @mattcollier This issue is to layout what testing remains as instanbul shows surprisingly large amounts of the library need code coverage i.e. that 79% is because there are a lot of modules with 100% coverage such as PublicKeyProofPurpose, but then LinkedDataProof stands at about 50% depending on the metric used.

Implement better errors when docs/contexts are missing from documentLoader

In implementing vc-js tests, I've ran into multiple instances where if a context or any other document (like the key controller, or the key doc itself) was not handled by the documentLoader, it would result in an obscure failure message, something like 'invalid @id'.

So the action item is: track down where this is happening, and issue a better error message, something closer to "Context not able to be loaded, make sure the documentLoader supports it."

Note: this is somewhat related to issue #61, but that one just has to do with adding more discussion to the README, whereas this one is about improving the error messages.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.