Keyoxide

Back to posts

How to write a basic ASPE client

Posted on 2023-09-25

This is the third in a series of posts related to the new Ariadne Signature Profiles:

This post is intended for developers who want to create their own tools compatible with Keyoxide.

This post is also available in the Keyoxide docs.

What does an ASPE client do?

An Ariadne Signature Profile (ASP) is a type of identity profile that services like Keyoxide can verify but which rely on basic cryptographic standards like EdDSA and ES256 instead of cryptographic tools like OpenPGP.

The ASP Exchange (ASPE) protocol refers to the set of HTTP requests by which people can upload and download ASPs to and from dedicated servers.

An ASPE client will:

Writing an ASPE client

Now, let's try and write an ASPE client. This will be a simple overview of the different required steps. For more implementation details, refer to the ASP specification.

Here are two open source ASPE clients you can use as basis for your own:

Creating a new profile

To create a new profile, simply create an object/struct with the following information:

As always with ASPs, the name of the profile may be real or anonymous. Be sure to remind your users of this fact!

The spec also specifies the avatar_url and email properties, but these are optional and for now, no profile verifier clients should use these yet until their behavior is better defined, so ASPE clients should omit them.

Generating a cryptographic key

Every ASP is identified and queried by a so-called fingerprint which is based on the cryptographic key associated with the profile. This means every ASP must have their own unique cryptographic key.

Indeed, the ASP method is based on the principle that cryptographic keys are cheap, single purpose and — in some way — ephemeral.

The spec makes opiniated decisions on which types of cryptographic keys are acceptable for the creation of an ASP. To strike a balance between reduction of code complexity of clients and freedom within the potential constraints of the client's environment, the spec allows two combinations of cryptographic keys and signature algorithm:

Verifying clients should always accept both of these, ASPE clients may choose to only generate profiles with a single algorithm. Indeed, at the time of writing, browsers do not widely support Ed25519 keys and are therefore restricted to P-256.

That being said, whenever possible, it is recommended to adopt Ed25519 over P-256. See the Guidance for Choosing an Elliptic Curve Signature Algorithm in 2022 [soatok.blog] for more information.

In the next steps, the client will be generating JSON Web Signatures (JWS) and according to the ASP spec, these JWS must include the cryptographic key in JSON Web Key (JWK) format. Make sure that your cryptographic library of choice is capable of converting keys to the JWK format. kx-aspe-web uses jose (JS) and kx-aspe-cli uses josekit (Rust).

Generating a profile JWS

Now that we have profile details and a crytographic key, let's generate cryptographic signatures.

To upload an ASP, the client will have to generate a signature of a signature. Let's start with the "inner" signature, the profile JWS.

It's recommended to use tried and trusted libraries for the generation of cryptographic signatures. kx-aspe-web uses jose (JS) and kx-aspe-cli uses josekit (Rust).

The object needed for the profile JWS looks as follows:

If the profile has a description and/or a color, the client may set the http://ariadne.id/color and the http://ariadne.id/color (in HEX format) respectively.

The JWS must be serialized using Compact Serialization (see section 3.1 of RFC7515).

Computing the fingerprint

To obtain the fingerprint associated with the ASP profile, one must create a specific JSON object based on the JWK-encoded public key, serialize it, hash it, truncate it and encode it. All the details for this process can be found in section 2.2 of the spec.

Generating a request JWS

The profile JWS generated above is the actual ASP that dedicated servers will host and distribute. To send the profile JWS to a dedicated server, it needs to be encapsulated for transport within a request JWS.

The object needed for the request JWS looks as follows:

Evidently, the key used for the request JWS must be the same as the one used for the profile JWS.

Note that the http://ariadne.id/action property is set to create. This is only valid for the first upload. Subsequent uploads should use the update action. To remove the ASP from the server, use the delete action — omit the http://ariadne.id/profile_jws property when doing so.

The JWS must also be serialized using Compact Serialization (see section 3.1 of RFC7515).

Uploading a request JWS

Now that we have our profile JWS inside a request JWS, the client needs to upload the latter to a dedicated server. Each public ASPE server has an endpoint dedicated to receiving request JWS:

POST ENDPOINT = '/.well-known/aspe/post'

Use a POST HTTP request with the request JWS as body and set request's Content-Type header to:

application/asp+jwt; charset=UTF-8

If all went well, the client should receive a 201 CREATED response — or 200 OK for the update and delete actions.

The ASP is now published at the following endpoint hosted by the ASPE server:

GET ENDPOINT = '/.well-known/aspe/id/' fingerprint

Securely storing profile data

The client has done its duty of creating a profile and uploading it to a dedicated server. However, people may like to update or delete their profile at a later moment. It's therefore crucial to store both the profile details and the secret cryptographic key.

Profile details

Storing the profile details should not be an issue. kx-aspe-cli stores it plainly as a TOML file in the OS' user data directory — developers, don't pollute people's $HOME directory, please, thank you.

kx-aspe-web takes an interesting approach: it doesn't store profile details locally but rather on the ASPE server. When editing the profile, it just fetches the profile from the server and starts from there. This has the benefit of making the profile details available on each and every device without complicated syncing protocols. Drawbacks are that people can't "prepare" an account by creating it first and uploading it later.

Local clients like desktop and mobile clients are strongly recommended to store a local copy of the profile.

Secret cryptographic key

This is perhaps the most delicate step of the process: people need to keep a copy of the secret key in order to keep control over their profile. But if the secret key is handled inappropriately, it becomes trivial for a bad actor to compromise that profile.

Some OS have dedicated key storage system like the Android Keystore or the iOS Keychain but this may not always be available or desired.

Based on the approach used by Minisign, both kx-aspe-web and kx-aspe-cli use scrypt to derive a key from a user-provided password and use said key to XOR the secret cryptographic key. The encrypted key resulting from the XOR operation is then either stored on the filesystem (kx-aspe-cli) or presented to the user to store in a password manager (kx-aspe-web).

To edit the profile at a later moment, the user must provide their password at the moment of uploading so that the secret key may be decrypted and used to sign the JWSs.

Note that the ASP specification does not favor a particular method for securing cryptographic keys.

Conclusion

Hopefully, this guide will enable more developers to create their own tools and enrich the ASP ecosystem!

If you enjoy the ASP profiles, you can help us by supporting the Keyoxide project on OpenCollective.