Skip to content

signatures should be on quoted graphs #1248

@bblfish

Description

@bblfish

In issue 204 on the N3 CG, I tried to translate 2 VC model examples. This revealed a few minor errors and some deeper conceptual problems, which are much easier to see in N3 than in Json-LD. These conceptual problems revolve around what is in a graph context and what is not. The JsonLD seems to place the contexts incorrectly, leading to unclarity about what is and what is not signed.

Update: the problem is perhaps most concisely expressed in a comment below in response to @msporny's feedback.

The N3 notation is to NQuads what Turtle is to NTriples: it makes it easy to read and reduces repetition for the author and the reader so that one can easily get an overview of what is being said. N3 makes it easy to read and write contexts. It also adds many other things, such as the ability to write rules for logical inferences... Where JsonLD makes it easy for developers happy with JSON to use the result, N3 makes it easy to see the data structure and reason about it. It especially makes it easy to see contexts, which are very difficult to see in jsonld.

1. Mapping the JSonLD of example 1 to N3

To take example 1, which I placed here https://bblfish.net/tmp/2023/08/vcdm.ex1.jsonld the result after fixing a few errors with namespaces, explained in detail in N3 issue 204 is that it gives me the following N3:

@prefix sec:     <https://w3id.org/security#> .
@prefix cred:    <https://www.w3.org/2018/credentials#> .
@prefix eg:      <https://example.org/examples#> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .

<did:example:c276e12ec21ebfeb1f712ebc6f1>
    <http://schema.org/name>
        "Exemple d'Université"@fr , 
        "Example University"@en .

<did:example:ebfeb1f712ebc6f1c276e12ec21>
    <http://schema.org/alumniOf>
        <did:example:c276e12ec21ebfeb1f712ebc6f1> .

<http://example.edu/credentials/1872>
    cred:issuer <https://example.edu/issuers/565049> ;
    a   eg:AlumniCredential ;
    a   cred:VerifiableCredential ;
    cred:issuanceDate "2010-01-01T19:23:24Z"^^xsd:dateTime ;
    cred:credentialSubject
        <did:example:ebfeb1f712ebc6f1c276e12ec21> ;
    sec:proof {
            []  a sec:RsaSignature2018 ;
                 dc:created "2017-06-18T21:19:10Z"^^xsd:dateTime ;
                sec:jws "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM" ;
               sec:proofPurpose sec:assertionMethod ;
              sec:verificationMethod
                    <https://example.edu/issuers/565049#key-1> .        
    }

The problem is that when signing data, one has to be very clear about which triples are signed. They, therefore, belong into a context which in n3 is placed inside the squiggly brackets { ... } .
In this N3 we have the signature in the context, but the claim that should be signed is outside of the context, so exactly what triples are being signed is unclear.

This can be made clearer by representing the above N3 in the diagram below, which shows graphs on rectangular surfaces when they appear inside {...} in the n3 notation.

Credential translated from JsonLD

Here we see that we can't tell clearly what is signed. We see that the credential links to the credential subject did:example:ebfeb1..., but what after that is included in the data signed? Is it also the alumniOf relation? Should one also add the literals? Which of the credential attributes has been signed? The data does not tell us that, but it should.

The problem is that one does not sign an object but a graph. Signatures are always applied to documents. Indeed, we can think of Graphs as semantically structured documents. Graphs are a type of object, of course, but we have a special syntax in N3 to relate them to other nodes by surrounding a set of triples with { ... }. Diagrammatically we represent this as nodes with graphs on the nodes.

As we will see next, we can have graphs in the nodes recursively: that is, graphs within nodes can also have graphs at their nodes. In the diagram below, we see this with the yellow rectangle surrounded by a green rectangle which itself is a node in a larger graph.

2. N3 corresponding to the VC Credentials diagram

The intuitions were clearly understood by the authors of diagram 6 from §3.2 of the VC-data-model spec, which uses surfaces to distinguish different claims.

Credentials Graph image from spec

This diagram represents the signature, the graph signed, and the claim, each in its own graph. This seems like the right model, aligning us with the well-known Says logic for decentralized access control.
We can interpret the colored surfaces as telling us who is making a claim.
Our trust in the claim being made depends on our trust in the agent making the claim, and our ability to verify that it did make that claim.

