Home

Awesome

Rhonabwy

NOTICE: This project is no longer being maintained. ⚠️

This project is now closed for me, I have no time nor motivation to maintain it, so I prefer closing this repository.

Disclaimer

This library is a personal project mostly developped by myself on my free time, with gracious help from users.

Several bugs and security issues were found and fixed in this library but there are probably more left. Nevertheless I have less time to work on it.

If you are looking for alternatives, there are multiple other JOSE libraries that can fit demanding needs, see https://jwt.io/libraries for example.

Javascript Object Signing and Encryption (JOSE) library - JWK, JWKS, JWS, JWE and JWT

JWT Relies on JWS and JWE functions, so it supports the same functionalities as the other 2. JWT functionalities also support nesting serialization (JWE nested in a JWS or the opposite).

"alg" Param ValueDigital Signature or MAC AlgorithmSupported
HS256HMAC using SHA-256YES
HS384HMAC using SHA-384YES
HS512HMAC using SHA-512YES
RS256RSASSA-PKCS1-v1_5 using SHA-256YES
RS384RSASSA-PKCS1-v1_5 using SHA-384YES
RS512RSASSA-PKCS1-v1_5 using SHA-512YES
ES256ECDSA using P-256 and SHA-256YES(1)
ES384ECDSA using P-384 and SHA-384YES(1)
ES512ECDSA using P-521 and SHA-512YES(1)
PS256RSASSA-PSS using SHA-256 and MGF1 with SHA-256YES(1)
PS384RSASSA-PSS using SHA-384 and MGF1 with SHA-384YES(1)
PS512RSASSA-PSS using SHA-512 and MGF1 with SHA-512YES(1)
noneNo digital signature or MAC performedYES
EdDSADigital Signature with Ed25519 Elliptic CurveYES(1)
ES256KDigital Signature with secp256k1 Curve KeyNO

(1) GnuTLS 3.6 minimum is required for ECDSA, Ed25519 (EdDSA) and RSA-PSS signatures.

"enc" Param ValueContent Encryption AlgorithmSupported
A128CBC-HS256AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm, as defined in Section 5.2.3YES
A192CBC-HS384AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm, as defined in Section 5.2.4YES
A256CBC-HS512AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm, as defined in Section 5.2.5YES
A128GCMAES GCM using 128-bit keyYES
A192GCMAES GCM using 192-bit keyYES (2)
A256GCMAES GCM using 256-bit keyYES

(2) GnuTLS 3.6.14 minimum is required for A192GCM enc.

"alg" Param ValueKey Management AlgorithmSupported
RSA1_5RSAES-PKCS1-v1_5YES
RSA-OAEPRSAES OAEP using default parametersYES(3)
RSA-OAEP-256RSAES OAEP using SHA-256 and MGF1 with SHA-256YES
A128KWAES Key Wrap with default initial value using 128-bit keyYES(3)
A192KWAES Key Wrap with default initial value using 192-bit keyYES(3)
A256KWAES Key Wrap with default initial value using 256-bit keyYES(3)
dirDirect use of a shared symmetric key as the CEKYES
ECDH-ESElliptic Curve Diffie-Hellman Ephemeral Static key agreement using Concat KDFYES(4)
ECDH-ES+A128KWECDH-ES using Concat KDF and CEK wrapped with "A128KW"YES(4)
ECDH-ES+A192KWECDH-ES using Concat KDF and CEK wrapped with "A192KW"YES(4)
ECDH-ES+A256KWECDH-ES using Concat KDF and CEK wrapped with "A256KW"YES(4)
A128GCMKWKey wrapping with AES GCM using 128-bit keyYES
A192GCMKWKey wrapping with AES GCM using 192-bit keyYES(5)
A256GCMKWKey wrapping with AES GCM using 256-bit keyYES
PBES2-HS256+A128KWPBES2 with HMAC SHA-256 and "A128KW" wrappingYES(5)
PBES2-HS384+A192KWPBES2 with HMAC SHA-384 and "A192KW" wrappingYES(5)
PBES2-HS512+A256KWPBES2 with HMAC SHA-512 and "A256KW" wrappingYES(5)

(3) Nettle 3.4 minimum is required for RSA-OAEP and AES key Wrap

(4) Nettle 3.6 minimum is required for ECDH-ES

(5) GnuTLS 3.6.14 minimum is required for A192GCMKW, PBES2-HS256+A128KW, PBES2-HS384+A192KW and PBES2-HS512+A256KW key wrapping algorithms.

rnbyc, Rhonabwy command-line tool

This command-line program can be used to:

Example commands to generate a RSA2048 key pair, serialize a JWT signed with the private key, then parse the serialized token and verifies the signature with the public key.

