/rhonabwy

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

Primary LanguageCGNU Lesser General Public License v2.1LGPL-2.1

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

View on jwt.io C/C++ CI

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).

  • Supported Cryptographic Algorithms (alg) for Digital Signatures and MACs:
"alg" Param Value Digital Signature or MAC Algorithm Supported
HS256 HMAC using SHA-256 YES
HS384 HMAC using SHA-384 YES
HS512 HMAC using SHA-512 YES
RS256 RSASSA-PKCS1-v1_5 using SHA-256 YES
RS384 RSASSA-PKCS1-v1_5 using SHA-384 YES
RS512 RSASSA-PKCS1-v1_5 using SHA-512 YES
ES256 ECDSA using P-256 and SHA-256 YES(1)
ES384 ECDSA using P-384 and SHA-384 YES(1)
ES512 ECDSA using P-521 and SHA-512 YES(1)
PS256 RSASSA-PSS using SHA-256 and MGF1 with SHA-256 YES(1)
PS384 RSASSA-PSS using SHA-384 and MGF1 with SHA-384 YES(1)
PS512 RSASSA-PSS using SHA-512 and MGF1 with SHA-512 YES(1)
none No digital signature or MAC performed YES
EdDSA Digital Signature with Ed25519 Elliptic Curve YES(1)
ES256K Digital Signature with secp256k1 Curve Key NO

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

  • Supported Encryption Algorithm (enc) for JWE payload encryption:
"enc" Param Value Content Encryption Algorithm Supported
A128CBC-HS256 AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm, as defined in Section 5.2.3 YES
A192CBC-HS384 AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm, as defined in Section 5.2.4 YES
A256CBC-HS512 AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm, as defined in Section 5.2.5 YES
A128GCM AES GCM using 128-bit key YES
A192GCM AES GCM using 192-bit key YES (2)
A256GCM AES GCM using 256-bit key YES

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

  • Supported Cryptographic Algorithms (alg) for Key Management:
"alg" Param Value Key Management Algorithm Supported
RSA1_5 RSAES-PKCS1-v1_5 YES
RSA-OAEP RSAES OAEP using default parameters YES(3)
RSA-OAEP-256 RSAES OAEP using SHA-256 and MGF1 with SHA-256 YES
A128KW AES Key Wrap with default initial value using 128-bit key YES(3)
A192KW AES Key Wrap with default initial value using 192-bit key YES(3)
A256KW AES Key Wrap with default initial value using 256-bit key YES(3)
dir Direct use of a shared symmetric key as the CEK YES
ECDH-ES Elliptic Curve Diffie-Hellman Ephemeral Static key agreement using Concat KDF YES(4)
ECDH-ES+A128KW ECDH-ES using Concat KDF and CEK wrapped with "A128KW" YES(4)
ECDH-ES+A192KW ECDH-ES using Concat KDF and CEK wrapped with "A192KW" YES(4)
ECDH-ES+A256KW ECDH-ES using Concat KDF and CEK wrapped with "A256KW" YES(4)
A128GCMKW Key wrapping with AES GCM using 128-bit key YES
A192GCMKW Key wrapping with AES GCM using 192-bit key YES(5)
A256GCMKW Key wrapping with AES GCM using 256-bit key YES
PBES2-HS256+A128KW PBES2 with HMAC SHA-256 and "A128KW" wrapping YES(5)
PBES2-HS384+A192KW PBES2 with HMAC SHA-384 and "A192KW" wrapping YES(5)
PBES2-HS512+A256KW PBES2 with HMAC SHA-512 and "A256KW" wrapping YES(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:

  • Generate and/or parse keys and output the result in a JWKS or a public/private pair of JWKS files.
  • Parse, decrypt, and/or verify signature of a JWT, using given key
  • Serialize a JWT, the JWT can be signed, encrypted or nested

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;
}

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.

Pre-compiled packages

You can install Rhonabwy with a pre-compiled package available in the release pages.

rhonabwy-dev-full packages

The rhonabwy-dev-full contain 4 different packages:

  • liborcania-dev_x.x.x_.ext
  • libyder-dev_y.y.y_.ext
  • libulfius-dev_z.z.z_.ext
  • librhonabwy-dev_a.a.a_.ext

You only need to install liborcania-dev_*, libyder-dev_* for librhonabwy-dev_* to work. libulfius-dev_* isn't required unless you want to run the test suite.

Manual install

CMake - Multi architecture

CMake minimum 3.5 is required.

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

$ git clone https://github.com/babelouest/rhonabwy.git
$ cd rhonabwy/
$ mkdir build
$ cd build
$ cmake ..
$ make && sudo make install

The available options for CMake are:

  • -DWITH_JOURNALD=[on|off] (default on): Build with journald (SystemD) support
  • -BUILD_RHONABWY_TESTING=[on|off] (default off): Build unit tests
  • -DINSTALL_HEADER=[on|off] (default on): Install header file rhonabwy.h
  • -DBUILD_RPM=[on|off] (default off): Build RPM package when running make package
  • -DCMAKE_BUILD_TYPE=[Debug|Release] (default Release): Compile with debugging symbols or not
  • -DBUILD_STATIC=[on|off] (default off): Compile static library
  • -DBUILD_RHONABWY_DOCUMENTATION=[on|off] (default off): Build documentation with doxygen
  • -DWITH_CURL=[on|off] (default on): Use libcurl to download remote content

Good ol' Makefile

Download Rhonabwy from GitHub repository, compile and install.

$ git clone https://github.com/babelouest/rhonabwy.git
$ 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.