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

Working protoytype using W3C proof spec #21

Open
trbouma opened this issue Feb 20, 2024 · 11 comments
Open

Working protoytype using W3C proof spec #21

trbouma opened this issue Feb 20, 2024 · 11 comments

Comments

@trbouma
Copy link
Collaborator

trbouma commented Feb 20, 2024

After a discussion with @aniltj , I revisited the W3C Data Integrity Spec and concluded that it can serve our needs instead of the 'more straightforward' JWT approach, which I was originally advocating for. The primary justification is to embrace what the W3C community has authored rather than trying advocate yet another way to do it.

All of the latest code is in this branch: https://github.com/CIRALabs/high-assurance-dids-with-dns/tree/w3c_proof

You can see it in action at http://trustroot.ca

The resulting did doc looks like below - note that "header", "dsnType", "alg", "iat" and "exp" are no longer because they can be expressed in the proof as: VerificationMethod {"type", :cryptosuite"} and Proof {"created", "expires" }

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/secp256k1recovery-2020"
  ],
  "id": "did:web:trustroot.ca",
  "sub": "did:web:trustroot.ca",
  "verificationMethod": [
    {
      "id": "did:web:trustroot.ca",
      "controller": "did:web:trustroot.ca",
      "type": "x509prime256v1",
      "publicKeyHex": "3059301306072a8648ce3d020106082a8648ce3d03010703420004d50eb242c6fcd1078ae74caf893668543cfaa8d5fb2096b1b7dfc687feafa3527655d0f2ebd86037bd6a80f19405c9cd3947dfdbf1190a8c482f9210ddf2da45"
    }
  ],
  "proof": {
    "id": "did:web:trustroot.ca",
    "domain": "did:web:trustroot.ca",
    "type": "DataIntegrityProof",
    "created": "2024-02-20T11:47:01.466206",
    "expires": "2024-02-20T12:47:01.466222",
    "verificationMethod": [
      {
        "id": "did:web:trustroot.ca",
        "type": "tlsa",
        "cryptosuite": "x509prime256v1",
        "controller": "did:web:trustroot.ca",
        "publicKeyHex": "3059301306072a8648ce3d020106082a8648ce3d03010703420004d50eb242c6fcd1078ae74caf893668543cfaa8d5fb2096b1b7dfc687feafa3527655d0f2ebd86037bd6a80f19405c9cd3947dfdbf1190a8c482f9210ddf2da45"
      }
    ],
    "proofPurpose": "assertionMethod",
    "proofValue": "e27ab1047d96a63b8a54dfe1c08e98e685f055396ef72bac22029cdb1b1ee1c4ac918b4f9befb6d97c4a7cd1077da4e549c443144cd5e68c64b6326efc59c7ab"
  }
}

There will still need to be some work to ensure that we can accommodate a wide array of Verification Methods. For example, x509 via openssl can accommodate about 50 different curves and schemes which are all formally specified. You can see above that I am using "x509prime256v1" which is a NIST curve, but x509 also supports all of the SECP curves. Further there are barebones schemes that don't use a cert, but just a public key/curve/signing algorithm.

I also dumped in "publicKeyHex" in the proof - it's not necessary, but it's a nice to have extracted from the certificate, just in case you need to verify the DID when offline.

