François' Blog

Introducing IndieCert

2015-02-02

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!

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.

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 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, instead of using the client certificates. Some browsers and operating systems unfortunately do not support easy client certificate enrollment.

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:

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&amp;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:

`code`
the code obtained in the authentication response query parameter `code`.
`redirect_uri`
the URL the browser was redirected back to after the successful authentication;

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&amp;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.

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:

References

Last updated on 2015-03-08

Return to Index