Anyway, the official Verifiable Claims interpretation of the JsonLD is that it should consist of 3 claims, i.e., sets of relations that we can think of as being placed on surfaces, following an idea from Pat Hayes, that he took from Peirce and which is now being worked on in the RDF Surfaces CG.

As shown in the diagram, a VC is data about a claim (the Yellow surface to the right) stating that Pat is an alumnus of "Example University". That claim is made or "said" by the issuer - the University in this case - at a certain date. The data about that is on the pink surface. Finally, the University key signs the above claim with the statement on the green surface.

In the says logic, this would be expressed as something like this:

$$\text{ UniKey } \text{ says } \text{ Uni } \text{ says } \text{ PaU}$$

where $\text{ PaU } \equiv \text{ Pat alumnusOf Uni }$

This suggests that the pink and yellow surfaces are placed onto the green surface, which follows by associativity of the says relation:

$$ \text{UniKey} \text{ says } ( \text{ Uni } \text{ says } \text{ PaU} ) $$

To be precise, we should perhaps start with The Guard initially receiving the following claim from some connAgent,
ie the agent at the other end of a connection.

$$ \text{ connAgent } \text{says} (\text{UniKey} \text{ says } ( \text{ Uni } \text{ says } \text{ PaU} )) $$

From the Guard's point of view, the only fact that exists at that point in time,
is that the connAgent said that thing (that the UniKey said...)
None of the embedded statements are to be taken as true or false at that point by the Guard.
They are quoted sayings, and their truth value is yet to be decided.

Yet, without needing to trust the connAgent at all, the Guard can verify the embedded claim made by the UniKey using cryptographic signatures so that it can conclude to the truth of the pink surface.
That is because the Guard trust the University key to speak for the University.
So he concludes:

$$ \text{ Uni } \text{ says } \text{ PaU } $$

Again here, the Guard has a fact that does not assert or deny that Pat is an alumnus of Uni, only that the Uni said so.
So we are now on the pink surface where the Guard does not yet know if the yellow surface is true or false.
If the Guard trusts the issuer about claims it makes regarding its own members - which seems like a reasonable assumption - then the Guard can proceed to believe that Pat is an alumnus of that university. Perhaps that is what is needed to be proven to satisfy an access control rule.

All that makes logical sense. If we wanted to write the above official diagram in N3, we would have something like the following N3.
(Note: the diagram has two links (credentialSubject and proof) that go from an object into a node in a graph context (a box). That requires an extra relation to point into the graph, it seems, but I'll ask and the N3 group if it could be done if it were really needed.)

@prefix sec:     <https://w3id.org/security#> .
@prefix cred:    <https://www.w3.org/2018/credentials#> .
@prefix eg:      <https://example.org/examples#> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/>.

{   
<http://example.edu/credentials/1872>
    cred:issuer <https://example.edu/issuers/565049> ;
    a   eg:AlumniCredential ,  cred:VerifiableCredential ;
    cred:issuanceDate "2010-01-01T19:23:24Z"^^xsd:dateTime ;
    cred:credentialSubject
        <did:example:ebfeb1f712ebc6f1c276e12ec21> ;
    cred:claim { 
    <did:example:ebfeb1f712ebc6f1c276e12ec21>
         schema:alumniOf [ id <did:example:c276e12ec21ebfeb1f712ebc6f1> 
               schema:name "Exemple d'Université"@fr ,   "Example University"@en 
         ] 
   }
 } sec:proofObject _:gn;
    sec:proof {
    _:gn  a sec:RsaSignature2018 ;
           dc:created "2017-06-18T21:19:10Z"^^xsd:dateTime ;
           sec:jws "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM" ;
            sec:proofPurpose sec:assertionMethod ;
            sec:verificationMethod
                    <https://example.edu/issuers/565049#key-1> 
    ]  .
} .

Here the VC signed the information about who made the claim and the claim together.
Now we see that it is odd that the university's name is in the claim. Should it perhaps be outside the claim? It is not clear from the graph what is intended there, but both would be fine.

3. Slight Simplification of N3 translation of Diagram

