diff options
Diffstat (limited to 'posts/indiecert.md')
-rw-r--r-- | posts/indiecert.md | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/posts/indiecert.md b/posts/indiecert.md new file mode 100644 index 0000000..8f5fedc --- /dev/null +++ b/posts/indiecert.md @@ -0,0 +1,265 @@ +--- +title: Introducing IndieCert +published: 2015-02-02 +modified: 2015-03-08 +--- + +**More feedback is required before this document can be considered finished. See "Issues" section below.** + +Authenticating to web servers with a client certificate, installed in the +user's browser, is unfortunately not widely used. They are convenient and safe +to use once the initial hurdle of installing them is taken. + +There is now a Proof of Concept instance! Check it out [here](https://indiecert.net)! + +The main benefit is easy and secure authentication. There is no need to provide +a password to any service, only the URL to your home page. So there is no +chance you will leak your password to some service. + +<video controls="controls" width="575"> + <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_auth_flow.webm" type="video/webm"> + <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_auth_flow.mp4" type="video/mp4"> +</video> + +In addition, this proposal describes a way to make the use of client certificates +feasible: + +1. A self-signed CA is used instead of a 'browser trusted' CA to issue the client certificates, this works without browser warnings; +2. Users authorize the certificates by publishing the certificate fingerprint on their home page allowing to claim ownership of a URL and by authenticating with the certificate directly; +3. Allow identity (certificate) linking using the user's home page address to allow registration of multiple fingerprints to support multiple devices and browsers. + +A possible drawback is that many users do not have a home page anymore. They +have a Facebook profile or a Twitter account, but no home page. However, this +is not relevant for [IndieWeb](https://indiewebcamp.com/) as all +users should have their own home page running on their own domain anyway :) + +As a fallback it is possible to allow authenticating using existing social +networks, similar to [IndieAuth](https://indieauth.com), instead +of using the client certificates. Some browsers and operating systems +unfortunately do not support easy client certificate enrollment. + +<img src="https://storage.tuxed.net/fkooman/public/upload/blog/keep-calm-and-use-certificates.png" width="300" height="350" alt="keep calm and use certificates"> + +### Protocol for Relying Parties + +The protocol follows the protocol proposed for IndieAuth. The protocol is +based on the IndieAuth protocol and aims to be compatible with it. + +#### Request Authentication + +The service redirects the user to `https://indiecert.net/auth` to +start the authentication phase. Two parameters need to be specified: + +- **redirect_uri**: + - the URL the browser should be redirected back to after the authentication is successful. This MUST be a valid HTTPS URL; +- **me**: + - the URL to the user's home page (see [Retrieving the User's Home Page](#retrieve_home_page)); + +##### Example +Below is an example of a browser redirect. The process can also be initiated +with a `<form>` submit using the `GET` method. + +``` +HTTP/1.1 302 Found +Location: https://indiecert.net/auth?redirect_uri=https://example.org/callback&me=https://tuxed.net/fkooman +``` + +IndieCert will at this point take care of the authentication and optional +enrollment process if that was not already done. + +#### Authentication Response + +IndieCert will redirect the browser back to the `redirect_uri` +specified in the authentication request after the user is authenticated at +IndieCert. + +##### Example + +``` +HTTP/1.1 302 Found +Location: https://example.org/callback?code=wW3OLXJZn35d7zFwg9YGmWti +``` + +#### Verification Request + +The `code` parameter can now be used to request the claimed user +identity. The following parameters are required: + +<dl> + <dt>`code`</dt> + <dd>the code obtained in the authentication response query parameter `code`.</dd> + <dt>`redirect_uri`</dt> + <dd>the URL the browser was redirected back to after the successful authentication;</dd> +</dl> + +Now a HTTP `POST` can be used to obtain the user's (normalized) home +page URL: + +``` +POST /auth HTTP/1.1 +Host: indiecert.net +Content-Type: application/x-www-form-urlencoded +Accept: application/json + +redirect_uri=https%3A%2F%2Fexample.org%2Fcallback&code=wW3OLXJZn35d7zFwg9YGmWti +``` + +The response will be formatted as JSON indicating the actual user home page in +the `me` parameter. + +This is the identity that MUST be used by the relying party to identify the +user as it could differ from the initial `me` specified by the user, +e.g.: redirects were followed to reach the user's home page. + +``` +HTTP/1.1 200 OK +Content-Type: application/json +Cache-Control: no-store +Pragma: no-cache + +{ + "me": "https://www.tuxed.net/fkooman/" +} +``` + +In case there was a failure in verifying the code, e.g. it was already used, or +not valid the following response can be expected: + + +``` +HTTP/1.1 400 Bad Request +Content-Type: application/json +Cache-Control: no-store +Pragma: no-cache + +{ + "error":"invalid_request" +} +``` + +### Protocol for the IndieCert Service + +The IndieCert service has to deal with certificates, issuing, installing and +verifying them. The most convenient method is to use the HTML +`<keygen>` tag. This makes the browser generate a private key +and certificate request (SPKAC) that is then sent to the service for signing. +The service will sign this with the CA generated for this particular IndieCert +instance. The signed certificate is sent back to the client and (automatically) +imported in the browser certificate store. + +After this, the certificate can be used to authenticate to the IndieCert +service, but it still needs to be linked to the URL of the user's home page. +This can be done by using the `rel="me"` attribute in a +`<link>` header tag or `<a>` body tag. + +``` +<link rel="me" href="ni://indiecert.net/sha-256;WXXyBZDo1pZYiLbrCNGFtSdSamqEvSJJBRzpx-MNIUA?ct=application/x-x509-user-cert"> +``` + +Once the user has placed this HTML element on their home page the URL it will +be found when the IndieCert instance will fetch the URL and extract all +`<link>` and `<a>` tags to look for the +`rel="me"` attribute. The fingerprint of the client certificate +used to authenticate to IndieCert needs to be listed on the home page. +After that, the URL of the home page will be used as an accepted identifier. + +<video controls="controls" width="575"> + <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_enroll.webm" type="video/webm"> + <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_enroll.mp4" type="video/mp4"> +</video> + +#### Retrieving the User's Home Page + +The user's home page MUST be fetched over HTTPS only, MUST follow redirects and +MUST NOT have any HTTP URLs in its redirect path. If the URL does not start +with `https://` it MUST be added by IndieCert. If a URL starts with +`http://` or is otherwise invalid it MUST be rejected. The final +URL, the URL that returns a `200 OK` status, MUST be used in the +response to the verification request, this is the normalized home page URL. + +For example the user provides `tuxed.net/fkooman`. IndieCert makes +this `https://tuxed.net/fkooman` and starts the fetching process. It +is then redirected to `https://www.tuxed.net/fkooman` and then to +`https://www.tuxed.net/fkooman/`. The claimed identity thus becomes +`https://www.tuxed.net/fkooman/` and this value is returned in +response to the verification request. + +### Identity Linking + +One of the benefits of publishing fingerprints on the user's home page is that +additional client certificate fingerprints can easily be added to the home page +to allow those certificates to claim the same identity. + +``` +<!-- laptop --> +<link rel="me" href="ni://indiecert.net/sha-256;WXXyBZDo1pZYiLbrCNGFtSdSamqEvSJJBRzpx-MNIUA?ct=application/x-x509-user-cert"> + +<!-- phone --> +<link rel="me" href="ni://indiecert.net/sha-256;ThIaJ7TJQ1oAIKCGKe0BdBO3Bh8NzxZeyAa-WCTuzpU?ct=application/x-x509-user-cert"> +``` + +Certificate revocation is done by removing the entry from the home page and it +can no longer be used to claim the identity. + +### Fingerprint Generation + +The fingerprint of the certificate is generated by calculating the SHA-256 hash +over the DER encoded certificate and base64url encoding the resulting binary +string according to RFC 6920 "Naming Things with Hashes" and RFC 4648 +"The Base16, Base32, and Base64 Data Encodings". An example of calculating a +fingerprint in PHP: + +``` +<?php +$string = 'Hello World!'; +echo rtrim(strtr(base64_encode(hash('SHA256', $string, true)), '+/', '-_'),'='); +``` + +### Distributed IndieCert + +One of the important issues to solve is how to make this protocol distributed, +i.e.: how to allow multiple instances of IndieCert to be used by different +services whilst allowing a smooth user experience. + +The relying party can choose to join an existing IndieCert instance, or run +their own if they don't trust any of the existing instances. The benefit of +running their own is better control and more trust and no requirement on third +parties for the authentication to their service. + +Assuming they want to run their own instance that would require the user to +generate a new certificate and put the fingerprint on their home page as well. +This results in additional overhead, for the user, but may be worth it from a +security perspective. And the process needs to be repeated once per IndieCert +instance, per device or even per browser. This the greatest weakness of this +proposal, that and adoption. If everyone runs their own IndieCert instance it +will quickly become a management nightmare for the user if they have to keep +track of all certificates in all their browsers on all their devices. This +could be solved by a tool allowing users to easily add fingerprints to their +website. + +For the actual user experience, the user just selects the specific certificate +for the specific IndieCert instance (it can be pre-selected by most browsers +based on the CA) so that should not be a problem. + +### Issues + +There are a number of issues we have to solve before this document can be +considered stable: + +- CSRF. User X can generate a code for his identity and trick user Y into + going to a relying party with user X's code to work under user X's identity, + possibly storing private data under user X's identity instead of user Y's. We + need to implement some kind of state generating/checking; +- Rate limiting on the verify endpoint; +- Many browsers, many devices, many instances of IndieCert is a scalability nightmare for the user... + +### References + +- [IndieAuth](https://indieauth.com) +- [IndieWebCamp](https://indiewebcamp.com) +- [RelMeAuth](http://microformats.org/wiki/RelMeAuth) +- [Certificate Download Specification](https://wiki.mozilla.org/CA:Certificate_Download_Specification) +- [Keygen Tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen) +- [Naming Things with Hashes](http://tools.ietf.org/html/rfc6920) (RFC 6920) +- [The Base16, Base32, and Base64 Data Encodings](http://tools.ietf.org/html/rfc4648) (RFC 4648) +- [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) (RFC 6749) |