Rhonabwy API documentation

Rhonabwy library is made to manage JWK, JWKS, JWS, JWE and JWT according to their respective RFCs:

- JSON Web Keys (JWK) and JSON Web Keys Set (JWKS)
- JSON Web Signatures (JWS)
- JSON Web Encryption (JWE)
- JSON Web Token (JWT)

Rhonabwy is based on the following libraries and actively uses them:

- GnuTLS for the cryptographic functions
- Jansson for the JSON manipulation
- Yder for the logs
- Libcurl when it requires to retrieve keys from an URL

When relevant, a function can accept or return GnuTLS or Jansson data. But if you're not using those in your application and prefer raw data, you can use the more agnostic functions.

# Return values

Lots of functions in Rhonabwy library return an int value. The returned value can be one of the following:

#define RHN_OK 0
#define RHN_ERROR 1
#define RHN_ERROR_MEMORY 2
#define RHN_ERROR_PARAM 3
#define RHN_ERROR_UNSUPPORTED 4
#define RHN_ERROR_INVALID 5

If a function is successful, it will return `RHN_OK` (0), otherwise an error code is returned.

# Global init and close

It's recommended to use `r_global_init` and `r_global_close` at the beginning and at the end of your program to initialize and cleanup internal values and settings. This will make outgoing requests faster, especially if you use lots of them, and dispatch your memory allocation functions in curl and Jansson if you changed them. These functions are NOT thread-safe, so you must use them in a single thread context.

int r_global_init(void);
void r_global_close(void);
r_global_close
void r_global_close(void)
Definition: misc.c:59
r_global_init
int r_global_init(void)
Definition: misc.c:37

# Log messages

Usually, a log message is displayed to explain more specifically what happened on error. The log manager used is Yder. You can enable Yder log messages on the console with the following command at the beginning of your program:

int main(void) {
y_init_logs("Rhonabwy", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Starting Rhonabwy client program");
// Do your code here
y_close_logs();
}

Example of an error log message:

2020-04-05T16:14:31 - Rhonabwy: r_jwk_is_valid - Invalid alg

Go to Yder API Documentation for more details.

# Memory management

All typedefs managed by Rhonabwy use dedicated init and free functions. You must always use those functions to allocate or free resources manipulated by the library.

int r_jwk_init(jwk_t ** jwk);
void r_jwk_free(jwk_t * jwk);
int r_jwks_init(jwks_t ** jwks);
void r_jwks_free(jwks_t * jwks);
int r_jws_init(jws_t ** jws);
void r_jws_free(jws_t * jws);
int r_jwe_init(jwe_t ** jwe);
void r_jwe_free(jwe_t * jwe);
int r_jwt_init(jwt_t ** jwt);
void r_jwt_free(jwt_t * jwt);
r_jwe_free
void r_jwe_free(jwe_t *jwe)
Definition: jwe.c:2540
r_jws_init
int r_jws_init(jws_t **jws)
Definition: jws.c:875
r_jws_free
void r_jws_free(jws_t *jws)
Definition: jws.c:918
r_jwk_free
void r_jwk_free(jwk_t *jwk)
Definition: jwk.c:57
r_jwks_free
void r_jwks_free(jwks_t *jwks)
Definition: jwks.c:41
r_jwt_free
void r_jwt_free(jwt_t *jwt)
Definition: jwt.c:95
r_jwks_init
int r_jwks_init(jwks_t **jwks)
Definition: jwks.c:30
r_jwe_init
int r_jwe_init(jwe_t **jwe)
Definition: jwe.c:2486
r_jwt_init
int r_jwt_init(jwt_t **jwt)
Definition: jwt.c:34
r_jwk_init
int r_jwk_init(jwk_t **jwk)
Definition: jwk.c:46
jwk_t
json_t jwk_t
Definition: rhonabwy.h:111
jwks_t
json_t jwks_t
Definition: rhonabwy.h:112
jwe_t
Definition: rhonabwy.h:257
jws_t
Definition: rhonabwy.h:243
jwt_t
Definition: rhonabwy.h:282

In addition, when a function return a `char *` value, this value must be freed using the function `r_free(void *)`.

void r_free(void * data);
r_free
void r_free(void *data)
Definition: misc.c:713

And finally, all `json_t *` returned values must be de allocated using `json_decref(json_t *)`, see Jansson Documentation for more details.

# Library information

The functions `r_library_info_json_t()` and `r_library_info_json_str()` return a JSON object that represents the signature and encryption algorithms supported, as well as the library version.

Example output:

{
"version": "0.9.9999",
"jws": {
"alg": [
"none",
"HS256",
"HS384",
"HS512",
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
"EdDSA",
"PS256",
"PS384",
"PS512"
]
},
"jwe": {
"alg": [
"RSA1_5",
"RSA-OAEP",
"RSA-OAEP-256",
"A128KW",
"A192KW",
"A256KW",
"dir",
"A128GCMKW",
"A192GCMKW",
"A256GCMKW",
"PBES2-HS256+A128KW",
"PBES2-HS384+A192KW",
"PBES2-HS512+A256KW",
"ECDH-ES",
"ECDH-ES+A128KW",
"ECDH-ES+A192KW",
"ECDH-ES+A256KW"
],
"enc": [
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512",
"A128GCM",
"A256GCM",
"A192GCM"
]
}
}

# Header or Claim integer value

When using `r_jws_set_header_int_value`, `r_jwe_set_header_int_value`, `r_jwt_set_header_int_value` or `r_jwt_set_claim_int_value`, the int value must be of type `rhn_int_t`, which inner format depend on the architecture. It's recommended not to use an `int` instead, or undefined behaviour may happen.

Likewise, the functions `r_jws_get_header_int_value`, `r_jwe_get_header_int_value`, `r_jwt_get_header_int_value` or `r_jwt_get_claim_int_value`, these functions will return a `rhn_int_t`.

To use a `rhn_int_t` in a printf-like function, you can use the macro `RHONABWY_INTEGER_FORMAT`:

rhn_int_t val = 42;
printf("value: %"RHONABWY_INTEGER_FORMAT"\n", val);
RHONABWY_INTEGER_FORMAT
#define RHONABWY_INTEGER_FORMAT
Definition: rhonabwy.h:115
rhn_int_t
json_int_t rhn_int_t
Definition: rhonabwy.h:113

# JWK

A JWK (JSON Web Key) is a format used to store and represent a cryptographic key in a JSON object.

Example of JWK:

{
"kty":"EC",
"crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"kid":"Public key used in JWS spec Appendix A.3 example"
}

The standard allows to store public and private keys for RSA and ECC algorithms, it also allows to store symmetric keys. In a JWK, every raw value is encoded in Base64Url format to fit in the JSON object without any issue.

A JWK is represented in Rhonabwy library using the type `jwk_t *`.

## Import and Export JWK

Rhonabwy allows to import and export a JWK in the following formats:

- A JSON structure in a `const char *`
- A JSON structure in a `json_t *`
- A key or certificate in `PEM` or `DER` format
- A `GnuTLS` structure of the following: `gnutls_privkey_t`, `gnutls_pubkey_t` or `gnutls_x509_crt_t` (import only)

If the imported JWK contains a `x5u` property, the key or certificate will be downloaded at the given address. If so, you can give an additional parameter `x5u_flag` which values can be:

- `R_FLAG_IGNORE_SERVER_CERTIFICATE`: ignore if web server certificate is invalid
- `R_FLAG_FOLLOW_REDIRECT`: follow redirection if necessary
- `R_FLAG_IGNORE_REMOTE`: do not download remote key, but the function may return an error

int r_jwk_import_from_json_str(jwk_t * jwk, const char * input);
int r_jwk_import_from_json_t(jwk_t * jwk, json_t * j_input);
int r_jwk_import_from_pem_der(jwk_t * jwk, int type, int format, const unsigned char * input, size_t input_len);
int r_jwk_import_from_gnutls_privkey(jwk_t * jwk, gnutls_privkey_t key);
int r_jwk_import_from_gnutls_pubkey(jwk_t * jwk, gnutls_pubkey_t pub);
int r_jwk_import_from_gnutls_x509_crt(jwk_t * jwk, gnutls_x509_crt_t crt);
int r_jwk_import_from_x5u(jwk_t * jwk, int x5u_flags, const char * x5u);
int r_jwk_import_from_x5c(jwk_t * jwk, const char * x5c);
int r_jwk_import_from_symmetric_key(jwk_t * jwk, const unsigned char * key, size_t key_len);
int r_jwk_import_from_password(jwk_t * jwk, const char * password);
int r_jwk_extract_pubkey(jwk_t * jwk_privkey, jwk_t * jwk_pubkey, int x5u_flags);
jwk_t * r_jwk_quick_import(rhn_import type, ...);
r_jwk_import_from_password
int r_jwk_import_from_password(jwk_t *jwk, const char *password)
Definition: jwk.c:1886
r_jwk_import_from_json_str
int r_jwk_import_from_json_str(jwk_t *jwk, const char *input)
Definition: jwk.c:899
r_jwk_import_from_pem_der
int r_jwk_import_from_pem_der(jwk_t *jwk, int type, int format, const unsigned char *input, size_t input_len)
Definition: jwk.c:932
r_jwk_quick_import
jwk_t * r_jwk_quick_import(rhn_import type,...)
Definition: jwk.c:1890
r_jwk_import_from_json_t
int r_jwk_import_from_json_t(jwk_t *jwk, json_t *j_input)
Definition: jwk.c:916
r_jwk_import_from_gnutls_x509_crt
int r_jwk_import_from_gnutls_x509_crt(jwk_t *jwk, gnutls_x509_crt_t crt)
Definition: jwk.c:1771
r_jwk_import_from_symmetric_key
int r_jwk_import_from_symmetric_key(jwk_t *jwk, const unsigned char *key, size_t key_len)
Definition: jwk.c:1857
r_jwk_import_from_x5c
int r_jwk_import_from_x5c(jwk_t *jwk, const char *x5c)
Definition: jwk.c:1829
r_jwk_import_from_gnutls_pubkey
int r_jwk_import_from_gnutls_pubkey(jwk_t *jwk, gnutls_pubkey_t pub)
Definition: jwk.c:1508
r_jwk_extract_pubkey
int r_jwk_extract_pubkey(jwk_t *jwk_privkey, jwk_t *jwk_pubkey, int x5u_flags)
Definition: jwk.c:848
r_jwk_import_from_x5u
int r_jwk_import_from_x5u(jwk_t *jwk, int x5u_flags, const char *x5u)
Definition: jwk.c:1807
r_jwk_import_from_gnutls_privkey
int r_jwk_import_from_gnutls_privkey(jwk_t *jwk, gnutls_privkey_t key)
Definition: jwk.c:1061
rhn_import
rhn_import
Definition: rhonabwy.h:228

The values `R_FLAG_IGNORE_SERVER_CERTIFICATE` and `R_FLAG_FOLLOW_REDIRECT` can be merged: `R_FLAG_IGNORE_SERVER_CERTIFICATE|R_FLAG_FOLLOW_REDIRECT`

## Manipulate JWK properties

You can manipulate the JWK properties directly using the dedicated functions:

const char * r_jwk_get_property_str(jwk_t * jwk, const char * key);
const char * r_jwk_get_property_array(jwk_t * jwk, const char * key, size_t index);
int r_jwk_set_property_str(jwk_t * jwk, const char * key, const char * value);
int r_jwk_set_property_array(jwk_t * jwk, const char * key, size_t index, const char * value);
int r_jwk_append_property_array(jwk_t * jwk, const char * key, const char * value);
int r_jwk_delete_property_str(jwk_t * jwk, const char * key);
int r_jwk_delete_property_array_at(jwk_t * jwk, const char * key, size_t index);
r_jwk_set_property_array
int r_jwk_set_property_array(jwk_t *jwk, const char *key, size_t index, const char *value)
Definition: jwk.c:2820
r_jwk_get_property_str
const char * r_jwk_get_property_str(jwk_t *jwk, const char *key)
Definition: jwk.c:2769
r_jwk_delete_property_str
int r_jwk_delete_property_str(jwk_t *jwk, const char *key)
Definition: jwk.c:2862
r_jwk_append_property_array
int r_jwk_append_property_array(jwk_t *jwk, const char *key, const char *value)
Definition: jwk.c:2844
r_jwk_set_property_str
int r_jwk_set_property_str(jwk_t *jwk, const char *key, const char *value)
Definition: jwk.c:2807
r_jwk_get_property_array
const char * r_jwk_get_property_array(jwk_t *jwk, const char *key, size_t index)
Definition: jwk.c:2781
r_jwk_delete_property_array_at
int r_jwk_delete_property_array_at(jwk_t *jwk, const char *key, size_t index)
Definition: jwk.c:2875

## Validate the format of a JWK

The function `r_jwk_is_valid` will check the validity of a JWK, i.e. check if all the required properties are present and in the correct format. Note that this function is called each time an import is made.

## Generate a random key pair

You can use Rhonabwy to generate a random key pair for RSA, ECC or OKP algorithms. The `jwk_t *` parameters must be initialized first.

The `type` parameter can have one of the following values: `R_KEY_TYPE_RSA` `R_KEY_TYPE_EC`, `R_KEY_TYPE_EDDSA` or `R_KEY_TYPE_ECDH`. The `bits` parameter specifies the length of the key. A RSA key must be at least 2048 bits, and the bits value allowed for an ECC key are 256, 384 or 512.

If the parameter `kid` is used, the generated key kid property will have the kid specified, otherwise a `kid` will be generated to identify the key pair.

int r_jwk_generate_key_pair(jwk_t * jwk_privkey, jwk_t * jwk_pubkey, int type, unsigned int bits, const char * kid);
r_jwk_generate_key_pair
int r_jwk_generate_key_pair(jwk_t *jwk_privkey, jwk_t *jwk_pubkey, int type, unsigned int bits, const char *kid)
Definition: jwk.c:491

# JWKS

A JWKS (JSON Web Key Set) is a format used to store and represent a set cryptographic key in a JSON object. A JWKS is always a JSON object containing the property `"keys"` that will point to an array of JWK.

Example of JWKS:

{
"keys":
[
{
"kty":"EC",
"crv":"P-256",
"x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use":"enc",
"kid":"1"
},
{
"kty":"RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e":"AQAB",
"alg":"RS256",
"kid":"2011-04-29"
}
]
}

In Rhonabwy library, you can manipulate the JWKS inside a JWKS by iteration or get a JWK by its kid.

jwk_t * r_jwks_get_at(jwks_t * jwks, size_t index);
jwk_t * r_jwks_get_by_kid(jwks_t * jwks, const char * kid);
r_jwks_get_by_kid
jwk_t * r_jwks_get_by_kid(jwks_t *jwks, const char *kid)
Definition: jwks.c:84
r_jwks_get_at
jwk_t * r_jwks_get_at(jwks_t *jwks, size_t index)
Definition: jwks.c:76

You can also import a JWKS using a JSON object or an URL.

int r_jwks_import_from_json_str(jwks_t * jwks, const char * input);
int r_jwks_import_from_json_t(jwks_t * jwks, json_t * j_input);
int r_jwks_import_from_uri(jwks_t * jwks, const char * uri, int flags);
jwks_t * r_jwks_quick_import(rhn_import, ...);
r_jwks_import_from_uri
int r_jwks_import_from_uri(jwks_t *jwks, const char *uri, int x5u_flags)
Definition: jwks.c:310
r_jwks_import_from_json_t
int r_jwks_import_from_json_t(jwks_t *jwks, json_t *j_input)
Definition: jwks.c:271
r_jwks_import_from_json_str
int r_jwks_import_from_json_str(jwks_t *jwks, const char *input)
Definition: jwks.c:248
r_jwks_quick_import
jwks_t * r_jwks_quick_import(rhn_import type,...)
Definition: jwks.c:336

# JWS

A JWS (JSON Web Signature) is a content digitally signed and serialized in a compact or JSON format that can be easily transferred in HTTP requests.

A compact JWS has 3 elements serialized in base64url format and separated by a dot (.). The 3 elements are:

- A header in JSON format
- A Payload
- A digital signature

Its representation uses the following format:

BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) || '.' || BASE64URL(JWS Signature)