We have two arguments for removing the green surface:

  1. Since the information about the signature is not itself signed, the claim does not perhaps need to be in a graph context. In the language of RDF Surfaces, if the top surface is positive, then we can take it to be the default surface.
  2. As argued above from the key says ... we can think of the green surface as containing the pink one and so the green surface being the base one. In that case we can see that the green surface would be the default graph and we can get rid of it altogether.

Removing the green surface simplifies the n3 quite a lot giving us:

@prefix sec:     <https://w3id.org/security#> .
@prefix cred:    <https://www.w3.org/2018/credentials#> .
@prefix eg:      <https://example.org/examples#> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/>.

{   
<http://example.edu/credentials/1872>
    cred:issuer <https://example.edu/issuers/565049> ;
    a   eg:AlumniCredential ,  cred:VerifiableCredential ;
    cred:issuanceDate "2010-01-01T19:23:24Z"^^xsd:dateTime ;
    cred:credentialSubject
        <did:example:ebfeb1f712ebc6f1c276e12ec21> ;
    cred:claim { 
    <did:example:ebfeb1f712ebc6f1c276e12ec21>
         schema:alumniOf [ id <did:example:c276e12ec21ebfeb1f712ebc6f1> 
               schema:name "Exemple d'Université"@fr ,   "Example University"@en 
         ] 
   }
 } sec:proofObject [  a sec:RsaSignature2018 ;
     dc:created "2017-06-18T21:19:10Z"^^xsd:dateTime ;
     sec:jws "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM" ;
      sec:proofPurpose sec:assertionMethod ;
      sec:verificationMethod
               <https://example.edu/issuers/565049#key-1> 
    ]  .

Graphically this can be represented as
Intermediate: Credential with Credential Proof in default

Would it be possible, with minor tweaking of the Json-ld contexts, to get the above interpretation to work?

4. proposition of N3 intended by the JsonLD

The above seems right but is not what the JsonLD mapping to RDF shows, if only because it is missing the yellow surface and has placed the data to be signed on the default surface.

The closest to something we could get that resembles the RDF we found the current JSonLD to translate to is to flip the
contexts. Instead of the signature being in the context, we get something more reasonable by having the signed data be in a context.

Perhaps this is what the VC data model intended the original json-ld to represent?

@prefix sec:     <https://w3id.org/security#> .
@prefix cred:    <https://www.w3.org/2018/credentials#> .
@prefix eg:      <https://example.org/examples#> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/>.

{
<did:example:c276e12ec21ebfeb1f712ebc6f1>
    schema:name
        "Exemple d'Université"@fr ,   "Example University"@en .

<did:example:ebfeb1f712ebc6f1c276e12ec21>
    schema:alumniOf <did:example:c276e12ec21ebfeb1f712ebc6f1> .

<http://example.edu/credentials/1872>
    cred:issuer <https://example.edu/issuers/565049> ;
    a   eg:AlumniCredential ,  cred:VerifiableCredential ;
    cred:issuanceDate "2010-01-01T19:23:24Z"^^xsd:dateTime ;
    cred:credentialSubject
        <did:example:ebfeb1f712ebc6f1c276e12ec21>  .
 } sec:proof [  a sec:RsaSignature2018 ;
           dc:created "2017-06-18T21:19:10Z"^^xsd:dateTime ;
           sec:jws "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM" ;
            sec:proofPurpose sec:assertionMethod ;
            sec:verificationMethod
                    <https://example.edu/issuers/565049#key-1> 
    ]  .

That is, here we only use a graph context to enclose the signed triples, which in this case
I guess enclose the metadata about the issuer too. Graphically represented, this is what we have:

Is this what Credential Example 2 Should Be?

Is that correct? I don't know. It would require a very close analysis of the spec to understand what is intended to be signed. Update: See a detailed reasoning for why this follows from the previous two models.

(todo: We could also imagine that only the claim was intended to be signed.)

In issue 204 on the N3 repo I show the same problem with Example 6 in the spec.

Conclusion

Perhaps I missed something. Is there a mistake in the JsonLd or its @context statements? I have not written a JSON-LD parser, so I don't know the capabilities of contexts inside out. Perhaps it is easy to fix? What is the intended N3 corresponding to the Json-Ld?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions