123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /* 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 inference 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);
- /** @} */
|