The signature is based on the following data:

BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload)

The algorithms supported by Rhonabwy are:

- HMAC with SHA-2 Functions: `HS256`, `HS384`, `HS512`
- Digital Signature with RSASSA-PKCS1-v1_5: `RS256`, `RS384`, `RS512`
- Digital Signature with ECDSA: `ES256`, `ES384`, `ES512`, `ES256K`
- Digital Signature with RSASSA-PSS: `PS256`, `PS384`, `PS512`
- Digital Signature with Ed25519 or Ed448 Elliptic Curve: `EDdSA`
- Unsecured: `none`

## Set values

To set the values of the JWS (header, keys, payload, etc.), you can use the dedicated functions (see the documentation), or use the function `r_jws_set_properties` to set multiple properties at once. The option list MUST end with the option `RHN_OPT_NONE`.

int r_jws_set_properties(jws_t * jws, ...);
r_jws_set_properties
int r_jws_set_properties(jws_t *jws,...)
Definition: jws.c:2136

The available `rhn_opt` and their following values for a `jws_t` are:

RHN_OPT_HEADER_INT_VALUE, const char *, int
RHN_OPT_HEADER_RHN_INT_VALUE, const char *, rhn_int_t
RHN_OPT_HEADER_STR_VALUE, const char * const char *
RHN_OPT_HEADER_JSON_T_VALUE, const char *, json_t *
RHN_OPT_HEADER_FULL_JSON_T, json_t *
RHN_OPT_HEADER_FULL_JSON_STR, const char *
RHN_OPT_PAYLOAD, const unsigned char *, size_t
RHN_OPT_SIG_ALG, jwa_alg
RHN_OPT_SIGN_KEY_JWK, jwk_t *
RHN_OPT_SIGN_KEY_JWKS, jwks_t *
RHN_OPT_SIGN_KEY_GNUTLS, gnutls_privkey_t
RHN_OPT_SIGN_KEY_JSON_T, json_t *
RHN_OPT_SIGN_KEY_JSON_STR, const char *
RHN_OPT_SIGN_KEY_PEM_DER, uint, const unsigned char *, size_t
RHN_OPT_VERIFY_KEY_JWK, jwk_t *
RHN_OPT_VERIFY_KEY_JWKS, jwks_t *
RHN_OPT_VERIFY_KEY_GNUTLS, gnutls_pubkey_t
RHN_OPT_VERIFY_KEY_JSON_T, json_t *
RHN_OPT_VERIFY_KEY_JSON_STR, const char *
RHN_OPT_VERIFY_KEY_PEM_DER, uint, const unsigned char *, size_t
jwa_alg
jwa_alg
Definition: rhonabwy.h:117
RHN_OPT_VERIFY_KEY_JWKS
@ RHN_OPT_VERIFY_KEY_JWKS
Public key set in JWKS format to verify the token signature, following parameter must be a jwks_t * v...
Definition: rhonabwy.h:209
RHN_OPT_SIG_ALG
@ RHN_OPT_SIG_ALG
Signature algorithm, following parameter must be a jwa_alg value.
Definition: rhonabwy.h:198
RHN_OPT_HEADER_JSON_T_VALUE
@ RHN_OPT_HEADER_JSON_T_VALUE
Header JSON value, following parameters must be const char * name, json_t * j_value.
Definition: rhonabwy.h:184
RHN_OPT_HEADER_INT_VALUE
@ RHN_OPT_HEADER_INT_VALUE
Header Integer value, following parameters must be const char * name, int i_value.
Definition: rhonabwy.h:181
RHN_OPT_SIGN_KEY_JSON_T
@ RHN_OPT_SIGN_KEY_JSON_T
Private key in JSON format to sign the token, following parameter must be a json_t * value.
Definition: rhonabwy.h:205
RHN_OPT_HEADER_FULL_JSON_STR
@ RHN_OPT_HEADER_FULL_JSON_STR
Stringified JSON value to set the entire header, following parameter must be const char * str_value.
Definition: rhonabwy.h:186
RHN_OPT_VERIFY_KEY_JWK
@ RHN_OPT_VERIFY_KEY_JWK
Public key in JWK format to verify the token signature, following parameter must be a jwk_t * value.
Definition: rhonabwy.h:208
RHN_OPT_VERIFY_KEY_GNUTLS
@ RHN_OPT_VERIFY_KEY_GNUTLS
Public key in GnuTLS format to verify the token signature, following parameter must be a gnutls_pubke...
Definition: rhonabwy.h:210
RHN_OPT_SIGN_KEY_GNUTLS
@ RHN_OPT_SIGN_KEY_GNUTLS
Private key in GnuTLS format to sign the token, following parameter must be a gnutls_privkey_t value.
Definition: rhonabwy.h:204
RHN_OPT_HEADER_STR_VALUE
@ RHN_OPT_HEADER_STR_VALUE
Header String value, following parameters must be const char * name, const char * str_value.
Definition: rhonabwy.h:183
RHN_OPT_HEADER_FULL_JSON_T
@ RHN_OPT_HEADER_FULL_JSON_T
JSON value to set the entire header, following parameter must be json_t * j_value.
Definition: rhonabwy.h:185
RHN_OPT_VERIFY_KEY_JSON_STR
@ RHN_OPT_VERIFY_KEY_JSON_STR
Public key in stringified JSON format to verify the token signature, following parameter must be a co...
Definition: rhonabwy.h:212
RHN_OPT_SIGN_KEY_JWK
@ RHN_OPT_SIGN_KEY_JWK
Private key in JWK format to sign the token, following parameter must be a jwk_t * value.
Definition: rhonabwy.h:202
RHN_OPT_VERIFY_KEY_PEM_DER
@ RHN_OPT_VERIFY_KEY_PEM_DER
Public key in PEM or DER format to verify the token signature, following parameter must be R_FORMAT_P...
Definition: rhonabwy.h:213
RHN_OPT_SIGN_KEY_PEM_DER
@ RHN_OPT_SIGN_KEY_PEM_DER
Private key in PEM or DER format to sign the token, following parameter must be R_FORMAT_PEM or R_FOR...
Definition: rhonabwy.h:207
RHN_OPT_HEADER_RHN_INT_VALUE
@ RHN_OPT_HEADER_RHN_INT_VALUE
Header rhn_int_t value, following parameters must be const char * name, rhn_int_t i_value.
Definition: rhonabwy.h:182
RHN_OPT_SIGN_KEY_JWKS
@ RHN_OPT_SIGN_KEY_JWKS
Private key set in JWKS format to sign the token, following parameter must be a jwks_t * value.
Definition: rhonabwy.h:203
RHN_OPT_SIGN_KEY_JSON_STR
@ RHN_OPT_SIGN_KEY_JSON_STR
Private key in stringified JSON format to sign the token, following parameter must be a const char * ...
Definition: rhonabwy.h:206
RHN_OPT_VERIFY_KEY_JSON_T
@ RHN_OPT_VERIFY_KEY_JSON_T
Public key in JSON format to verify the token signature, following parameter must be a json_t * value...
Definition: rhonabwy.h:211
RHN_OPT_PAYLOAD
@ RHN_OPT_PAYLOAD
JSON value to set the entire payload, following parameters must be const unsigned char * value,...
Definition: rhonabwy.h:189

Example of usage for `r_jws_set_properties`:

jws_t * jws;
const unsigned char payload[] = {4, 8, 15, 16, 23, 42};
jwk_t * jwk; // Set a private RSA key in this value
r_jws_set_properties(jws, RHN_OPT_HEADER_INT_VALUE, "int", 42,
RHN_OPT_HEADER_STR_VALUE, "str", "a value",
RHN_OPT_HEADER_JSON_T_VALUE, "json", json_true(),
RHN_OPT_PAYLOAD, payload, sizeof(payload),
RHN_OPT_SIG_ALG, R_JWA_ALG_RS256,
RHN_OPT_SIGN_KEY_JWK, jwk,
RHN_OPT_NONE); // Test if return value is RHN_OK
char * token = r_jws_serialize(jws, NULL, 0);
}
r_jws_serialize
char * r_jws_serialize(jws_t *jws, jwk_t *jwk_privkey, int x5u_flags)
Definition: jws.c:1962
RHN_OPT_NONE
@ RHN_OPT_NONE
End option list, mandatory at the end of the option list.
Definition: rhonabwy.h:180
R_JWA_ALG_RS256
@ R_JWA_ALG_RS256
Definition: rhonabwy.h:123

## JWS example

In this example, the payload used is the following message:

The true sign of intelligence is not knowledge but imagination.

The JWS will be signed using HMAC with SHA256 algorithm, in this example, the signing process will use a key identified by the kid "1", therefore the header is the following:

{"alg":"HS256","kid":"1"}

The key used to sign the data is:

{
"kty":"oct",
"alg":"HS256",
"k":"c2VjcmV0",
"kid":"1"
}

Finally, the complete representation of the JWS is the following:

eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.GKxWqRBFr-6X4HfflzGeGvKVsJ8v1-J39Ho2RslC-5o

## Serialize a JWS using Rhonabwy in compact mode

The JWS above can be created with the following sample code:

#include <rhonabwy.h>
jws_t * jws = NULL;
jwk_t * jwk_key_symmetric = NULL;
char * token = NULL;
const unsigned char payload[] = "The true sign of intelligence is not knowledge but imagination.";
const char jwk_key_symmetric_str[] = "{\"kty\":\"oct\",\"alg\":\"HS256\",\"k\":\"c2VjcmV0\",\"kid\":\"1\"}";
if (r_jwk_init(&jwk_key_symmetric) == RHN_OK &&
r_jws_init(&jws) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key_symmetric, jwk_key_symmetric_str) == RHN_OK &&
r_jws_set_alg(jws, R_JWA_ALG_HS256) == RHN_OK &&
r_jws_set_payload(jws, payload, sizeof(payload)) == RHN_OK) {
token = r_jws_serialize(jws, jwk_key_symmetric, 0); // token will store the signed token
}
r_free(token);
r_jws_free(jws);
r_jwk_free(jwk_key_symmetric);
RHN_OK
#define RHN_OK
Definition: rhonabwy.h:46
r_jws_set_payload
int r_jws_set_payload(jws_t *jws, const unsigned char *payload, size_t payload_len)
Definition: jws.c:960
r_jws_set_alg
int r_jws_set_alg(jws_t *jws, jwa_alg alg)
Definition: jws.c:995
R_JWA_ALG_HS256
@ R_JWA_ALG_HS256
Definition: rhonabwy.h:120
rhonabwy.h
Rhonabwy JSON Web Key (JWK) library.

## Parse and validate signature of a JWS using Rhonabwy

The JWS above can be parsed and verified using the following sample code:

#include <rhonabwy.h>
jws_t * jws = NULL;
jwk_t * jwk_key_symmetric = NULL;
const char token[] = "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ."
"VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u."
"GKxWqRBFr-6X4HfflzGeGvKVsJ8v1-J39Ho2RslC-5o";
const char jwk_key_symmetric_str[] = "{\"kty\":\"oct\",\"alg\":\"HS256\",\"k\":\"c2VjcmV0\",\"kid\":\"1\"}";
const char * payload = NULL;
size_t payload_len = 0;
if (r_jwk_init(&jwk_key_symmetric) == RHN_OK &&
r_jws_init(&jws) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key_symmetric, jwk_key_symmetric_str) == RHN_OK &&
r_jws_parse(jws, token, 0) == RHN_OK &&
r_jws_verify_signature(jws, jwk_key_symmetric, 0) == RHN_OK &&
(payload = r_jws_get_payload(jws, &payload_len)) != NULL && payload_len > 0) {
// payload and payload_len will contain the payload data
}
r_jws_free(jws);
r_jwk_free(jwk_key_symmetric);
r_jws_verify_signature
int r_jws_verify_signature(jws_t *jws, jwk_t *jwk_pubkey, int x5u_flags)
Definition: jws.c:1870
r_jws_get_payload
const unsigned char * r_jws_get_payload(jws_t *jws, size_t *payload_len)
Definition: jws.c:985
r_jws_parse
int r_jws_parse(jws_t *jws, const char *jws_str, int x5u_flags)
Definition: jws.c:1411