I also updated the verify_did script (https://github.com/CIRALabs/high-assurance-dids-with-dns/blob/w3c_proof/sandbox/scripts/verify_did.py It's still pretty ugly, I am still cleaning up.

Finally, I am documenting how to add a subdomain - the steps to create a high assurance did for a subdomain like https://credentials.trustroot.ca

The steps are here: https://github.com/CIRALabs/high-assurance-dids-with-dns/blob/w3c_proof/sandbox/SUBDOMAIN.md

I am also experimenting with user dids like did:web:[email protected] which I believe can have some profound implications, but I will save that detail for another issue.

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 20, 2024

this is the did doc for the userdid:web:trustroot.ca:examplecorp or the more concise 'verifiable web identifier' version of: [email protected]. Note that the proof is same as above (except for different times) but the verificationMethod in the body is different because it relates to the user of the did, in this case excamplecorp, not trustroot.ca

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/secp256k1recovery-2020"
  ],
  "id": "did:web:trustroot.ca:examplecorp",
  "sub": "did:web:trustroot.ca:examplecorp",
  "verificationMethod": [
    {
      "id": "did:web:trustroot.ca:examplecorp",
      "controller": "did:web:trustroot.ca:examplecorp",
      "type": "secp256k1",
      "publicKeyHex": [
        "e4f7cafa0b271769087b06859917921941c4cea13abe842f379fc9209f367592"
      ]
    }
  ],
  "proof": {
    "id": "did:web:trustroot.ca",
    "domain": "did:web:trustroot.ca",
    "type": "DataIntegrityProof",
    "created": "2024-02-20T12:26:44.870816",
    "expires": "2024-02-20T13:26:44.870996",
    "verificationMethod": [
      {
        "id": "did:web:trustroot.ca",
        "type": "tlsa",
        "cryptosuite": "x509prime256v1",
        "controller": "did:web:trustroot.ca",
        "publicKeyHex": "3059301306072a8648ce3d020106082a8648ce3d03010703420004d50eb242c6fcd1078ae74caf893668543cfaa8d5fb2096b1b7dfc687feafa3527655d0f2ebd86037bd6a80f19405c9cd3947dfdbf1190a8c482f9210ddf2da45"
      }
    ],
    "proofPurpose": "assertionMethod",
    "proofValue": "4ac9b4ac0d7f8343e7ba50177c9135df17e42d712b0a8967cceabd63c69e0771c954ff87cdc20d5a80ede865b0edcf41fced4a6104555e01471fbd9a3e06e3d5"
  }
}

@aniltj
Copy link
Collaborator

aniltj commented Feb 20, 2024

Is the OPTIONAL domain property in the proof used correctly? From the spec (https://www.w3.org/TR/vc-data-integrity/#proofs) >> "A verifier SHOULD use the value to ensure that the proof was intended to be used in the security domain in which the verifier is operating. The specification of the domain parameter is useful in challenge-response protocols where the verifier is operating from within a security domain known to the creator of the proof."

This implies that the issuer knows the security domain of the verifier, which is not possible here as it could be anyone on the internet who wants to verify.

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 20, 2024

@aniltj - not sure. I need to read the spec more closely to see if it is correct. I saw that "domain" was a new attribute I hadn't seen before, so I dumped it in without fully understanding it.

All said, I am seeing huge potential for someone publishing their verifiable web identifier with a formalized scheme that can optionally support methods for different use cases such as presenting verifiable information that is public, do a challenge and response for authentication, and enabling one-time or many-time requests for selected proofs to reserved audiences by means of providing some sort of proofkey.

Anyway, further exploration. FWW, I am seeing a massive potential to break away from the 'digital wallet' and 'digital credential' metaphor that we've all been working with so far. I am exploring the different options in that light,

@jessecarter111
Copy link
Contributor

Am supportive of going back to the W3C spec. Note that the publicKeyHex has been deprecated by W3C (https://www.w3.org/TR/did-spec-registries/#publickeyhex). While the publicKeyHex is a nice convenience, I don't think it is necessary. I think the assumption is the end user has the cryptographic capabilities to do the necessary key conversions.

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 20, 2024

Ok - will remove publickeyhex

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 20, 2024

Attempting to implement the W3C data integrity proof spec - a few things don't seem to be right.

For the proof verificationMethod - the spec says it has to be a URL (link) to a public key or the cryptographic material - why?? For my implementation I retrieve the material by querying a DNSSEC record (not a website). I am putting the result of this query as text of the public key instead. This should be changed in the spec.

There is an inconsistency - the spec does not have cryptosuite as a field in the prooofs, yet it is in the examples. This is useful, so I added.

For the verificationMethods in the body of the doc, the registration https://www.w3.org/TR/did-spec-registries/#publickeyhex seems to be overly restrictive, deprecating methods that are still used by other ecosystems. I propose that they loosen up these requirements to accommodate a broader ecosystem.

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 20, 2024

This is how my resulting proof object looks like. I had to add in "dnsType". Also see that the "verficationMethod" is the hexstring of the publickey - not a URL

  "proof": {
    "id": "did:web:trustroot.ca",
    "type": "DataIntegrityProof",
    "dnsType": "tlsa",
    "proofPurpose": "assertionMethod",
    "verificationMethod": "3059301306072a8648ce3d020106082a8648ce3d03010703420004d50eb242c6fcd1078ae74caf893668543cfaa8d5fb2096b1b7dfc687feafa3527655d0f2ebd86037bd6a80f19405c9cd3947dfdbf1190a8c482f9210ddf2da45",
    "created": "2024-02-20T22:05:38.451173",
    "expires": "2024-02-20T23:05:38.451196",
    "cryptosuite": "x509prime256v1",
    "proofValue": "7254ed50ef45c4be0bf77e1cfc33d3c91335b28edb976338ce6eb72f12528ca1c84488a766bb4cd0076f146de1ed22c4c31f37c6ac2829769f844bf00af97525"
  }

@jessecarter111
Copy link
Contributor

The verificationMethod just points to an object in the DID doc representing a key pair.
For the information to be in the DNS, it also has to be a verificationMethod in the DID document. Cross-validating the information across 2 separate domains is an important aspect of the enhanced authenticity, and also provides optionality for the verifier when interacting with the DID document.

By not actually pointing to a verificationMethod and instead just using the key material, we make it much more difficult to ascertain the correct keypair, and even make assertions about the key itself.

I strongly posit that the verificationMethod field should be left as we originally implemented and left as a fragment pointing to a verificationMethod in the DID document.

i.e:

{
"verificationMethod":"did:web:trustroot.ca#key-1"
}

In cases where the DID doc is self signed the use of the verificationMethod URI is intuitive. For a self signed DID document, it just links to another object in the DID document. You already have access to it if you are looking at the proof.

It also makes it much more difficult to interact with DID docs that are not self signed. If we aren't pointing to a verificationMethod, figuring who that key belongs to is unnecessarily difficult.

In both cases, the user can choose to resolve that key in the DNS to verify or just use the verificationMethod directly.

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 21, 2024

OK, I think I am getting it now. The verificationMethod in the "proof" is just a pointer to the verificationMethod in the did doc.

A bit nested and referential for my liking ( read confusing) but I think I am getting it now....

So here is the latest iteration - for verificationMethod for "id" I used #key-dnstla to give a better indication of what it actually is. You will see in "proof" this is what I am pointing to.

I am also still using the publicKeyHex format as I believe this is a better format for human inspection (it is same format in the DNS TLSA record) and it should not be deprecated because this format is in wide use (especially compressed public key format) in many other ecosystems. The spec should be more accommodating to these formats.

Anyway, I hope this is correct. Since this did is for trustroot.ca it is 'self-signed'. I will put in the next comment the did doc for a user did - e.g. did:web:trustroot.ca:examplecorp

The latest and greatest did doc for did:web:trustroot.ca is below:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/secp256k1recovery-2020"
  ],
  "id": "did:web:trustroot.ca",
  "sub": "did:web:trustroot.ca",
  "verificationMethod": [
    {
      "id": "did:web:trustroot.ca#key-dnstlsa",
      "controller": "did:web:trustroot.ca",
      "type": "x509prime256v1",
      "publicKeyHex": "3059301306072a8648ce3d020106082a8648ce3d03010703420004d50eb242c6fcd1078ae74caf893668543cfaa8d5fb2096b1b7dfc687feafa3527655d0f2ebd86037bd6a80f19405c9cd3947dfdbf1190a8c482f9210ddf2da45"
    }
  ],
  "proof": {
    "id": "did:web:trustroot.ca",
    "type": "DataIntegrityProof",
    "dnsType": "tlsa",
    "proofPurpose": "assertionMethod",
    "verificationMethod": "did:web:trustroot.ca#key-dnstlsa",
    "created": "2024-02-21T13:07:17.100937",
    "expires": "2024-02-21T14:07:17.100957",
    "cryptosuite": "x509prime256v1",
    "proofValue": "c623e566344852a4f4e4f57cf23620c53ca37278604f84e2e57310a5ecddb9389366c0cbfcf1eb4911186b3c6685be492b11aa6a5482130c40c2a6e07227b93b"
  }
}

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 21, 2024