$ rnbyc -j -g RSA2048 -o priv.jwks -p pub.jwks
$ rnbyc -s '{"iss":"https://rhonabwy.tld","aud":"abcxyz1234"}' -K priv.jwks -a RS256
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImVNdnI3bktBX2I5QUI4NGpMU05zTFFKZHRmdHpadnllV2M1V0VVMjhnRFkifQ.eyJpc3MiOiJodHRwczovL3Job25hYnd5LnRsZCIsImF1ZCI6ImFiY3h5ejEyMzQifQ.j6v-yxcWvHhyLIc-r3Nzn5rCF9yeJJzgyLSHW_10wREfckspbzf8UTof5Zsrwg8JvKNlJ4Tt4ZffJC4BkkehdBYXPrgcfq9NtvNYsRmAdiNJhOXtZCU9j9X89j2xhY7pRBgWENI9c3730cmAUgaC-IUKsoNRw_dd-eboyrgYKIzUCYRnuwqDB31T2oUSVjy6CckoenyoeHJhHg-x384G-g4ovP1l-L4YpjgCyr6BR8mjBFwHU56MP6hNN299HpUd56usQ3vMn7z5hL6QqE92qz-SsJBySrv8whLWjjN9J4Wq5g3_R7Qw00x60bFnuCDhPBjg3EPXXGqlI0x0vwgwHw
$ rnbyc -P pub.jwks -t eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImVNdnI3bktBX2I5QUI4NGpMU05zTFFKZHRmdHpadnllV2M1V0VVMjhnRFkifQ.eyJpc3MiOiJodHRwczovL3Job25hYnd5LnRsZCIsImF1ZCI6ImFiY3h5ejEyMzQifQ.j6v-yxcWvHhyLIc-r3Nzn5rCF9yeJJzgyLSHW_10wREfckspbzf8UTof5Zsrwg8JvKNlJ4Tt4ZffJC4BkkehdBYXPrgcfq9NtvNYsRmAdiNJhOXtZCU9j9X89j2xhY7pRBgWENI9c3730cmAUgaC-IUKsoNRw_dd-eboyrgYKIzUCYRnuwqDB31T2oUSVjy6CckoenyoeHJhHg-x384G-g4ovP1l-L4YpjgCyr6BR8mjBFwHU56MP6hNN299HpUd56usQ3vMn7z5hL6QqE92qz-SsJBySrv8whLWjjN9J4Wq5g3_R7Qw00x60bFnuCDhPBjg3EPXXGqlI0x0vwgwHw
Token signature verified
{
  "iss": "https://rhonabwy.tld",
  "aud": "abcxyz1234"
}

Check its documentation

API Documentation

Documentation is available in the documentation page: https://babelouest.github.io/rhonabwy/

Example program to parse and verify the signature of a JWT using its public key in JWK format:

/**
 * To compile this program run:
 * gcc -o demo_rhonabwy demo_rhonabwy.c -lrhonabwy
 */
#include <stdio.h>
#include <rhonabwy.h>

int main(void) {
  const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjEifQ."                                     // Header
                       "eyJzdHIiOiJwbG9wIiwiaW50Ijo0Miwib2JqIjp0cnVlfQ."                                         // Claims
                       "ooXNEt3JWFGMuvkGUM-szUOU1QTu4DvyC3qQP64UGeeJQuMGupBCVATnGkiqNLiPSJ9uBsjZbyUrWe8z7Iag_A"; // Signature

  const char jwk_pubkey_ecdsa_str[] = "{"
                                        "\"kty\":\"EC\","
                                        "\"crv\":\"P-256\","
                                        "\"alg\":\"ES256\","
                                        "\"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\","
                                        "\"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\","
                                        "\"kid\":\"1\","
                                        "\"use\":\"sig\""
                                      "}";

  unsigned char output[2048];
  size_t output_len = 2048;
  jwk_t * jwk = NULL;
  jwt_t * jwt = NULL;
  char * claims;

  if ((jwk = r_jwk_quick_import(R_IMPORT_JSON_STR, jwk_pubkey_ecdsa_str)) != NULL && (jwt = r_jwt_quick_parse(token, R_PARSE_NONE, 0)) != NULL) {
    if (r_jwk_export_to_pem_der(jwk, R_FORMAT_PEM, output, &output_len, 0) == RHN_OK) {
      printf("Exported key:\n%.*s\n", (int)output_len, output);
      if (r_jwt_verify_signature(jwt, jwk, 0) == RHN_OK) {
        claims = r_jwt_get_full_claims_str(jwt);
        printf("Verified payload:\n%s\n", claims);
        r_free(claims);
      } else {
        fprintf(stderr, "Error r_jwt_verify_signature\n");
      }
    } else {
      fprintf(stderr, "Error r_jwk_export_to_pem_der\n");
    }
  } else {
    fprintf(stderr, "Error parsing\n");
  }
  r_jwk_free(jwk);
  r_jwt_free(jwt);

  return 0;
}

Examples

Some example programs are available in the examples directory.

Installation

Rhonabwy is available in the following distributions.

Packaging status

Dependencies

Rhonabwy is based on Nettle, GnuTLS, Jansson, zlib, libcurl and libsystemd (if possible), you must install those libraries first before building Rhonabwy.

You also need check and Ulfius to run the tests.

Prerequisites

You need Orcania and Yder.

Those libraries are included in the package rhonabwy-dev-full_{x.x.x}_{OS}_{ARCH}.tar.gz in the Latest release page. If you're building with CMake, they will be automatically downloaded and installed if missing.

Manual install

CMake - Multi architecture

CMake minimum 3.5 is required.

Last Rhonabwy release: https://github.com/babelouest/rhonabwy/releases/latest/

Run the CMake script in a sub-directory, example:

$ cd <rhonabwy_source>
$ mkdir build
$ cd build
$ cmake ..
$ make && sudo make install

The available options for CMake are:

Good ol' Makefile

Download Rhonabwy from GitHub repository, compile and install.

Last Rhonabwy release: https://github.com/babelouest/rhonabwy/releases/latest/

$ cd rhonabwy/src
$ make
$ sudo make install

To disable curl library on build (to avoid its dependencies), you can pass the option DISABLE_CURL=1 to the make command.

$ cd rhonabwy/src
$ make DISABLE_CURL=1
$ sudo make install

By default, the shared library and the header file will be installed in the /usr/local location. To change this setting, you can modify the DESTDIR value in the src/Makefile.

Example: install Rhonabwy in /tmp/lib directory

$ cd src
$ make && make DESTDIR=/tmp install

You can install Rhonabwy without root permission if your user has write access to $(DESTDIR). A ldconfig command is executed at the end of the install, it will probably fail if you don't have root permission, but this is harmless. If you choose to install Rhonabwy in another directory, you must set your environment variable LD_LIBRARY_PATH properly.