(Updated 13/03/09: links at the end)

After the discussions we've been having recently on the foaf-protocols list about the various elements of trust that could be expressed in FOAF+SSL, I've decided to investigate a bit further the signature of FOAF files. There is a summary of FOAF+SSL on the W3C Workshop on the Future of Social Networking website. Henry Story's blog also has a number of entries about FOAF+SSL.

In short, a FOAF+SSL is an authentication mechanism that relies on a customised X.509 client certificate which contains the user's public key and the user identity URI (WebID). Because such a certificate may either be self-signed or be signed by a CA you might not know, authenticating this certificate as representing the WebID may be done in two different ways:

  1. getting the FOAF file from this WebID, and verifying that the public key of the certificate matches the public key associated with this WebID in that FOAF file;
  2. searching through the FOAF files of your peers to check if the public key of the certificate matches the public key they know of (for this particular WebID).

Both mechanisms may be used, for different purposes. The second relies on a Web-of-Trust (WoT) built from your FOAF network.

I would like to see if it's possible to provide a mechanism to build such a FOAF-based web-of-trust securely, in a similar way as it's done in PGP. In the PGP model, you can sign someone else's public key (coupled with an identifier), and ask someone else to sign your own. Other people's signatures of your key can be added to your PGP certificate and they can add your signatures of their key to their respective certificates. Thus, PGP users build a collection of certificates from trusted peers, which they'll be able to verify in the future. In addition, you may choose some of these peers to be trusted introducers, in which case they will also accept the certificates that these introducers have signed.

Increasing the number of signatures in a certificate increases the likelihood someone will recognise it. This is how trust is built, from the web made of certificates. FOAF, although not inherently secure, can also be used to build a model of trust in a social network. The problem here is that, to be able to build a web-of-trust from FOAF files, the authenticity of the FOAF files themselves has to be established first. The web is there, but not the signatures, thus not the trust (in the certification sense).

XML Signature

Since RDF may be represented in XML, XML Signature looks like a potential solution, as Dan Brickley mentioned in a comment on this blog.

XML Signature offers three ways of associating a signature with the signed content:

There are two interesting scenarios in this case: signing the root element of the FOAF document or signing some elements within it.

Enveloped or enveloping signatures

It's possible to use XML Signature to put the signature within the signed document (enveloped or enveloping signatures). The problem with this approach is that I could no longer get my FOAF file to validate: the <sig:Signature xmlns:sig="http://www.w3.org/2000/09/xmldsig#" /> element and its content don't mix well with RDF. A workaround is to validate and remove the signature before processing it in the RDF tool.

Detached signatures

The advantage of having the signature detached from the FOAF document is that this document can still be valid RDF. In this case, the XML signature document would have another URI, which could be referred to by the signed document itself, using RDF. For signing the entire document, XML Signature isn't really required in fact. The same objective could be achieved by signing the entire FOAF file using something based on PGP or S/MIME. The main advantage of XML signature over PGP and S/MIME in this case is that it provides a link to the document that has been signed (the URI in the <sig:Reference /> element; an application using this could thus be hypermedia driven.

