EdDSA Signatures in Tokens

EdDSA Signatures in Tokens

Introduction to EdDSA

EdDSA is a high performant, state-of-the-art digital signature scheme. There are two main variants: Ed25519 and Ed448 which are the names of the underlying Edwards Curves. One of the reasons for EdDSA's performance, is the small size of the public keys (32 or 57 bytes) and signatures (64 or 114 bytes). EdDSA is also very secure for several reasons:

  1. EdDSA uses a deterministic nonce that removes the requirement of a random number generator compared to ECDSA. Poor generation of a nonce can break an ECDSA system. This vulnerability does not apply for EdDSA.
  2. EdDSA is designed to be more resilient to side-channel attacks, that is, attacks that analyze for example power consumption or timing to gain information about the operation and keys. One method to mitigate the risk for side-channel attacks are constant-time implementations. There is no need for expensive point validation in EdDSA because of its complete formulas. Consequently, EdDSA is easier to implement and to implement securely.
  3. The algorithm supported by the Curity Identity Server, also called PureEdDSA is known to provide collision resilience. That means that collisions in the hash-function do not break the system.

There has been enough time for researchers to study EdDSA since the publication of the original paper in 2011. In addition, with RFC 8032 an implementation focused description was published. This enabled developers to add support for the algorithm in their products. With version 7.2, EdDSA is also available in the Curity Identity Server. This tutorial shows how to configure the Curity Identity Server to issue tokens with an EdDSA Signature.

Import an EdDSA Key

If you do not have any key yet, use a tool of your choice to generate an EdDSA key pair. For example, test one of the following commands to generate a key:

keytool -genkeypair -keyalg eddsa -keysize 255 -dname CN=tutorial,O=curityio -keystore eddsa-keystore.p12 -storepass Password1 -alias ed25519-key

This command uses Java's keytool to create a key-pair for EdDSA (-keyalg) with a length of 255 bits (-keysize). This key can be used with the curve Ed25519. The command also creates a self-signed certificate with the given distinguished name (-dname). The results are stored in the provided keystore (-keystore and -storepass) under the given name (-alias). The alias is used to identify the key in case there are several entries in the keystore.

openssl genpkey -algorithm ed25519 -out ed25519-key.pem

This is a simple and compact command that just creates the key pair and no certificate. The key can be used with the curve Ed25519.

Unprotected key

Use the command with caution! Do not use in production. The private key is unencrypted.

With the key available, open the Facilities menu and navigate to Signing Keys. Click on + New next to it. In the form enter a name and choose asymmetric as the type of the new signing key.

Import existing Signing Key

Click on Upload Existing. Select the keystore or file containing the private EdDSA key. Enter the password and alias if necessary.

Import existing Signing Key

Add and Commit the configuration.

Verify the Key

Open the Facilities menu and navigate to Signing Keys. Select the key with the name from above.

Verify Signing Key

Double-check the values: issuer, expiration dates and fingerprints of the certificate (if any); algorithm, curve and public key x of the JWK.

EdDSA was designed with high performance in mind. You can literally see that. Take the time to acknowledge how small (short) the encoded public key is: 256 bits compared to several thousand bits for RSA keys; a single parameter compared to two for an elliptic curve key.

Issue Tokens with EdDSA

To create tokens with an EdDSA signature, configure the Token Issuer with an EdDSA key. Select the Token Service from the profiles. Click on Token Issuers in the menu.

Configure Token Issuer

Scroll down. Select EdDSA from the drop-down for the algorithm. From the drop-down for the signing key select an appropriate EdDSA key, e.g. eddsa-signing-key from the example above. Commit the changes.

Configure Token Issuer

The Curity Identity Server publishes its keys in a jwks_uri. It was updated with the EdDSA key. When you navigate to the JWKS endpoint of your instance of the Curity Identity Server you can verify the key. If you use the default settings from the configuration wizard and run the server on localhost the JWKS endpoint will look like this: https://localhost:8443/oauth/v2/oauth-anonymous/jwks. The result looks similar to the following json and should match the key from above.

{"keys": [
  {
    "kty":"OKP",
    "kid":"1810805287",
    "use":"sig",
    "alg":"EdDSA",
    "crv":"Ed25519",
    "x":"9T2s4FQy0bg7AJ5w_k2gkgTLxHd0S1Fj6RRHEjn9tMw",
    "x5t":"SUyrxNZQjpV0L93qk55tVldxlmk"
  }
]}

Testing

The easiest way is to use OAuth.tools for retrieving and parsing tokens.

However, you need a valid client configuration for testing. Download and import the sample configuration from the developer portal or follow other tutorials to learn how to run certain flows to retrieve a token.

Here is an example for an access token with an EdDSA signature:

eyJraWQiOiIxODEwODA1Mjg3IiwieDV0IjoiU1V5cnhOWlFqcFYwTDkzcWs1NXRWbGR4bG1rIiwieDV0I1MyNTYiOiJUM2FOcE9rMXJSZld1VjlLRkRpZ1RHcktyWTVEdjJxWlhBS1A2UUFjdlIwIiwiYWxnIjoiRWREU0EifQ.eyJqdGkiOiI5OWM5NGE0YS0wMGU1LTRjMDUtOWUzYS0zMTY3ZDdjYzU5MzkiLCJkZWxlZ2F0aW9uSWQiOiJjOWM3MjcwYy1mZThhLTRkOTQtODQwMC1hZTU4NDM0NjIwN2QiLCJleHAiOjE2NTM5MDY5NDIsIm5iZiI6MTY1MzkwNjY0Miwic2NvcGUiOiJyZWFkIG9wZW5pZCIsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMvb2F1dGgvdjIvb2F1dGgtYW5vbnltb3VzIiwic3ViIjoidGVzdHVzZXIiLCJhdWQiOiJ0ZXN0Y2xpZW50IiwiaWF0IjoxNjUzOTA2NjQyLCJwdXJwb3NlIjoiYWNjZXNzX3Rva2VuIn0.u5k1G4jOA4bANyonCQ0q8K2jT6rX2V6vP4xEZalt2iWmajqHZp2peDZaQffwnNk6bS4oQSOtQ4a2A6AaUuJ5Bg

Header

{
  "kid": "1810805287",
  "x5t": "SUyrxNZQjpV0L93qk55tVldxlmk",
  "x5t#S256": "T3aNpOk1rRfWuV9KFDigTGrKrY5Dv2qZXAKP6QAcvR0",
  "alg": "EdDSA"
}

Payload

{
  "jti": "99c94a4a-00e5-4c05-9e3a-3167d7cc5939",
  "delegationId": "c9c7270c-fe8a-4d94-8400-ae584346207d",
  "exp": 1653906942,
  "nbf": 1653906642,
  "scope": "read openid",
  "iss": "https://localhost:8443/oauth/v2/oauth-anonymous",
  "sub": "testuser",
  "aud": "testclient",
  "iat": 1653906642,
  "purpose": "access_token"
}

Check out and take a deep dive into the code example for Securing a Java API with JWTs. It supports the validation of EdDSA signed tokens and thus contains the code on how to validate an EdDSA signature in Java.