Skip to content

Authenticity checks #3

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

Closed
kimdhamilton opened this issue Nov 1, 2018 · 4 comments
Closed

Authenticity checks #3

kimdhamilton opened this issue Nov 1, 2018 · 4 comments
Assignees
Labels
pending close (7 days) This issue will be closed after 7 days.

Comments

@kimdhamilton
Copy link
Contributor

There is already an issue in the spec (Issue 1) tracking authenticity checks through bidirectional links. I discussed this with @dlongley at TPAC and realized some of my assumptions carried over from earlier VC drafts.

creator is in the unsigned proof region, and (I think) an earlier version of the VC data model mentioned (something around the "Entity Profile"?) mentioned that creator should be checked against a property on issuer.

The idea that the creator key material can be checked against some property of the issuer referenced in the signed content is appealing. We enforce that as part of Open Badges verification, but it's not clear where this stands from an LD-proofs perspective.

@dlongley
Copy link
Contributor

dlongley commented Nov 1, 2018

@kimdhamilton,

creator is in the unsigned proof region...

Clarification: the "proof region" is signed. The only piece of information that isn't signed with LD signatures is the signature value itself (as that would be circular). Everything else is signed. This code (from the JavaScript implementation) separately canonizes both the information in the "proof region" (proof) and the entire document (expanded -- as it is in JSON-LD expanded form at this point in the implementation). Then it hashes each and concatenates them.

    const c14nProofOptions = await this.canonize(proof, options);
    const canonizeOptions = Object.assign({}, options, {skipExpansion: true});
    const c14nDocument = await this.canonize(expanded, canonizeOptions);
    return {
      data: this._sha256(c14nProofOptions).getBytes() +
        this._sha256(c14nDocument).getBytes(),
      encoding: 'binary'
    };

https://github.com/digitalbazaar/jsonld-signatures/blob/f34eeba666ccc57bbaceb5482d7a8bfd7b3d42ed/lib/suites/LinkedDataSignature.js#L58-L63

This is according to the LD signatures specification's "Create Verify Hash Algorithm", where the "canonicalized options document" refers to the "proof" information and the "canonicalized document" refers to everything else.

https://w3c-dvcg.github.io/ld-signatures/#create-verify-hash-algorithm

  1. Generate output by:
    4.1 Creating a canonicalized options document by canonicalizing options according to the canonicalization algorithm (e.g. the GCA2015 [RDF-DATASET-NORMALIZATION] algorithm).
    4.2 Hash canonicalized options document using the message digest algorithm (e.g. SHA-256) and set output to the result.
    4.3 Hash canonicalized document using the message digest algorithm (e.g. SHA-256) and append it to output.

Next you said:

...An earlier version of the VC data model spec mentioned that creator should be checked against a property on issuer.

Yes, creator refers to the key that signed -- and dereferencing that key should yield a statement about who the controller of that key is. Dereferencing the controller's identifier should yield a document that includes the key in a cryptosuite section matching the proofPurpose of the proof. For example, credentialIssuance is such a proofPurpose -- the one that should be used when issuing a credential. These checks establish a bi-directional link and that the key was approved for the purpose of the proof that is being verified.

Then, a final additional check should be made (for VC verification) that the issuer field matches the controller's identifier.

So, in all, you've got a proof that looks something like this:

"proof": {
  "type": "SomeLdSignatureScheme",
  "proofPurpose": "credentialIssuance",
  "creator": "did:v1:nym:1234#somekey",
  "jws": "..."
}

When you dereference the creator key ID you get:

{
  "id": "did:v1:nym:1234#somekey",
  "type": "SomeKeyType",
  "controller": "did:v1:nym:1234",
  "publicKeyBase58": "..."
}

When you dereference the controller ID you get:

{
  "id": "did:v1:nym:1234",
  ...,
  "credentialIssuance": [{
    "type": "SomeCredentialIssuanceCryptoSuite",
    "publicKey": [{
      /* the key you're looking for must be in here, i.e. the same one as above! */
      "id": "did:v1:nym:1234#somekey",
      "type": "SomeKeyType",
      "controller": "did:v1:nym:1234",
      "publicKeyBase58": "..."
    }
    }]
  }],
  ...
}

We need to update the LD signature/proof spec(s) to make this clear.

@kimdhamilton
Copy link
Contributor Author

Ah, the signed part of proof was the sticking point. From this document, it was ambiguous to me which part was removed before signing, so I guessed that we carried forward the technique from step 3 of ld-signature verification algorithm, which says remove signature (now corresponding to proof) nodes.

So with that clarification, it's consistent with my recollection of our discussion (e.g. proofPurpose, etc), and this is making more sense.

I want to keep this issue open. I'll take a stab at some edits after mulling it over.

@kimdhamilton kimdhamilton self-assigned this Nov 1, 2018
@dlongley
Copy link
Contributor

dlongley commented Nov 1, 2018

...so I guessed that we carried forward the technique from step 3 of ld-signature verification algorithm, which says remove signature (now corresponding to proof) nodes.

Right ... so the only "proof nodes" that are removed are any that were signed previously (typically by other parties), to enable "set" or multisignatures over the same data. In other words, any proof someone else attached won't be signed by you, but any proof you attach will be signed by you. Hopefully that makes sense.

@msporny
Copy link
Member

msporny commented Jul 2, 2023

There has been some fairly significant re-work and finalization of the algorithms used in the specification since this issue was raised. There is now text that details how adding proofs and verifying proofs works (in general):

These general algorithms are then further refined in each cryptosuite specification:

... which contain enough detail now to specify exactly what is signed, and in what order. I believe this issue is addressed now, and am marking it with a pending 7 day close. Please let us know if you feel that the issue isn't addressed now, what we can do further to address the issue, and (ideally) a corresponding PR that would address your concern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending close (7 days) This issue will be closed after 7 days.
Projects
None yet
Development

No branches or pull requests

3 participants