I'm not sure if it's possible to specify a given content type in the <sig:Reference /> element (there is a Type attribute, but it doesn't seem to have anything to do with the content type). This can be a big problem, since the signature applies to a specific representation. For example, dereferencing Henry's FOAF card can serve a text/rdf+n3 representation (by default) or an application/rdf+xml one, depending on the user agent's Accept header. It would make sense for an RDF-based application that relies on these signatures to try to get the XML-based representations, but XML signature doesn't seem to be limited to signing XML representations when that representation is detached. There could even be multiple XML subtypes for other kinds of documents (say, application/atom+xml and application/xhtml+xml). A word about this is briefly mentioned in the URI section of the XML Signature specification, but I can't see any mechanism to help. A Content-Type attribute would have been nice.

I think I would prefer to be able to keep the signature within the RDF document. This could avoid potential concurrency issues if the FOAF document isn't updated at the same time as its signature. This would also make it more convenient to retrieve the FOAF file and how it has been certified in one operation.

Signing the entire FOAF file

Self-signing

The owner of the FOAF file can sign it: this is equivalent to producing a self-signed certificate. At least, if that person's public key is already known by the reader, it's possible to verify the integrity of the file. It's not bad, but it doesn't make the web-of-trust grow.

Signing by another party

Having your certificate signed by people is the mechanism by which the web-of-trust expands. If they sign the entire file, they will have to do it again every time you make any modification (white-space formatting included). That sounds highly impractical. I'm happy to sign Henry's FOAF file to assert the links between his URI, his name and his public key. However, I don't really want to have to produce another signature every time he adds a new person to his network.

Signing a subgraph and incorporating other's signatures

I think what would be much better would be to be able to sign sub-graphs. For example, in my FOAF file, I should be able to sign this sub-graph, so as to assert the links between Henry's name, URI and public key:

<rdf:Description rdf:ID="henrycert">
	<rdf:type rdf:resource="http://www.w3.org/ns/auth/rsa#RSAPublicKey" />
	<cert:identity>
		<rdf:Description rdf:about="http://bblfish.net/people/henry/card#me">
			<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person" />
			<name>Henry Story</name>
		</rdf:Description>
	</cert:identity>
	<rsa:modulus rdf:parseType="Resource">
		<cert:hex>
			862d6e0b8c3252a79d6eb82966f14e495c839ec2d57983ec39bfac79f8a99f887a3ca559cfee438e90f73da143cefc0a849509d8d91e7093a94c1a39863a5bed78a0f0234a372f12dce0a9535b14d92d56827b3791352b5817681ad7949aa7831911d51827a57e46bad9190d73a69ce56ada74a59ddc0df2a7a31247bbd67445
		</cert:hex>
	</rsa:modulus>
	<rsa:public_exponent rdf:parseType="Resource">
		<cert:decimal>65537</cert:decimal>
	</rsa:public_exponent>
</rdf:Description>

I think signing this would be a useful FOAF certificate, similar to the PGP certification, where only the association between public key and ID is signed.

Henry could also incorporate this signed sub-graph that I've signed into this own FOAF file, as a way to add certifications directly to his own public key (again, this is similar to the way PGP works). He could incorporate several copies of this sub-graph, signed by different people.

Specifying what to sign

For my first attempt to sign this element, I used <rdf:Description id="henrycert">. <sig:Reference URI="#henrycert" /> dereferences the fragment using the id attribute (via DOM's getElementById). Unfortunately, RDF validators and tools don't like the presence of this id attribute.

The trick I used relies on an XPath Transform:

<Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
	<XPath xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#">ancestor-or-self::*[@r:ID='henrycert']</XPath>
</Transform>

The is another problem here. If everyone who signs this element for Henry uses rdf:ID="henrycert" there are going to be conflicts when he pastes these certifications into his own collection. It seems better to use a UUID instead of henrycert, to avoid clashes.

Identifying the key used for the certification

In addition, because my public key is in the signature, in <sig:KeyInfo />, it's useful for whoever use it to know that it's mine. Instead of using the FOAF+SSL client certificate and a <sig:X509Data /> element, I've simply put my URI in the <sig:KeyName /> element. That's at least sufficient for this experiment.

Using these certifications

Once such a has been verified, in the XML Signature sense, it would be good to retain this fact in the RDF graph. I'm not sure how to express this. In addition, we'd also need to verify that the public key really belongs to its identifier, in the same way as it's done in FOAF+SSL.

I'd still have preferred to be able to keep the signatures within the same RDF document, but this doesn't seem to be possible (if we want that document to be processable by usual tools). Perhaps the easiest solution would be to create separate FOAF files containing just what needs to be signed. It might also be possible to have an RDF Signature specification similar to the XML Signature specification, including some canonicalisation which would be required, but this seems like a big job, and an unfortunate duplication of effort (seeing what has been done for XML Signature).

Update - 13/03/2009

Toby Inkster pointed out the work done by Jeremy Carroll on this topic. If you've found this blog entry interesting, you should read this work too.

In addition, if you're interested in XML Signature in Java, here are a couple of links you'll certainly find interesting: