/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
/*
* Copyright 2016 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* JSON Web Encryption (RFC 7516)
*
* A JSON Web Encryption (JWE) object contains (usually) two levels of
* encryption. First, the plaintext is encrypted with a random symmetric key.
* In José, we call this key the Content Encryption Key (CEK). Next, the CEK is
* wrapped (encrypted) with one or more keys. These keys are standard JSON Web
* Keys (JWK) and may be symmetric or asymmetric.
*
* Thus there is (usually) one CEK and one or more JWKs. However, there are
* some exceptions to this rule. Two such examples are the algorithms: "dir"
* and "ECDH-ES". In the first case, the JWK is a symmetric key and is used
* directly as the CEK. In the second case, an ECDH key exchange is performed
* and the result is used directly as the CEK. But in general, the maxim holds.
*
* This means that you can encrypt the data using one CEK and then encrypt the
* CEK to multiple recipients. With this schema, multiple recipients can each
* decrypt the data using their own key without having to send separate
* ciphertext to each recipient.
*
* For maximum flexibility, José structures its API to take advantage of this
* schema. For example, when encrypting to two recipients, the code could look
* like this (error handling omitted):
*
* json_t *enc(void *plaintext, size_t len, json_t *jwk0, json_t *jwk1) {
* json_auto_t *jwe = json_object();
* json_auto_t *cek = json_object();
*
* // Wrap to the first recipient (CEK generated implicitly)
* jose_jwe_enc_jwk(NULL, jwe, NULL, jwk0, cek);
*
* // Wrap to the second recipient
* jose_jwe_enc_jwk(NULL, jwe, NULL, jwk1, cek);
*
* // Encrypt plaintext using the generated CEK
* jose_jwe_enc_cek(NULL, jwe, cek, plaintext, len);
*
* return json_incref(jwe);
* }
*
* However, because José intends to be easy to use, we also provide shortcuts.
* For example, you could use a JWKSet which contains multiple JWKs:
*
* json_t *enc(void *plaintext, size_t len, json_t *jwkset) {
* json_auto_t *jwe = json_object();
*
* // Perform wrapping and encryption to all recipients
* jose_jwe_enc(NULL, jwe, NULL, jwkset, plaintext, len);
*
* return json_incref(jwe);
* }
*
* Here are two tips to remember. First, let José generate your CEK implicitly.
* Second, always perform wrapping before encryption. Both of these tips are
* important because some wrapping algorithms may impose constraints on the
* generation of the CEK.
*
* To decrypt a JWE, we just reverse the process. First, we use a JWK to
* unwrap the CEK. Then we use the CEK to decrypt the ciphertext. Here is how
* that might look in code (again, error handling omitted):
*
* void *dec(json_t *jwe, json_t *jwk, size_t *len) {
* json_auto_t *cek = NULL;
*
* // Unwrap the CEK using our JWK
* cek = jose_jwe_dec_jwk(NULL, jwe, NULL, jwk);
*
* // Decrypt ciphertext using the CEK
* return jose_jwe_dec_cek(NULL, jwe, cek, len);
* }
*
* Or, again, in simplified form:
*
* void *dec(json_t *jwe, json_t *jwk, size_t *len) {
* return jose_jwe_dec(NULL, jwe, NULL, jwk, len);
* }
*
* If you need to forward a JWE to a new recipient, you can do this without
* performing re-encryption. Just unwrap the CEK and then wrap the CEK again
* using a new JWK. For example:
*
* void fwd(json_t *jwe, json_t *oldjwk, json_t *newjwk) {
* json_auto_t *cek = NULL;
*
* // Unwrap the CEK using the old JWK
* cek = jose_jwe_dec_jwk(NULL, jwe, NULL, oldjwk);
*
* // Wrap the CEK to the new JWK
* jose_jwe_enc_jwk(NULL, jwe, NULL, newjwk, cek);
* }
*
* In all the above examples, parameters like which encryption algorithms to
* use were inferred from our keys. Where such an inferrence cannot be made,
* sensible and secure defaults were chosen automatically. If you would like
* more control over the process, simply set parameters in the appropriate
* objects (more on this in the function documentation). For example,
* to enable plaintext compression, you can specify the \p zip property
* in the JWE Protected Header:
*
* json_t *enc(void *plaintext, size_t len, json_t *jwkset) {
* json_auto_t *jwe = json_pack("{s:{s:s}}", "protected", "zip", "DEF");
*
* // Perform compressed wrapping and encryption to all recipients
* jose_jwe_enc(NULL, jwe, NULL, jwkset, plaintext, len);
*
* return json_incref(jwe);
* }
*
* José currently supports the "alg", "enc" and "zip" header parameters, as
* well as any algorithm-specific header parameters used by the specific
* algorithms we implement. Other header parameters may be specified, but do
* not effect the behavior of José's JWE implementation.
*
* \defgroup jose_jwe JWE
* \see https://tools.ietf.org/html/rfc7516
* @{
*/
#pragma once
#include "cfg.h"
#include "io.h"
#include <jansson.h>
#include <stdbool.h>
#include <stdint.h>
/**
* Merges the JOSE headers of a JWE object and a JWE recpient object.
*
* \param jwe A JWE object.
* \param rcp A JWE recipient object.
* \return The newly allocated JOSE header.
*/
json_t *
jose_jwe_hdr(const json_t *jwe, const json_t *rcp);
/**
* Wraps and encrypts plaintext.
*
* This function is a thin wrapper around the jose_jwe_enc_io() function
* allowing the user to specify the plaintext in a single call. The ciphertext
* output will be appended to the JWE as the "ciphertext" property.
*
* \see jose_jwe_enc_cek_io()
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param rcp The JWE recipient object(s) or NULL.
* \param jwk The JWK(s) or JWKSet used for wrapping.
* \param pt The plaintext.
* \param ptl The length of the plaintext.
* \return On success, true. Otherwise, false.
*/
bool
jose_jwe_enc(jose_cfg_t *cfg, json_t *jwe, json_t *rcp, const json_t *jwk,
const void *pt, size_t ptl);
/**
* Wraps and encrypts plaintext using streaming.
*
* This function is a thin wrapper around the jose_jwe_enc_jwk() and
* jose_jwe_enc_cek_io() functions, removing the complexity of managing the CEK.
*
* \see jose_jwe_enc_jwk()
* \see jose_jwe_enc_cek_io()
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param rcp The JWE recipient object(s) or NULL.
* \param jwk The JWK(s) or JWKSet used for wrapping.
* \param next The next IO object in the chain.
* \return The new IO object or NULL on error.
*/
jose_io_t *
jose_jwe_enc_io(jose_cfg_t *cfg, json_t *jwe, json_t *rcp, const json_t *jwk,
jose_io_t *next);
/**
* Wraps a CEK with a JWK.
*
* The purpose of this function is to wrap (encrypt) or, in some cases, produce
* the CEK (\p cek) from the provided JWK(s) (\p jwk). This function can be
* used in two modes: single-JWK and multi-JWK.
*
* In single-JWK mode, the \p jwk parameter contains a JWK object and the
* \p rcp parameter must contain either a JWE recipient object or NULL, in
* which case a default empty JWE recipient object is created internally.
*
* Multi-JWK mode works exactly the same as single-JWK mode except that it
* performs multiple wrappings in a single call. This mode is enabled by
* passing either an array of JWK objects or a JWKSet as the \p jwk parameter.
* In this mode, the \p rcp parameter contains one of the following values:
*
* 1. A JWE recipient object that will be used for all wrappings. In this case,
* a copy will be made for each wrapping and \p rcp will not be modified in
* any way.
*
* 2. An array of JWE recipient objects. Each object will be used with its
* corresponding JWK from \p jwk. If the arrays in \p sig and \p jwk are a
* different size, an error will occur.
*
* 3. NULL. This has the same effect as passing NULL for each separate JWK.
*
* In either mode, if the resulting JWE (\p jwe) would contain only a single
* recipient, the JWE will be represented in Flattened JWE JSON Serialization
* Syntax. Otherwise, it will be represented in General JWE JSON Serialization
* Syntax.
*
* If the "alg" parameter is not specified in the JOSE Header, it will be
* inferred from the JWK and the chosen algorithm will be added to the JWE
* Per-Recipient Unprotected Header. Likewise, any missing, required,
* algorithm-specific parameters will be either inferred or sensible, secure
* defaults will be chosen and the results will be added to the JWE
* Per-Recipient Unprotected Header.
*
* If the provided CEK (\p cek) does not contain key material, it will be
* implicitly generated during the first call to jose_jwe_enc_jwk(). This
* important feature enables the use of the "dir" and "ECDH-ES" algorithms.
* In the case of the "dir" algorithm, the JWK is the CEK and thus the key
* material is copied from \p jwk to \p cek. A similar situation arises with
* the algorithm "ECDH-ES" where the result of a key exchange is used as the
* CEK; thus, the CEK is produced during the wrapping process. This feature
* implies that if multiple wrappings are created, only one of them may have
* the algorithm "ECDH-ES" and it must be the first wrapping. Attempting to
* use "ECDH-ES" with an existing CEK will result in an error.
*
* It is additionally possible to pass a password JSON string as key input
* to the PBES2 family of algorithms anywhere a JWK can be used. Likewise, if
* the "alg" JOSE Header parameter is not specified and a JSON string is used
* in place of a JWK, the PBES2 family of algorithms will be inferred.
*
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param rcp The JWE recipient object(s) or NULL.
* \param jwk The JWK(s) or JWKSet used for wrapping.
* \param cek The CEK to wrap (if empty, generated).
* \return On success, true. Otherwise, false.
*/
bool
jose_jwe_enc_jwk(jose_cfg_t *cfg, json_t *jwe, json_t *rcp, const json_t *jwk,
json_t *cek);
/**
* Encrypts plaintext with the CEK.
*
* This function is a thin wrapper around the jose_jwe_enc_cek_io() function
* allowing the user to specify the plaintext in a single call. The ciphertext
* output will be appended to the JWE as the "ciphertext" property.
*
* \see jose_jwe_enc_cek_io()
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param cek The CEK object.
* \param pt The plaintext.
* \param ptl The length of the plaintext.
* \return On success, true. Otherwise, false.
*/
bool
jose_jwe_enc_cek(jose_cfg_t *cfg, json_t *jwe, const json_t *cek,
const void *pt, size_t ptl);
/**
* Encrypts plaintext with the CEK using streaming.
*
* The plaintext is provided through the returned IO object. The plaintext
* will be encrypted and written to the \p next IO object. This IO object
* works on binary data, so you may need to use a URL-safe Base64 decoder on
* input and a URL-safe Base64 encoder on output, depending on your situation.
*
* Compressed plaintext can be implicitly enabled by specifying the "zip"
* parameter the JWE Protected Header.
*
* If the JWE Protected Header is a JSON object rather than an encoded string,
* this function will encode the JWE Protected Header to its URL-safe Base64
* encoding as defined in RFC 7516. However, this function will never modify
* a JWE Protected Header that is already encoded.
*
* If the "enc" parameter is not specified in the JWE Protected Header or the
* JWE Shared Unprotected Header, it will be inferred from the CEK and stored
* in either the JWE Protected Header or the JWE Shared Unprotected Header
* (preferring the JWE Protected header if it can be modified).
*
* Please note that the "tag" property will only be added to the JWE when
* \ref jose_io_t.done() returns.
*
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param cek The CEK object.
* \param next The next IO object in the chain.
* \return The new IO object or NULL on error.
*/
jose_io_t *
jose_jwe_enc_cek_io(jose_cfg_t *cfg, json_t *jwe, const json_t *cek,
jose_io_t *next);
/**
* Unwraps and decrypts ciphertext.
*
* This function is a thin wrapper around the jose_jwe_dec_io() function
* allowing the user to obtain the plaintext in a single call. The ciphertext
* input will be obtained from the JWE "ciphertext" property.
*
* \see jose_jwe_dec_io()
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param rcp The JWE recipient object(s) or NULL.
* \param jwk The JWK(s) or JWKSet used for wrapping.
* \param ptl The length of the plaintext (output).
* \return The newly-allocated plaintext.
*/
void *
jose_jwe_dec(jose_cfg_t *cfg, const json_t *jwe, const json_t *rcp,
const json_t *jwk, size_t *ptl);
/**
* Unwraps and decrypts ciphertext using streaming.
*
* This function is a thin wrapper around the jose_jwe_dec_jwk() and
* jose_jwe_dec_cek_io() functions, removing the complexity of managing the CEK.
*
* \see jose_jwe_dec_jwk()
* \see jose_jwe_dec_cek_io()
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param rcp The JWE recipient object(s) or NULL.
* \param jwk The JWK(s) or JWKSet used for unwrapping.
* \param next The next IO object in the chain.
* \return The new IO object or NULL on error.
*/
jose_io_t *
jose_jwe_dec_io(jose_cfg_t *cfg, const json_t *jwe, const json_t *rcp,
const json_t *jwk, jose_io_t *next);
/**
* Unwraps a CEK with a JWK.
*
* The purpose of this function is to unwrap (decrypt) or, in some cases,
* produce the CEK (\p cek) from the provided JWK(s) (\p jwk). This function
* can be used in two modes: single-JWK and multi-JWK.
*
* In single-JWK mode, the \p jwk parameter contains a JWK object and the
* \p rcp parameter must contain either a JWE recipient object you wish to
* unwrap or NULL, in which case all JWE recipients will be tried.
*
* Multi-JWK mode works exactly the same as single-JWK mode except that it
* attempts to unwrap with multiple JWKs in a single call. This mode is enabled
* by passing either an array of JWK objects or a JWKSet as the \p jwk
* parameter. In this mode, the \p rcp parameter contains one of the following
* values:
*
* 1. A JWE recipient object that will be used for all attempted unwrappings.
*
* 2. An array of JWE recipient objects. Each object will be used with its
* corresponding JWK from \p jwk. If the arrays in \p sig and \p jwk are a
* different size, an error will occur.
*
* 3. NULL. This has the same effect as passing NULL for each separate JWK.
*
* In either mode, a CEK is returned for the first JWK that successfully
* unwraps a CEK. Two exceptions to this rule are if the "dir" or "ECDH-ES"
* algorithms are used. In this case, a CEK may be returned which will fail
* during decryption since there is no way to completely validate the JWK with
* these algorithms. Thus, we suggest placing the keys for these algorithms
* last when unwrapping with multiple JWKs.
*
* If the "alg" parameter is not specified in the JOSE Header, it will be
* inferred from the JWK. This includes using a JSON string in place of a JWK
* for the PBES2 family of algorithms.
*
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param rcp The JWE recipient object(s) or NULL.
* \param jwk The JWK(s) or JWKSet used for wrapping.
* \return On success, a newly-allocated CEK object. Otherwise, NULL.
*/
json_t *
jose_jwe_dec_jwk(jose_cfg_t *cfg, const json_t *jwe, const json_t *rcp,
const json_t *jwk);
/**
* Decrypts ciphertext with the CEK.
*
* This function is a thin wrapper around the jose_jwe_dec_cek_io() function
* allowing the user to obtain the plaintext in a single call. The ciphertext
* input will be obtained from the JWE "ciphertext" property.
*
* \see jose_jwe_dec_cek_io()
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param cek The CEK object.
* \param ptl The length of the plaintext (output).
* \return The newly-allocated plaintext.
*/
void *
jose_jwe_dec_cek(jose_cfg_t *cfg, const json_t *jwe, const json_t *cek,
size_t *ptl);
/**
* Decrypts ciphertext with the CEK using streaming.
*
* The ciphertext is provided through the returned IO object. The ciphertext
* will be decrypted and written to the \p next IO object. This IO object
* works on binary data, so you may need to use a URL-safe Base64 decoder on
* input and a URL-safe Base64 encoder on output, depending on your situation.
*
* Please note that validation of the ciphertext integrity protection is delayed
* until \ref jose_io_t.done() returns. This means it is incredibly important
* to check this return value and it is also important to be careful with the
* plaintext emitted until this check is performed.
*
* Compressed plaintext will be internally decompressed if the "zip" property
* is appropriately defined.
*
* If the "enc" parameter is not specified in the JWE Protected Header or the
* JWE Shared Unprotected Header, it will be inferred from the CEK.
*
* Please note that the "tag" property on the JWE will only be accessed when
* \ref jose_io_t.done() is called. So you may define it at any time on the
* JWE object before calling \ref jose_io_t.done().
*
* \param cfg The configuration context (optional).
* \param jwe The JWE object.
* \param cek The CEK object.
* \param next The next IO object in the chain.
* \return The new IO object or NULL on error.
*/
jose_io_t *
jose_jwe_dec_cek_io(jose_cfg_t *cfg, const json_t *jwe, const json_t *cek,
jose_io_t *next);
/** @} */