The functions `r_jws_parse`, `r_jws_parsen`, `r_jws_compact_parse` and `r_jws_compact_parsen` will parse a serialized JWS. If public keys are present in the header, they will be added to the public keys list and can be used to verify the token signature.

int r_jws_parse(jws_t * jws, const char * jws_str, int x5u_flags);
int r_jws_parsen(jws_t * jws, const char * jws_str, size_t jws_str_len, int x5u_flags);
r_jws_parsen
int r_jws_parsen(jws_t *jws, const char *jws_str, size_t jws_str_len, int x5u_flags)
Definition: jws.c:1415

### Compressed payload

The header value `"zip":"DEF"` is used to specify if the JWS payload is compressed using ZIP/Deflate algorithm. Rhonabwy will automatically compress or decompress the decrypted payload during serialization or parse process.

## Unsecured JWS

It's possible to use Rhonabwy for unsecured JWS, with the header `alg:"none"` and an empty signature, using a dedicated set of functions: `r_jws_parse_unsecure`, `r_jws_parsen_unsecure`, `r_jws_compact_parsen_unsecure`, `r_jws_compact_parse_unsecure` and `r_jws_serialize_unsecure`, or using `r_jws_advanced_parse` with the `parse_flags` value `R_PARSE_UNSIGNED` set.

### Parse a unsecured JWS

By default, the functions `r_jws_parse`, `r_jws_parsen`, `r_jws_compact_parse` and `r_jws_compact_parsen` will return `RHN_ERROR_INVALID` if the parsed JWS is unsigned. To parse any JWS, signed or unsigned, you must use the functions `r_jws_parse_unsecure`, `r_jws_parsen_unsecure`, `r_jws_compact_parsen_unsecure` and `r_jws_compact_parse_unsecure`, or using `r_jws_advanced_parse` with the `parse_flags` value `R_PARSE_UNSIGNED` set.

### Serialize an unsecured JWS

Use the function `r_jws_serialize_unsecure` to serialize an unsecured JWS. By design, the functions `r_jws_serialize_json_t` and `r_jws_serialize_json_str` will return NULL with mode `R_JSON_MODE_FLATTENED` on unsecured JWS.

## Advanced parsing

JWS standard allows to add in the JWS header a public key in several forms:

- `jwk`: a public key in JWK format
- `jku`: an url to a JWK Set
- `x5c`: an array of X509 certificates
- `x5u`: an url to a X509 certificate

When using the functions `r_jws_parse`, `r_jws_parsen`, `r_jws_compact_parse`, `r_jws_compact_parsen`, `r_jws_parse_unsecure`, `r_jws_parsen_unsecure`, `r_jws_compact_parsen_unsecure` and `r_jws_compact_parse_unsecure`, by default, if a public key is mentionned in the header, it will be added to the `jws->jwks_pubkey`, so the signature verification will not need to specify a key. This can be dangerous if the token comes from a untrustworthy source and if the token isn't checked properly.

To simplify secure token parsing, you should use the functions `r_jws_advanced_parse[n]`:

int r_jws_advanced_parse(jws_t * jws, const char * jws_str, uint32_t parse_flags, int x5u_flags);
int r_jws_advanced_parsen(jws_t * jws, const char * jws_str, size_t jws_str_len, uint32_t parse_flags, int x5u_flags);
r_jws_advanced_parsen
int r_jws_advanced_parsen(jws_t *jws, const char *jws_str, size_t jws_str_len, uint32_t parse_flags, int x5u_flags)
Definition: jws.c:1431
r_jws_advanced_parse
int r_jws_advanced_parse(jws_t *jws, const char *jws_str, uint32_t parse_flags, int x5u_flags)
Definition: jws.c:1427

## Quick parsing

The quick parsing functions can be used to parse a JWS in one line:

jws_t * r_jws_quick_parse(const char * jws_str, uint32_t parse_flags, int x5u_flags);
jws_t * r_jws_quick_parsen(const char * jws_str, size_t jws_str_len, uint32_t parse_flags, int x5u_flags);
r_jws_quick_parsen
jws_t * r_jws_quick_parsen(const char *jws_str, size_t jws_str_len, uint32_t parse_flags, int x5u_flags)
Definition: jws.c:1853
r_jws_quick_parse
jws_t * r_jws_quick_parse(const char *jws_str, uint32_t parse_flags, int x5u_flags)
Definition: jws.c:1849

### Signature verification

Signature verification is provided by the function `r_jws_verify_signature` which has the following definition:

int r_jws_verify_signature(jws_t * jws, jwk_t * jwk_pubkey, int x5u_flags);

The function `r_jws_verify_signature` will return `RHN_ERROR_INVALID` if the JWS is unsecured.

# JWE

A JWE (JSON Web Encryption) is an encrypted content serialized in a compact format that can be easily transferred in HTTP requests.

Basically the payload is encrypted using AES-CBC or AES-GCM and an Initialization Vector (IV), a authentication tag is generated to validate the decryption, and the AES key used to encrypt the payload is encrypted itself using a symmetric or asymmetric encryption algorithm.

The serialized token has the following format:

BASE64URL(UTF8(JWE Protected Header)) || '.' || BASE64URL(JWE Encrypted Key) || '.' || BASE64URL(JWE Initialization Vector) || '.' || BASE64URL(JWE Ciphertext) || '.' || BASE64URL(JWE Authentication Tag)

In Rhonabwy library, the supported algorithms are:

- Supported Encryption Algorithm (`enc`) for JWE payload encryption: `A128CBC-HS256`, `A192CBC-HS384`, `A256CBC-HS512`, `A128GCM`, `A2192GCM`, `A256GCM`
- Supported Cryptographic Algorithms for Key Management: `RSA1_5` (RSAES-PKCS1-v1_5), `RSA-OAEP`, `RSA-OAEP-256`, `A128KW`, `A192KW`, `A256KW`, `dir` (Direct use of a shared symmetric key), `A128GCMKW`, `A192GCMKW`, `A256GCMKW`, `ECDH-ES`, `ECDH-ES+A128KW`, `ECDH-ES+A192KW`, `ECDH-ES+A256KW`, `PBES2-HS384+A192KW` and `PBES2-HS512+A256KW`, `PBES2-HS256+A128KW`

If you don't specify a Content Encryption Key or an Initialization Vector before the serialization, Rhonabwy will automatically generate one or the other or both depending on the algorithm specified.

## Set values

To set the values of the JWE (header, keys, payload, etc.), you can use the dedicated functions (see the documentation), or use the function `r_jwe_set_properties` to set multiple properties at once. The option list MUST end with the option `RHN_OPT_NONE`.

int r_jwe_set_properties(jwe_t * jwe, ...);
r_jwe_set_properties
int r_jwe_set_properties(jwe_t *jwe,...)
Definition: jwe.c:4364

The available `rhn_opt` and their following values for a `jwe_t` are:

RHN_OPT_HEADER_INT_VALUE, const char *, int
RHN_OPT_HEADER_RHN_INT_VALUE, const char *, rhn_int_t
RHN_OPT_HEADER_STR_VALUE, const char * const char *
RHN_OPT_HEADER_JSON_T_VALUE, const char *, json_t *
RHN_OPT_HEADER_FULL_JSON_T, json_t *
RHN_OPT_HEADER_FULL_JSON_STR, const char *
RHN_OPT_PAYLOAD, const unsigned char *, size_t
RHN_OPT_ENC_ALG, jwa_alg
RHN_OPT_ENC, jwa_enc
RHN_OPT_CIPHER_KEY, const unsigned char *, size_t
RHN_OPT_IV, const unsigned char *, size_t
RHN_OPT_AAD, const unsigned char *, size_t
RHN_OPT_ENCRYPT_KEY_JWK, jwk_t *
RHN_OPT_ENCRYPT_KEY_JWKS, jwks_t *
RHN_OPT_ENCRYPT_KEY_GNUTLS, gnutls_pubkey_t
RHN_OPT_ENCRYPT_KEY_JSON_T, json_t *
RHN_OPT_ENCRYPT_KEY_JSON_STR, const char *
RHN_OPT_ENCRYPT_KEY_PEM_DER, uint, const unsigned char *, size_t
RHN_OPT_DECRYPT_KEY_JWK, jwk_t *
RHN_OPT_DECRYPT_KEY_JWKS, jwks_t *
RHN_OPT_DECRYPT_KEY_GNUTLS, gnutls_privkey_t
RHN_OPT_DECRYPT_KEY_JSON_T, json_t *
RHN_OPT_DECRYPT_KEY_JSON_STR, const char *
RHN_OPT_DECRYPT_KEY_PEM_DER, uint, const unsigned char *, size_t
jwa_enc
jwa_enc
Definition: rhonabwy.h:169
RHN_OPT_DECRYPT_KEY_JWK
@ RHN_OPT_DECRYPT_KEY_JWK
Private key in JWK format to decrypt the token, following parameter must be a jwk_t * value.
Definition: rhonabwy.h:220
RHN_OPT_ENCRYPT_KEY_JSON_T
@ RHN_OPT_ENCRYPT_KEY_JSON_T
Public key in JSON format to encrypt the token, following parameter must be a json_t * value.
Definition: rhonabwy.h:217
RHN_OPT_DECRYPT_KEY_JWKS
@ RHN_OPT_DECRYPT_KEY_JWKS
Private key set in JWKS format to decrypt the token, following parameter must be a jwks_t * value.
Definition: rhonabwy.h:221
RHN_OPT_ENCRYPT_KEY_JSON_STR
@ RHN_OPT_ENCRYPT_KEY_JSON_STR
Public key in stringified JSON format to encrypt the token, following parameter must be a const char ...
Definition: rhonabwy.h:218
RHN_OPT_DECRYPT_KEY_JSON_STR
@ RHN_OPT_DECRYPT_KEY_JSON_STR
Private key in stringified JSON format to decrypt the token, following parameter must be a const char...
Definition: rhonabwy.h:224
RHN_OPT_ENCRYPT_KEY_GNUTLS
@ RHN_OPT_ENCRYPT_KEY_GNUTLS
Public key in GnuTLS format to encrypt the token, following parameter must be a gnutls_pubkey_t value...
Definition: rhonabwy.h:216
RHN_OPT_ENCRYPT_KEY_PEM_DER
@ RHN_OPT_ENCRYPT_KEY_PEM_DER
Public key in PEM or DER format to encrypt the token, following parameter must be R_FORMAT_PEM or R_F...
Definition: rhonabwy.h:219
RHN_OPT_AAD
@ RHN_OPT_AAD
Additional Authenticated Data (AAD) for data encryption, following parameters must be const unsigned ...
Definition: rhonabwy.h:201
RHN_OPT_CIPHER_KEY
@ RHN_OPT_CIPHER_KEY
Cipher key to encrypt data, following parameters must be const unsigned char * value,...
Definition: rhonabwy.h:199
RHN_OPT_IV
@ RHN_OPT_IV
Initial Value (IV) for data encryption, following parameters must be const unsigned char * value,...
Definition: rhonabwy.h:200
RHN_OPT_DECRYPT_KEY_JSON_T
@ RHN_OPT_DECRYPT_KEY_JSON_T
Private key in JSON format to decrypt the token, following parameter must be a json_t * value.
Definition: rhonabwy.h:223
RHN_OPT_DECRYPT_KEY_PEM_DER
@ RHN_OPT_DECRYPT_KEY_PEM_DER
Private key in PEM or DER format to decrypt the token, following parameter must be R_FORMAT_PEM or R_...
Definition: rhonabwy.h:225
RHN_OPT_ENC_ALG
@ RHN_OPT_ENC_ALG
Key management algorithm, following parameter must be a jwa_alg value.
Definition: rhonabwy.h:196
RHN_OPT_DECRYPT_KEY_GNUTLS
@ RHN_OPT_DECRYPT_KEY_GNUTLS
Private key in GnuTLS format to decrypt the token, following parameter must be a gnutls_privkey_t val...
Definition: rhonabwy.h:222
RHN_OPT_ENC
@ RHN_OPT_ENC
Encryption algorithm, following parameter must be a jwa_enc value.
Definition: rhonabwy.h:197
RHN_OPT_ENCRYPT_KEY_JWKS
@ RHN_OPT_ENCRYPT_KEY_JWKS
Public key set in JWKS format to encrypt the token, following parameter must be a jwks_t * value.
Definition: rhonabwy.h:215
RHN_OPT_ENCRYPT_KEY_JWK
@ RHN_OPT_ENCRYPT_KEY_JWK
Public key in JWK format to encrypt the token, following parameter must be a jwk_t * value.
Definition: rhonabwy.h:214

Example of usage for `r_jwe_set_properties`:

jwe_t * jwe;
const unsigned char payload[] = {4, 8, 15, 16, 23, 42};
jwk_t * jwk; // Set a public RSA key in this value
r_jwe_set_properties(jwe, RHN_OPT_HEADER_INT_VALUE, "int", 42,
RHN_OPT_HEADER_STR_VALUE, "str", "a value",
RHN_OPT_HEADER_JSON_T_VALUE, "json", json_true(),
RHN_OPT_PAYLOAD, payload, sizeof(payload),
RHN_OPT_ENC_ALG, R_JWA_ALG_RSA_OAEP_256,
RHN_OPT_ENC, R_JWA_ENC_A128GCM,
RHN_OPT_ENCRYPT_KEY_JWK, jwk,
RHN_OPT_NONE); // Test if return value is RHN_OK
char * token = r_jwe_serialize(jwe, NULL, 0);
}
r_jwe_serialize
char * r_jwe_serialize(jwe_t *jwe, jwk_t *jwk_pubkey, int x5u_flags)
Definition: jwe.c:4095
R_JWA_ENC_A128GCM
@ R_JWA_ENC_A128GCM
Definition: rhonabwy.h:174
R_JWA_ALG_RSA_OAEP_256
@ R_JWA_ALG_RSA_OAEP_256
Definition: rhonabwy.h:135

## JWE example

In this example, the payload used is the following message:

The true sign of intelligence is not knowledge but imagination.

The RSA private key associated to this token is:

{
"kty":"RSA",
"n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e":"AQAB",
"d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q",
"p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs","q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk",
"dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0","dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk",
"qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU",
"kid":"2011-04-29"
}

The encryption algorithm used is `A128CBC-HS256` and the cryptographic algorithm to encrypt the key is `RSA1_5`

Finally, the complete representation of the JWE is:

eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.0ouvmluqT8kvBCgjMw8mhBFFEI5Rua58WnnATU21RqEQ2f9M6FqGEkgYpJ81ePtTkOyW1l8V-4nxIDxy-xeTHd0v5bDEbxhWKRdOmUHACC018Gt1ZB9EHHJt7k4UYj3up2xVa8qykKbZ3WGF0Gffi6ctfLCfRCWNnXMbAylV02mf4Tfhpad_WC4EeZENNryilXbAKD_9NNje-CoXD0IQK4-z2fkzfyUislwzK7dyz--uNNAC3N6XO3Blr_z61wXWGEHBa62fyHCsQqagAzN_MqTZv6cxOpRpeWM4_SwjjvcyC77rRyVpN0lC9ukyX_pNrGLXW8zH4mH78OcKPoDLPw.o5e-xb5ZzvZA2JYD2qgFbA.YNTPRS7Hv0fqE7ReEUAS_KNM31wMPPldhBGmYuQTzUWVcX8pGqooTbwaV4o_7BBiF4apD_VCGWwQ-fDD0eDofg.uyAjCu7WSo8BeBDFmYfkLA

## Serialize a JWE using Rhonabwy

The JWE above can be created with the following sample code:

#include <rhonabwy.h>
jwe_t * jwe = NULL;
jwk_t * jwk_key_rsa = NULL;
char * token = NULL;
const unsigned char payload[] = "The true sign of intelligence is not knowledge but imagination.";
const char jwk_pubkey_rsa_str[] = "{\"kty\":\"RSA\",\"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRX"\
"jBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6"\
"qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\""\
",\"e\":\"AQAB\",\"alg\":\"RS256\",\"kid\":\"2011-04-29\"}",
if (r_jwk_init(&jwk_key_rsa) == RHN_OK &&
r_jwe_init(&jwe) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key_rsa, jwk_pubkey_rsa_str) == RHN_OK &&
r_jwe_set_alg(jwe, R_JWA_ALG_RSA1_5) == RHN_OK &&
r_jwe_set_enc(jwe, R_JWA_ENC_A128CBC) == RHN_OK &&
r_jwe_set_payload(jwe, payload, sizeof(payload)) == RHN_OK) {
token = r_jwe_serialize(jwe, jwk_key_rsa, 0); // token will store the encrypted token
}
r_free(token);
r_jwe_free(jwe);
r_jwk_free(jwk_key_rsa);
r_jwe_set_payload
int r_jwe_set_payload(jwe_t *jwe, const unsigned char *payload, size_t payload_len)
Definition: jwe.c:2596
r_jwe_set_enc
int r_jwe_set_enc(jwe_t *jwe, jwa_enc enc)
Definition: jwe.c:2862
r_jwe_set_alg
int r_jwe_set_alg(jwe_t *jwe, jwa_alg alg)
Definition: jwe.c:2843
R_JWA_ENC_A128CBC
@ R_JWA_ENC_A128CBC
Definition: rhonabwy.h:171
R_JWA_ALG_RSA1_5
@ R_JWA_ALG_RSA1_5
Definition: rhonabwy.h:133

### Compressed payload

The header value `"zip":"DEF"` is used to specify if the JWE payload is compressed using ZIP/Deflate algorithm. Rhonabwy will automatically compress or decompress the decrypted payload during encryption or decryption process.

## Parse and decrypt a JWE using Rhonabwy

The JWE above can be parsed and verified using the following sample code:

#include <rhonabwy.h>
jwe_t * jwe = NULL;
jwk_t * jwk_key_rsa = NULL;
const char jwk_pirvkey_rsa_str[] = "{\"kty\":\"RSA\",\"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKR"\
"XjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHz"\
"u6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKg"\
"w\",\"e\":\"AQAB\",\"d\":\"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2v"\
"v7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk"\
"5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoA"\
"C8Q\",\"p\":\"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7"\
"XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs\",\"q\":\"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3v"\
"obLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelx"\
"k\",\"dp\":\"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA7"\
"7Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0\",\"dq\":\"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA"\
"6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cg"\
"k\",\"qi\":\"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_m"\
"HZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU\",\"alg\":\"RS256\",\"kid\":\"2011-04-29\"}",
token[] = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.0ouvmluqT8kvBCgjMw8mhBFFEI5Rua58WnnATU21RqEQ2f9M6FqGEkgYpJ81ePtTkOyW1l8V-4nxIDxy-xeTHd0v5bDEbxhWKRdOmUHACC018Gt1ZB9EHHJt7k4UYj3up2xVa8qykKbZ3WGF0Gffi6ctfLCfRCWNnXMbAylV02mf4Tfhpad_WC4EeZENNryilXbAKD_9NNje-CoXD0IQK4-z2fkzfyUislwzK7dyz--uNNAC3N6XO3Blr_z61wXWGEHBa62fyHCsQqagAzN_MqTZv6cxOpRpeWM4_SwjjvcyC77rRyVpN0lC9ukyX_pNrGLXW8zH4mH78OcKPoDLPw.o5e-xb5ZzvZA2JYD2qgFbA.YNTPRS7Hv0fqE7ReEUAS_KNM31wMPPldhBGmYuQTzUWVcX8pGqooTbwaV4o_7BBiF4apD_VCGWwQ-fDD0eDofg.uyAjCu7WSo8BeBDFmYfkLA";
const char * payload = NULL;
size_t payload_len = 0;
if (r_jwk_init(&jwk_key_rsa) == RHN_OK &&
r_jwe_init(&jwe) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key_rsa, jwk_pirvkey_rsa_str) == RHN_OK &&
r_jwe_parse(jwe, token, 0) == RHN_OK &&
r_jwe_decrypt(jwe, jwk_key_rsa, 0) == RHN_OK &&
(payload = r_jwe_get_payload(jwe, &payload_len)) != NULL && payload_len > 0) {
// payload and payload_len will contain the payload data
}
r_jwe_free(jwe);
r_jwk_free(jwk_key_rsa);
r_jwe_get_payload
const unsigned char * r_jwe_get_payload(jwe_t *jwe, size_t *payload_len)
Definition: jwe.c:2621
r_jwe_parse
int r_jwe_parse(jwe_t *jwe, const char *jwe_str, int x5u_flags)
Definition: jwe.c:3590
r_jwe_decrypt
int r_jwe_decrypt(jwe_t *jwe, jwk_t *jwk_privkey, int x5u_flags)
Definition: jwe.c:3985

## ECDH-ES implementation

The ECDH-ES algorithm requires an ECC or ECDH public key for the encryption. The RFC specifies `"A new ephemeral public key value MUST be generated for each key agreement operation.", so an ephemeral key is genererated on each encryption.

You can specify the ephemeral key to use though, by setting an encryption key to the JWE before generating the token. The responsibilty not to reuse the same ephemeral key is yours then.

Example with a specified ephemeral key:

const unsigned char payload[] = "The true sign of intelligence is not knowledge but imagination...";
// This is the ephemeral key
const char eph[] = " {\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0\","
"\"y\":\"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps\",\"d\":\"0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo\"}",
bob[] = "{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ\","
"\"y\":\"e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck\"}"; // This is the public key
jwk_t * jwk_eph = NULL, * jwk_bob = NULL;
jwe_t * jwe = NULL;
char * token;
jwk_eph = r_jwk_quick_import(R_IMPORT_JSON_STR, eph);
jwk_bob = r_jwk_quick_import(R_IMPORT_JSON_STR, bob);
r_jwe_init(&jwe);
r_jwe_set_payload(jwe, payload, sizeof(payload));
r_jwe_add_keys(jwe, jwk_eph, jwk_bob); // Add both public and ephemeral keys here
r_jwe_set_alg(jwe, R_JWA_ALG_ECDH_ES_A128KW);
r_jwe_set_enc(jwe, R_JWA_ENC_A128GCM);
r_jwe_set_header_str_value(jwe, "apu", "QWxpY2U");
r_jwe_set_header_str_value(jwe, "apv", "Qm9i");
token = r_jwe_serialize(jwe, NULL, 0); // token will contain the compact representation of the serialized token, e.g. eyJhcHUiOiJRV3hwWTJVIiwiYXB2IjoiUW0[...]
r_free(token);
r_jwk_free(jwk_eph);
r_jwk_free(jwk_bob);
r_jwe_free(jwe);
r_jwe_add_keys
int r_jwe_add_keys(jwe_t *jwe, jwk_t *jwk_privkey, jwk_t *jwk_pubkey)
Definition: jwe.c:2979
r_jwe_set_header_str_value
int r_jwe_set_header_str_value(jwe_t *jwe, const char *key, const char *str_value)
Definition: jwe.c:2885
R_IMPORT_JSON_STR
@ R_IMPORT_JSON_STR
Import from a stringified JSON, following parameter must be a const char * value.
Definition: rhonabwy.h:230
R_JWA_ALG_ECDH_ES_A128KW
@ R_JWA_ALG_ECDH_ES_A128KW
Definition: rhonabwy.h:141

# Tokens in JSON format

Rhonabwy supports serializing and parsing tokens in JSON format, see JWE JSON Serialization and JWS JSON Serialization.

## JWS JSON serialization and parsing

To serialize a JWS in JSON format, you must use the functions `r_jws_serialize_json_t` or `r_jws_serialize_json_str`, the parameter `mode` must have the value `R_JSON_MODE_GENERAL` to serialize in general format (allows multiple signatures), or `R_JSON_MODE_FLATTENED` to serialize in flattened format.

To parse a JWS in JSON format, you can either use `r_jws_parse_json_str`, `r_jws_parsen_json_str` or `r_jws_parse_json_t` when you know the token is in JSON format, or you can use `r_jws_parse` or `r_jws_parsen`.

If the token is in general JSON format and has multiple signatures, the function `r_jws_verify_signature` will return `RHN_OK` if one of the signatures is verified by the public key specified or one of the public keys added to its public JWKS.

## JWE JSON serialization and parsing

To serialize a JWE in JSON format, you must use the functions `r_jwe_serialize_json_t` or `r_jwe_serialize_json_str`, the parameter `mode` must have the value `R_JSON_MODE_GENERAL` to serialize in general format (allows multiple key encryption), or `R_JSON_MODE_FLATTENED` to serialize in flattened format.

To parse a JWE in JSON format, you can either use `r_jwe_parse_json_str`, `r_jwe_parsen_json_str` or `r_jwe_parse_json_t` when you know the token is in JSON format, or you can use `r_jwe_parse` or `r_jwe_parsen`.

If the token is in general JSON format and has multiple key encryption, the function `r_jwe_decrypt` will decrypt the payload and return `RHN_OK` if one of the recipients content is correctly decrypted using a specified private key or one of the private key added to its private JWKS.

## Quick parsing

The quick parsing functions can be used to parse a JWE in one line:

jwe_t * r_jwe_quick_parse(const char * jwe_str, uint32_t parse_flags, int x5u_flags);
jwe_t * r_jwe_quick_parsen(const char * jwe_str, size_t jwe_str_len, uint32_t parse_flags, int x5u_flags);
r_jwe_quick_parse
jwe_t * r_jwe_quick_parse(const char *jwe_str, uint32_t parse_flags, int x5u_flags)
Definition: jwe.c:3964
r_jwe_quick_parsen
jwe_t * r_jwe_quick_parsen(const char *jwe_str, size_t jwe_str_len, uint32_t parse_flags, int x5u_flags)
Definition: jwe.c:3968

# JWT

Finally, a JWT (JSON Web Token) is a JSON content signed and/or encrypted and serialized in a compact format that can be easily transferred in HTTP requests. Technically, a JWT is a JWS or a JWE which payload is a stringified JSON and has the property `"type":"JWT"` in the header.

A JWT can be nested, which means signed and encrypted, in which case the payload is signed as a JWS first, then the serialized signed token is used as the payload in a JWE, or the opposite.

## Set values

To set the values of the JWT (header, keys, payload, etc.), you can use the dedicated functions (see the documentation), or use the function `r_jwt_set_properties` to set multiple properties at once. The option list MUST end with the option `RHN_OPT_NONE`.

int r_jwt_set_properties(jwt_t * jwt, ...);
r_jwt_set_properties
int r_jwt_set_properties(jwt_t *jwt,...)
Definition: jwt.c:2081

The available `rhn_opt` and their following values for a `jwt_t` are:

RHN_OPT_HEADER_INT_VALUE, const char *, int
RHN_OPT_HEADER_RHN_INT_VALUE, const char *, rhn_int_t
RHN_OPT_HEADER_STR_VALUE, const char * const char *
RHN_OPT_HEADER_JSON_T_VALUE, const char *, json_t *
RHN_OPT_HEADER_FULL_JSON_T, json_t *
RHN_OPT_HEADER_FULL_JSON_STR, const char *
RHN_OPT_CLAIM_INT_VALUE, const char *, int
RHN_OPT_CLAIM_RHN_INT_VALUE, const char *, rhn_int_t
RHN_OPT_CLAIM_STR_VALUE, const char * const char *
RHN_OPT_CLAIM_JSON_T_VALUE, const char *, json_t *
RHN_OPT_CLAIM_FULL_JSON_T, json_t *
RHN_OPT_CLAIM_FULL_JSON_STR, const char *
RHN_OPT_SIG_ALG, jwa_alg
RHN_OPT_ENC_ALG, jwa_alg
RHN_OPT_ENC, jwa_enc
RHN_OPT_CIPHER_KEY, const unsigned char *, size_t
RHN_OPT_IV, const unsigned char *, size_t
RHN_OPT_SIGN_KEY_JWK, jwk_t *
RHN_OPT_SIGN_KEY_JWKS, jwks_t *
RHN_OPT_SIGN_KEY_GNUTLS, gnutls_privkey_t
RHN_OPT_SIGN_KEY_JSON_T, json_t *
RHN_OPT_SIGN_KEY_JSON_STR, const char *
RHN_OPT_SIGN_KEY_PEM_DER, uint, const unsigned char *, size_t
RHN_OPT_VERIFY_KEY_JWK, jwk_t *
RHN_OPT_VERIFY_KEY_JWKS, jwks_t *
RHN_OPT_VERIFY_KEY_GNUTLS, gnutls_pubkey_t
RHN_OPT_VERIFY_KEY_JSON_T, json_t *
RHN_OPT_VERIFY_KEY_JSON_STR, const char *
RHN_OPT_VERIFY_KEY_PEM_DER, uint, const unsigned char *, size_t
RHN_OPT_ENCRYPT_KEY_JWK, jwk_t *
RHN_OPT_ENCRYPT_KEY_JWKS, jwks_t *
RHN_OPT_ENCRYPT_KEY_GNUTLS, gnutls_pubkey_t
RHN_OPT_ENCRYPT_KEY_JSON_T, json_t *
RHN_OPT_ENCRYPT_KEY_JSON_STR, const char *
RHN_OPT_ENCRYPT_KEY_PEM_DER, uint, const unsigned char *, size_t
RHN_OPT_DECRYPT_KEY_JWK, jwk_t *
RHN_OPT_DECRYPT_KEY_JWKS, jwks_t *
RHN_OPT_DECRYPT_KEY_GNUTLS, gnutls_privkey_t
RHN_OPT_DECRYPT_KEY_JSON_T, json_t *
RHN_OPT_DECRYPT_KEY_JSON_STR, const char *
RHN_OPT_DECRYPT_KEY_PEM_DER, uint, const unsigned char *, size_t
RHN_OPT_CLAIM_INT_VALUE
@ RHN_OPT_CLAIM_INT_VALUE
Claims Integer value, following parameters must be const char * name, int i_value.
Definition: rhonabwy.h:190
RHN_OPT_CLAIM_FULL_JSON_STR
@ RHN_OPT_CLAIM_FULL_JSON_STR
Stringified JSON value to set the entire claims, following parameter must be const char * str_value.
Definition: rhonabwy.h:195
RHN_OPT_CLAIM_STR_VALUE
@ RHN_OPT_CLAIM_STR_VALUE
Claims String value, following parameters must be const char * name, const char * str_value.
Definition: rhonabwy.h:192
RHN_OPT_CLAIM_JSON_T_VALUE
@ RHN_OPT_CLAIM_JSON_T_VALUE
Claims JSON value, following parameters must be const char * name, json_t * j_value.
Definition: rhonabwy.h:193
RHN_OPT_CLAIM_FULL_JSON_T
@ RHN_OPT_CLAIM_FULL_JSON_T
JSON value to set the entire claims, following parameter must be json_t * j_value.
Definition: rhonabwy.h:194
RHN_OPT_CLAIM_RHN_INT_VALUE
@ RHN_OPT_CLAIM_RHN_INT_VALUE
Claims Integer value, following parameters must be const char * name, int i_value.
Definition: rhonabwy.h:191

Example of usage for `r_jwt_set_properties`:

jwt_t * jwt;
const unsigned char payload[] = {4, 8, 15, 16, 23, 42};
jwk_t * jwk; // Set a private RSA key in this value
r_jwt_set_properties(jwt, RHN_OPT_HEADER_INT_VALUE, "int", 42,
RHN_OPT_HEADER_STR_VALUE, "str", "a value",
RHN_OPT_HEADER_JSON_T_VALUE, "json", json_true(),
RHN_OPT_CLAIM_FULL_JSON_STR, "{\"str\":\"grut\",\"int\":42,\"obj\":true}",
RHN_OPT_SIG_ALG, R_JWA_ALG_RS256,
RHN_OPT_SIGN_KEY_JWK, jwk,
RHN_OPT_NONE); // Test if return value is RHN_OK
char * token = r_jwt_serialize_signed(jwt, NULL, 0);
}
r_jwt_serialize_signed
char * r_jwt_serialize_signed(jwt_t *jwt, jwk_t *privkey, int x5u_flags)
Definition: jwt.c:1006

## Verify a list of claims in the JWT

The function int `int r_jwt_validate_claims(jwt_t * jwt, ...)` will help you verify the validity of some claims in the JWT.

Claim types available

- `R_JWT_CLAIM_ISS`: claim `"iss"`, values expected a string or `NULL` to validate the presence of the claim
- `R_JWT_CLAIM_SUB`: claim `"sub"`, values expected a string or `NULL` to validate the presence of the claim
- `R_JWT_CLAIM_AUD`: claim `"aud"`, values expected a string or `NULL` to validate the presence of the claim
- `R_JWT_CLAIM_EXP`: claim `"exp"`, value expected `R_JWT_CLAIM_NOW` or an positive integer value or `R_JWT_CLAIM_PRESENT` to validate the presence of the claim
- `R_JWT_CLAIM_NBF`: claim `"nbf"`, value expected `R_JWT_CLAIM_NOW` or an positive integer value or `R_JWT_CLAIM_PRESENT` to validate the presence of the claim
- `R_JWT_CLAIM_IAT`: claim `"iat"`, value expected `R_JWT_CLAIM_NOW` or an positive integer value or `R_JWT_CLAIM_PRESENT` to validate the presence of the claim
- `R_JWT_CLAIM_JTI`: claim `"jti"`, values expected a string or `NULL` to validate the presence of the claim
- `R_JWT_CLAIM_STR`: the claim name specified must have the string value expected or `NULL` to validate the presence of the claim
- `R_JWT_CLAIM_INT`: the claim name specified must have the integer value expected
- `R_JWT_CLAIM_JSN`: the claim name specified must have the json_t * value expected or `NULL` to validate the presence of the claim
- `R_JWT_CLAIM_TYP`: header parameter `"typ"` (type), values expected a string or `NULL` to validate the presence of the header parameter
- `R_JWT_CLAIM_CTY`: header parameter `"cty"` (Content Type), values expected a string or `NULL` to validate the presence of the header parameter

For example, the following code will check the jwt against the claim `iss` has the value `"https://example.com"`, the claim `sub` has the value `"client_1"`, the presence of the claim `aud`, the claim `exp` is after now, the claim `nbf` is before now, the claim `scope` has the value `"scope1"`, the claim `age` has the value `42` and the claim `verified` has the JSON value `true`:

if (r_jwt_validate_claims(jwt, R_JWT_CLAIM_ISS, "https://example.com",
R_JWT_CLAIM_SUB, "client_1",
R_JWT_CLAIM_AUD, NULL,
R_JWT_CLAIM_EXP, R_JWT_CLAIM_NOW,
R_JWT_CLAIM_NBF, R_JWT_CLAIM_NOW,
R_JWT_CLAIM_STR, "scope", "scope1",
R_JWT_CLAIM_INT, "age", 42,
R_JWT_CLAIM_JSN, "verified", json_true(),
R_JWT_CLAIM_NOP) == RHN_OK)
R_JWT_CLAIM_NOW
#define R_JWT_CLAIM_NOW
Definition: rhonabwy.h:81
r_jwt_validate_claims
int r_jwt_validate_claims(jwt_t *jwt,...)
Definition: jwt.c:1719
R_JWT_CLAIM_ISS
@ R_JWT_CLAIM_ISS
Definition: rhonabwy.h:155
R_JWT_CLAIM_SUB
@ R_JWT_CLAIM_SUB
Definition: rhonabwy.h:156
R_JWT_CLAIM_NBF
@ R_JWT_CLAIM_NBF
Definition: rhonabwy.h:159
R_JWT_CLAIM_JSN
@ R_JWT_CLAIM_JSN
Definition: rhonabwy.h:164
R_JWT_CLAIM_STR
@ R_JWT_CLAIM_STR
Definition: rhonabwy.h:162
R_JWT_CLAIM_INT
@ R_JWT_CLAIM_INT
Definition: rhonabwy.h:163
R_JWT_CLAIM_EXP
@ R_JWT_CLAIM_EXP
Definition: rhonabwy.h:158
R_JWT_CLAIM_NOP
@ R_JWT_CLAIM_NOP
Definition: rhonabwy.h:154
R_JWT_CLAIM_AUD
@ R_JWT_CLAIM_AUD
Definition: rhonabwy.h:157

## Serialize a JWT using Rhonabwy

Let's use the following JSON object in a JWT:

{
"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true
}

The JWT can be signed using the algorithm `HS256` and the following key:

{
"kty":"oct",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
}

The signed JWT serialized will be:

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

### Signed JWT

The signed JWT above can be created with the following sample code:

#include <rhonabwy.h>
jwt_t * jwt = NULL;
jwk_t * jwk_key = NULL;
const char payload[] = "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}",
jwk_key_str[] = "{\"kty\":\"oct\",\"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\"}";
char * token = NULL;
if (r_jwk_init(&jwk_key) == RHN_OK &&
r_jwt_init(&jwt) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key, jwk_key_str) == RHN_OK &&
r_jwt_set_sign_alg(jwt, R_JWA_ALG_HS256) == RHN_OK &&
r_jwt_set_full_claims_json_str(jwt, payload) == RHN_OK) {
token = r_jwt_serialize_signed(jwt, jwk_key, 0); // token will store the signed token
}
r_free(token);
r_jwt_free(jwt);
r_jwk_free(jwk_key);
r_jwt_set_sign_alg
int r_jwt_set_sign_alg(jwt_t *jwt, jwa_alg alg)
Definition: jwt.c:814
r_jwt_set_full_claims_json_str
int r_jwt_set_full_claims_json_str(jwt_t *jwt, const char *str_claims)
Definition: jwt.c:267

The same payload can be encrypted and serialized in an encrypted JWT using `RSA1_5` as key encryption algorithm and `A128CBC-HS256` as content encryption algorithm.

The encrypted JWT of the payload above can be the following:

eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.QR1Owv2ug2WyPBnbQrRARTeEk9kDO2w8qDcjiHnSJflSdv1iNqhWXaKH4MqAkQtMoNfABIPJaZm0HaA415sv3aeuBWnD8J-Ui7Ah6cWafs3ZwwFKDFUUsWHSK-IPKxLGTkND09XyjORj_CHAgOPJ-Sd8ONQRnJvWn_hXV1BNMHzUjPyYwEsRhDhzjAD26imasOTsgruobpYGoQcXUwFDn7moXPRfDE8-NoQX7N7ZYMmpUDkR-Cx9obNGwJQ3nM52YCitxoQVPzjbl7WBuB7AohdBoZOdZ24WlN1lVIeh8v1K4krB8xgKvRU8kgFrEn_a1rZgN5TiysnmzTROF869lQ.AxY8DCtDaGlsbGljb3RoZQ.MKOle7UQrG6nSxTLX6Mqwt0orbHvAKeWnDYvpIAeZ72deHxz3roJDXQyhxx0wKaMHDjUEOKIwrtkHthpqEanSBNYHZgmNOV7sln1Eu9g3J8.fiK51VwhsxJ-siBMR-YFiA

### Encrypted JWT

An encrypted JWT can be created with Rhonabwy using the following sample code:

#include <rhonabwy.h>
jwt_t * jwt = NULL;
jwk_t * jwk_key = NULL;
const char payload[] = "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}",
jwk_pubkey_rsa_str[] = "{\"kty\":\"RSA\",\"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRX"\
"jBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6"\
"qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\""\
",\"e\":\"AQAB\",\"alg\":\"RS256\",\"kid\":\"2011-04-29\"}";
char * token = NULL;
if (r_jwk_init(&jwk_key) == RHN_OK &&
r_jwt_init(&jwt) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key, jwk_pubkey_rsa_str) == RHN_OK &&
r_jwt_set_enc_alg(jwt, R_JWA_ALG_RSA1_5) == RHN_OK &&
r_jwt_set_enc(jwt, R_JWA_ENC_A128CBC) == RHN_OK &&
r_jwt_set_full_claims_json_str(jwt, payload) == RHN_OK) {
token = r_jwt_serialize_encrypted(jwt, jwk_key, 0); // token will store the encrypted token
}
r_free(token);
r_jwt_free(jwt);
r_jwk_free(jwk_key);
r_jwt_set_enc_alg
int r_jwt_set_enc_alg(jwt_t *jwt, jwa_alg alg)
Definition: jwt.c:834
r_jwt_set_enc
int r_jwt_set_enc(jwt_t *jwt, jwa_enc enc)
Definition: jwt.c:854
r_jwt_serialize_encrypted
char * r_jwt_serialize_encrypted(jwt_t *jwt, jwk_t *pubkey, int x5u_flags)
Definition: jwt.c:1055

### Nested JWT

A nested JWT can be created with Rhonabwy using the following sample code:

#include <rhonabwy.h>
jwt_t * jwt = NULL;
jwk_t * jwk_key = NULL, * jwk_key_sign = NULL;
const char payload[] = "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}",
jwk_pubkey_rsa_str[] = "{\"kty\":\"RSA\",\"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRX"\
"jBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6"\
"qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\""\
",\"e\":\"AQAB\",\"alg\":\"RS256\",\"kid\":\"2011-04-29\"}",
jwk_key_str[] = "{\"kty\":\"oct\",\"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\"}";
char * token = NULL;
if (r_jwk_init(&jwk_key) == RHN_OK &&
r_jwk_init(&jwk_key_sign) == RHN_OK &&
r_jwt_init(&jwt) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key, jwk_pubkey_rsa_str) == RHN_OK &&
r_jwk_import_from_json_str(jwk_key_sign, jwk_key_str) == RHN_OK &&
r_jwt_set_enc_alg(jwt, R_JWA_ALG_RSA1_5) == RHN_OK &&
r_jwt_set_enc(jwt, R_JWA_ENC_A128CBC) == RHN_OK &&
r_jwt_set_sign_alg(jwt, R_JWA_ALG_HS256) == RHN_OK &&
r_jwt_set_sign_alg(jwt, R_JWA_ALG_HS256) == RHN_OK &&
r_jwt_set_full_claims_json_str(jwt, payload) == RHN_OK) {
token = r_jwt_serialize_nested(jwt, R_JWT_TYPE_NESTED_SIGN_THEN_ENCRYPT, jwk_key_sign, 0, jwk_key, 0); // token will store the nested token
}
r_free(token);
r_jwt_free(jwt);
r_jwk_free(jwk_key);
R_JWT_TYPE_NESTED_SIGN_THEN_ENCRYPT
#define R_JWT_TYPE_NESTED_SIGN_THEN_ENCRYPT
Definition: rhonabwy.h:78
r_jwt_serialize_nested
char * r_jwt_serialize_nested(jwt_t *jwt, unsigned int type, jwk_t *sign_key, int sign_key_x5u_flags, jwk_t *encrypt_key, int encrypt_key_x5u_flags)
Definition: jwt.c:1105

## Parse a JWT

The functions `r_jwt_parse` and `r_jwt_parsen` will parse a serialized JWT. If public keys are present in the header, they will be added to the public keys list and can be used to verify the token signature.

int r_jwt_parse(jwt_t * jwt, const char * jwt_str, int x5u_flags);
int r_jwt_parsen(jwt_t * jwt, const char * jwt_str, size_t jwt_str_len, int x5u_flags);
r_jwt_parsen
int r_jwt_parsen(jwt_t *jwt, const char *token, size_t token_len, int x5u_flags)
Definition: jwt.c:1190
r_jwt_parse
int r_jwt_parse(jwt_t *jwt, const char *token, int x5u_flags)
Definition: jwt.c:1186

## Advanced parsing

JWT standard allows to add in the JWT header a public key in several forms:

- `jwk`: a public key in JWK format
- `jku`: an url to a JWK Set
- `x5c`: an array of X509 certificates
- `x5u`: an url to a X509 certificate

When using the functions `r_jwt_parse`, `r_jwt_parsen`, `r_jwt_compact_parse`, `r_jwt_compact_parsen`, `r_jwt_parse_unsecure`, `r_jwt_parsen_unsecure`, `r_jwt_compact_parsen_unsecure` and `r_jwt_compact_parse_unsecure`, by default, if a public key is mentionned in the header, it will be added to the `jwt->jwks_pubkey`, so the signature verification will not need to specify a key. This can be dangerous if the token comes from a untrustworthy source and if the token isn't checked properly.

To simplify secure token parsing, you should use the functions `r_jwt_advanced_parse[n]`:

int r_jwt_advanced_parse(jwt_t * jwt, const char * token, uint32_t parse_flags, int x5u_flags);
int r_jwt_advanced_parsen(jwt_t * jwt, const char * token, size_t token_len, uint32_t parse_flags, int x5u_flags);
r_jwt_advanced_parse
int r_jwt_advanced_parse(jwt_t *jwt, const char *token, uint32_t parse_flags, int x5u_flags)
Definition: jwt.c:1202
r_jwt_advanced_parsen
int r_jwt_advanced_parsen(jwt_t *jwt, const char *token, size_t token_len, uint32_t parse_flags, int x5u_flags)
Definition: jwt.c:1206

## Quick parsing

The quick parsing functions can be used to parse a JWT in one line:

jwt_t * r_jwt_quick_parse(const char * token, uint32_t parse_flags, int x5u_flags);
jwt_t * r_jwt_quick_parsen(const char * token, size_t token_len, uint32_t parse_flags, int x5u_flags);
r_jwt_quick_parse
jwt_t * r_jwt_quick_parse(const char *token, uint32_t parse_flags, int x5u_flags)
Definition: jwt.c:1338
r_jwt_quick_parsen
jwt_t * r_jwt_quick_parsen(const char *token, size_t token_len, uint32_t parse_flags, int x5u_flags)
Definition: jwt.c:1342

## Unsecured JWT

It's possible to use Rhonabwy for unsecured JWT, with the header `alg:"none"` and an empty signature, using a dedicated set of functions: `r_jwt_parse_unsecure`, `r_jwt_parsen_unsecure` and `r_jwt_serialize_signed_unsecure`, or using `r_jwt_advanced_parse` with the `parse_flags` value `R_PARSE_UNSIGNED` set.

### Parse a unsecured JWT

By default, the functions `r_jwt_parse` and `r_jwt_parsen` will return `RHN_ERROR_INVALID` if the parsed JWT is unsigned. To parse any JWT, signed or unsigned, you must use the functions `r_jwt_parse_unsecure` and `r_jwt_parsen_unsecure`, or using `r_jwt_advanced_parse` with the `parse_flags` value `R_PARSE_UNSIGNED` set.

### Serialize an unsecured JWT

Use the function `r_jwt_serialize_signed_unsecure` to serialize an unsecured JWT.

### Signature verification

The function `r_jwt_verify_signature` will return `RHN_ERROR_INVALID` if the JWT is unsecured.

### Nested JWT with an unsecured signature

It's not possible to serialize or parse a nested JWT with an unsecured signature.