And here is the did doc for the user did:web:trustroot.ca:examplecorp

You will see in the "proof" it is exactly the same as the in the previous case.

What is different in this case (since it is a user did doc) - there are two verification methods - one for the user (examplecorp) to verify anything the user issues and one for (trustroot) to verify the did doc that trustroot issues (in this case, this did doc, which is indicated in the proof object)

I hope this is all correct now. The other part I am getting confused is the order and hierarchy of verificationMethod, assertionMethod and DataIntegrityMethod. It all seems rather complicated, nested and referential. I am sure it's justified but it's taking me time to sort it all out.

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/secp256k1recovery-2020"
  ],
  "id": "did:web:trustroot.ca:examplecorp",
  "sub": "did:web:trustroot.ca:examplecorp",
  "verificationMethod": [
    {
      "id": "did:web:trustroot.ca:examplecorp",
      "controller": "did:web:trustroot.ca:examplecorp",
      "type": "secp256k1",
      "publicKeyHex": [
        "e4f7cafa0b271769087b06859917921941c4cea13abe842f379fc9209f367592"
      ]
    },
    {
      "id": "did:web:trustroot.ca#key-dnstlsa",
      "controller": "did:web:trustroot.ca",
      "type": "x509prime256v1",
      "publicKeyHex": "3059301306072a8648ce3d020106082a8648ce3d03010703420004d50eb242c6fcd1078ae74caf893668543cfaa8d5fb2096b1b7dfc687feafa3527655d0f2ebd86037bd6a80f19405c9cd3947dfdbf1190a8c482f9210ddf2da45"
    }
  ],
  "proof": {
    "id": "did:web:trustroot.ca",
    "type": "DataIntegrityProof",
    "dnsType": "tlsa",
    "proofPurpose": "assertionMethod",
    "verificationMethod": "did:web:trustroot.ca#key-dnstlsa",
    "created": "2024-02-21T13:21:44.666409",
    "expires": "2024-02-21T14:21:44.666434",
    "cryptosuite": "x509prime256v1",
    "proofValue": "599f9187693899094be7261fa02e7093ea249fede7783880d41f57a6d30d4990cdafc5c3519484df00690a525d0774e674759d22e1e7c3fc00217e1498e8743c"
  }
}

@trbouma
Copy link
Collaborator Author

trbouma commented Feb 21, 2024

Looking over this overall approach, there are a few things still to sort out.

In the proof:

  1. "dnsType" and "crypotosuite" are redundant because these can be discerned from the "verificationMethod" in this case did:web:trustroot.ca#key-dnstlsa. So these should be removed.

  2. "type" is "DataIntegrityProof" - ok, this is a good indicator, but it does not look like it is used a parameter for any lookups.

  3. "proofPurpose" is "assertionMethod" - not sure how this is used in relation to "verificationMethod" -

I guess I am getting confused because I don't have a clear sense of the underlying data/conceptual model. I will spend some more time reading the specs to sort out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants