/*
 * libwebsockets - small server side websockets and web server implementation
 *
 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "private-lib-core.h"

/*
 * These came from RFC7518 (JSON Web Algorithms) Section 3
 *
 * Cryptographic Algorithms for Digital Signatures and MACs
 */

static const struct lws_jose_jwe_alg lws_gencrypto_jws_alg_map[] = {

	/*
	 * JWSs MAY also be created that do not provide integrity protection.
	 * Such a JWS is called an Unsecured JWS.  An Unsecured JWS uses the
	 * "alg" value "none" and is formatted identically to other JWSs, but
	 * MUST use the empty octet sequence as its JWS Signature value.
	 * Recipients MUST verify that the JWS Signature value is the empty
	 * octet sequence.
	 *
	 * Implementations that support Unsecured JWSs MUST NOT accept such
	 * objects as valid unless the application specifies that it is
	 * acceptable for a specific object to not be integrity protected.
	 * Implementations MUST NOT accept Unsecured JWSs by default.  In order
	 * to mitigate downgrade attacks, applications MUST NOT signal
	 * acceptance of Unsecured JWSs at a global level, and SHOULD signal
	 * acceptance on a per-object basis.  See Section 8.5 for security
	 * considerations associated with using this algorithm.
	 */
	{	/* optional */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_NONE,
		"none", NULL, 0, 0, 0
	},

	/*
	 * HMAC with SHA-2 Functions
	 *
	 * The HMAC SHA-256 MAC for a JWS is validated by computing an HMAC
	 * value per RFC 2104, using SHA-256 as the hash algorithm "H", using
	 * the received JWS Signing Input as the "text" value, and using the
	 * shared key.  This computed HMAC value is then compared to the result
	 * of base64url decoding the received encoded JWS Signature value.  The
	 * comparison of the computed HMAC value to the JWS Signature value MUST
	 * be done in a constant-time manner to thwart timing attacks.
	 *
	 * Alternatively, the computed HMAC value can be base64url encoded and
	 * compared to the received encoded JWS Signature value (also in a
	 * constant-time manner), as this comparison produces the same result as
	 * comparing the unencoded values.  In either case, if the values match,
	 * the HMAC has been validated.
	 */

	{	/* required: HMAC using SHA-256 */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_SHA256,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_NONE,
		"HS256", NULL, 0, 0, 0
	},
	{	/* optional: HMAC using SHA-384 */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_SHA384,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_NONE,
		"HS384", NULL, 0, 0, 0
	},
	{	/* optional: HMAC using SHA-512 */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_SHA512,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_NONE,
		"HS512", NULL, 0, 0, 0
	},

	/*
	 * Digital Signature with RSASSA-PKCS1-v1_5
	 *
	 * This section defines the use of the RSASSA-PKCS1-v1_5 digital
	 * signature algorithm as defined in Section 8.2 of RFC 3447 [RFC3447]
	 * (commonly known as PKCS #1), using SHA-2 [SHS] hash functions.
	 *
	 * A key of size 2048 bits or larger MUST be used with these algorithms.
	 *
	 * The RSASSA-PKCS1-v1_5 SHA-256 digital signature is generated as
	 * follows: generate a digital signature of the JWS Signing Input using
	 * RSASSA-PKCS1-v1_5-SIGN and the SHA-256 hash function with the desired
	 * private key.  This is the JWS Signature value.
	 *
	 * The RSASSA-PKCS1-v1_5 SHA-256 digital signature for a JWS is
	 * validated as follows: submit the JWS Signing Input, the JWS
	 * Signature, and the public key corresponding to the private key used
	 * by the signer to the RSASSA-PKCS1-v1_5-VERIFY algorithm using SHA-256
	 * as the hash function.
	 */

	{	/* recommended: RSASSA-PKCS1-v1_5 using SHA-256 */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5,
		LWS_JOSE_ENCTYPE_NONE,
		"RS256", NULL, 2048, 4096, 0
	},
	{	/* optional: RSASSA-PKCS1-v1_5 using SHA-384 */
		LWS_GENHASH_TYPE_SHA384,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5,
		LWS_JOSE_ENCTYPE_NONE,
		"RS384", NULL, 2048, 4096, 0
	},
	{	/* optional: RSASSA-PKCS1-v1_5 using SHA-512 */
		LWS_GENHASH_TYPE_SHA512,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5,
		LWS_JOSE_ENCTYPE_NONE,
		"RS512", NULL, 2048, 4096, 0
	},

	/*
	 * Digital Signature with ECDSA
	 *
	 * The ECDSA P-256 SHA-256 digital signature is generated as follows:
	 *
	 * 1.  Generate a digital signature of the JWS Signing Input using ECDSA
	 *     P-256 SHA-256 with the desired private key.  The output will be
	 *     the pair (R, S), where R and S are 256-bit unsigned integers.
	 * 2.  Turn R and S into octet sequences in big-endian order, with each
	 *     array being be 32 octets long.  The octet sequence
	 *     representations MUST NOT be shortened to omit any leading zero
	 *     octets contained in the values.
	 *
	 * 3.  Concatenate the two octet sequences in the order R and then S.
	 *     (Note that many ECDSA implementations will directly produce this
	 *     concatenation as their output.)
	 *
	 * 4.  The resulting 64-octet sequence is the JWS Signature value.
	 *
	 * The ECDSA P-256 SHA-256 digital signature for a JWS is validated as
	 * follows:
	 *
	 * 1.  The JWS Signature value MUST be a 64-octet sequence.  If it is
	 *     not a 64-octet sequence, the validation has failed.
	 *
	 * 2.  Split the 64-octet sequence into two 32-octet sequences.  The
	 *     first octet sequence represents R and the second S.  The values R
	 *     and S are represented as octet sequences using the Integer-to-
	 *     OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1]
	 *     (in big-endian octet order).
	 * 3.  Submit the JWS Signing Input, R, S, and the public key (x, y) to
	 *     the ECDSA P-256 SHA-256 validator.
	 */

	{	/* Recommended+: ECDSA using P-256 and SHA-256 */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDSA,
		LWS_JOSE_ENCTYPE_NONE,
		"ES256", "P-256", 256, 256, 0
	},
	{	/* optional: ECDSA using P-384 and SHA-384 */
		LWS_GENHASH_TYPE_SHA384,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDSA,
		LWS_JOSE_ENCTYPE_NONE,
		"ES384", "P-384", 384, 384, 0
	},
	{	/* optional: ECDSA using P-521 and SHA-512 */
		LWS_GENHASH_TYPE_SHA512,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDSA,
		LWS_JOSE_ENCTYPE_NONE,
		"ES512", "P-521", 521, 521, 0
	},
	{	/* Recommended+: EdDSA using Ed25519 and Ed448 */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_EDDSA,
		LWS_JOSE_ENCTYPE_NONE,
		"EdDSA", NULL, 0, 0, 0
	},
#if 0
	Not yet supported

	/*
	 * Digital Signature with RSASSA-PSS
	 *
	 * A key of size 2048 bits or larger MUST be used with this algorithm.
	 *
	 * The RSASSA-PSS SHA-256 digital signature is generated as follows:
	 * generate a digital signature of the JWS Signing Input using RSASSA-
	 * PSS-SIGN, the SHA-256 hash function, and the MGF1 mask generation
	 * function with SHA-256 with the desired private key.  This is the JWS
	 * Signature value.
	 *
	 * The RSASSA-PSS SHA-256 digital signature for a JWS is validated as
	 * follows: submit the JWS Signing Input, the JWS Signature, and the
	 * public key corresponding to the private key used by the signer to the
	 * RSASSA-PSS-VERIFY algorithm using SHA-256 as the hash function and
	 * using MGF1 as the mask generation function with SHA-256.
	 *
	 */
	{	/* optional: RSASSA-PSS using SHA-256 and MGF1 with SHA-256 */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS,
		LWS_JOSE_ENCTYPE_NONE,
		"PS256", NULL, 2048, 4096, 0
	},
	{	/* optional: RSASSA-PSS using SHA-384 and MGF1 with SHA-384 */
		LWS_GENHASH_TYPE_SHA384,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS,
		LWS_JOSE_ENCTYPE_NONE,
		"PS384", NULL, 2048, 4096, 0
	},
	{	/* optional: RSASSA-PSS using SHA-512 and MGF1 with SHA-512*/
		LWS_GENHASH_TYPE_SHA512,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS,
		LWS_JOSE_ENCTYPE_NONE,
		"PS512", NULL, 2048, 4096, 0
	},
#endif
	/* list terminator */
	{ 0, 0, 0, 0, NULL, NULL, 0, 0, 0}
};

/*
 * These came from RFC7518 (JSON Web Algorithms) Section 4
 *
 * Cryptographic Algorithms for Key Management
 *
 * JWE uses cryptographic algorithms to encrypt or determine the Content
 * Encryption Key (CEK).
 */

static const struct lws_jose_jwe_alg lws_gencrypto_jwe_alg_map[] = {

	/*
	 * This section defines the specifics of encrypting a JWE CEK with
	 * RSAES-PKCS1-v1_5 [RFC3447].  The "alg" (algorithm) Header Parameter
	 * value "RSA1_5" is used for this algorithm.
	 *
	 * A key of size 2048 bits or larger MUST be used with this algorithm.
	 */


	{	/* recommended+: RSAES OAEP using default parameters */
		LWS_GENHASH_TYPE_SHA1,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP,
		LWS_JOSE_ENCTYPE_NONE,
		"RSA-OAEP", NULL, 2048, 4096, 0
	},
	{	/* recommended+: RSAES OAEP using SHA-256 and MGF1 SHA-256 */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP,
		LWS_JOSE_ENCTYPE_NONE,
		"RSA-OAEP-256", NULL, 2048, 4096, 0
	},

	/*
	 * Key Wrapping with AES Key Wrap
	 *
	 * This section defines the specifics of encrypting a JWE CEK with the
	 * Advanced Encryption Standard (AES) Key Wrap Algorithm [RFC3394] using
	 * the default initial value specified in Section 2.2.3.1 of that
	 * document.
	 *
	 *
	 */
	{	/* recommended: AES Key Wrap with AES Key Wrap with defaults
				using 128-bit key  */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_AES_ECB,
		LWS_JOSE_ENCTYPE_NONE,
		"A128KW", NULL, 128, 128, 64
	},

	{	/* optional: AES Key Wrap with AES Key Wrap with defaults
				using 192-bit key */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_AES_ECB,
		LWS_JOSE_ENCTYPE_NONE,
		"A192KW", NULL, 192, 192, 64
	},

	{	/* recommended: AES Key Wrap with AES Key Wrap with defaults
				using 256-bit key */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_AES_ECB,
		LWS_JOSE_ENCTYPE_NONE,
		"A256KW", NULL, 256, 256, 64
	},

	/*
	 * This section defines the specifics of directly performing symmetric
	 * key encryption without performing a key wrapping step.  In this case,
	 * the shared symmetric key is used directly as the Content Encryption
	 * Key (CEK) value for the "enc" algorithm.  An empty octet sequence is
	 * used as the JWE Encrypted Key value.  The "alg" (algorithm) Header
	 * Parameter value "dir" is used in this case.
	 */
	{	/* recommended */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_NONE,
		"dir", NULL, 0, 0, 0
	},

	/*
	 * Key Agreement with Elliptic Curve Diffie-Hellman Ephemeral Static
	 * (ECDH-ES)
	 *
	 * This section defines the specifics of key agreement with Elliptic
	 * Curve Diffie-Hellman Ephemeral Static [RFC6090], in combination with
	 * the Concat KDF, as defined in Section 5.8.1 of [NIST.800-56A].  The
	 * key agreement result can be used in one of two ways:
	 *
	 * 1.  directly as the Content Encryption Key (CEK) for the "enc"
	 *     algorithm, in the Direct Key Agreement mode, or
	 *
	 * 2.  as a symmetric key used to wrap the CEK with the "A128KW",
	 *     "A192KW", or "A256KW" algorithms, in the Key Agreement with Key
	 *     Wrapping mode.
	 *
	 * A new ephemeral public key value MUST be generated for each key
	 * agreement operation.
	 *
	 * In Direct Key Agreement mode, the output of the Concat KDF MUST be a
	 * key of the same length as that used by the "enc" algorithm.  In this
	 * case, the empty octet sequence is used as the JWE Encrypted Key
	 * value.  The "alg" (algorithm) Header Parameter value "ECDH-ES" is
	 * used in the Direct Key Agreement mode.
	 *
	 * In Key Agreement with Key Wrapping mode, the output of the Concat KDF
	 * MUST be a key of the length needed for the specified key wrapping
	 * algorithm.  In this case, the JWE Encrypted Key is the CEK wrapped
	 * with the agreed-upon key.
	 */

	{	/* recommended+: ECDH Ephemeral Static Key agreement Concat KDF */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDHES,
		LWS_JOSE_ENCTYPE_NONE,
		"ECDH-ES", NULL, 128, 128, 0
	},
	{	/* recommended: ECDH-ES + Concat KDF + wrapped by AES128KW */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDHES,
		LWS_JOSE_ENCTYPE_AES_ECB,
		"ECDH-ES+A128KW", NULL, 128, 128, 0
	},
	{	/* optional: ECDH-ES + Concat KDF + wrapped by AES192KW */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDHES,
		LWS_JOSE_ENCTYPE_AES_ECB,
		"ECDH-ES+A192KW", NULL, 192, 192, 0
	},
	{	/* recommended: ECDH-ES + Concat KDF + wrapped by AES256KW */
		LWS_GENHASH_TYPE_SHA256,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_ECDHES,
		LWS_JOSE_ENCTYPE_AES_ECB,
		"ECDH-ES+A256KW", NULL, 256, 256, 0
	},

	/*
	 * Key Encryption with AES GCM
	 *
	 *  This section defines the specifics of encrypting a JWE Content
	 *  Encryption Key (CEK) with Advanced Encryption Standard (AES) in
	 *  Galois/Counter Mode (GCM) ([AES] and [NIST.800-38D]).
	 *
	 * Use of an Initialization Vector (IV) of size 96 bits is REQUIRED with
	 * this algorithm.  The IV is represented in base64url-encoded form as
	 * the "iv" (initialization vector) Header Parameter value.
	 *
	 * The Additional Authenticated Data value used is the empty octet
	 * string.
	 *
	 * The requested size of the Authentication Tag output MUST be 128 bits,
	 * regardless of the key size.
	 *
	 * The JWE Encrypted Key value is the ciphertext output.
	 *
	 * The Authentication Tag output is represented in base64url-encoded
	 * form as the "tag" (authentication tag) Header Parameter value.
	 *
	 *
	 * "iv" (Initialization Vector) Header Parameter
	 *
	 * The "iv" (initialization vector) Header Parameter value is the
	 * base64url-encoded representation of the 96-bit IV value used for the
	 * key encryption operation.  This Header Parameter MUST be present and
	 * MUST be understood and processed by implementations when these
	 * algorithms are used.
	 *
	 * "tag" (Authentication Tag) Header Parameter
	 *
	 * The "tag" (authentication tag) Header Parameter value is the
	 * base64url-encoded representation of the 128-bit Authentication Tag
	 * value resulting from the key encryption operation.  This Header
	 * Parameter MUST be present and MUST be understood and processed by
	 * implementations when these algorithms are used.
	 */
	{	/* optional: Key wrapping with AES GCM using 128-bit key  */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_AES_ECB,
		LWS_JOSE_ENCTYPE_NONE,
		"A128GCMKW", NULL, 128, 128, 96
	},

	{	/* optional: Key wrapping with AES GCM using 192-bit key */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_AES_ECB,
		LWS_JOSE_ENCTYPE_NONE,
		"A192GCMKW", NULL, 192, 192, 96
	},

	{	/* optional: Key wrapping with AES GCM using 256-bit key */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_AES_ECB,
		LWS_JOSE_ENCTYPE_NONE,
		"A256GCMKW", NULL, 256, 256, 96
	},

	/* list terminator */
	{ 0, 0, 0, 0, NULL, NULL, 0, 0, 0 }
};

/*
 * The "enc" (encryption algorithm) Header Parameter identifies the
 * content encryption algorithm used to perform authenticated encryption
 * on the plaintext to produce the ciphertext and the Authentication
 * Tag.  This algorithm MUST be an AEAD algorithm with a specified key
 * length.  The encrypted content is not usable if the "enc" value does
 * not represent a supported algorithm.  "enc" values should either be
 * registered in the IANA "JSON Web Signature and Encryption Algorithms"
 * registry established by [JWA] or be a value that contains a
 * Collision-Resistant Name.  The "enc" value is a case-sensitive ASCII
 * string containing a StringOrURI value.  This Header Parameter MUST be
 * present and MUST be understood and processed by implementations.
 */

static const struct lws_jose_jwe_alg lws_gencrypto_jwe_enc_map[] = {
	/*
	 * AES_128_CBC_HMAC_SHA_256 / 512
	 *
	 * It uses the HMAC message authentication code [RFC2104] with the
	 * SHA-256 hash function [SHS] to provide message authentication, with
	 * the HMAC output truncated to 128 bits, corresponding to the
	 * HMAC-SHA-256-128 algorithm defined in [RFC4868].  For encryption, it
	 * uses AES in the CBC mode of operation as defined in Section 6.2 of
	 * [NIST.800-38A], with PKCS #7 padding and a 128-bit IV value.
	 *
	 * The AES_CBC_HMAC_SHA2 parameters specific to AES_128_CBC_HMAC_SHA_256
	 * are:
	 *
	 * The input key K is 32 octets long.
	 *       ENC_KEY_LEN is 16 octets.
	 *       MAC_KEY_LEN is 16 octets.
	 *       The SHA-256 hash algorithm is used for the HMAC.
	 *       The HMAC-SHA-256 output is truncated to T_LEN=16 octets, by
	 *       stripping off the final 16 octets.
	 */
	{	/* required */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_SHA256,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_AES_CBC,
		"A128CBC-HS256", NULL, 256, 256, 128
	},
	/*
	 * AES_192_CBC_HMAC_SHA_384 is based on AES_128_CBC_HMAC_SHA_256, but
	 * with the following differences:
	 *
	 * The input key K is 48 octets long instead of 32.
	 * ENC_KEY_LEN is 24 octets instead of 16.
	 * MAC_KEY_LEN is 24 octets instead of 16.
	 * SHA-384 is used for the HMAC instead of SHA-256.
	 * The HMAC SHA-384 value is truncated to T_LEN=24 octets instead of 16.
	 */
	{	/* required */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_SHA384,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_AES_CBC,
		"A192CBC-HS384", NULL, 384, 384, 192
	},
	/*
	 * AES_256_CBC_HMAC_SHA_512 is based on AES_128_CBC_HMAC_SHA_256, but
	 * with the following differences:
	 *
	 * The input key K is 64 octets long instead of 32.
	 * ENC_KEY_LEN is 32 octets instead of 16.
	 * MAC_KEY_LEN is 32 octets instead of 16.
	 * SHA-512 is used for the HMAC instead of SHA-256.
	 * The HMAC SHA-512 value is truncated to T_LEN=32 octets instead of 16.
	 */
	{	/* required */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_SHA512,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_AES_CBC,
		"A256CBC-HS512", NULL, 512, 512, 256
	},

	/*
	 * The CEK is used as the encryption key.
	 *
	 * Use of an IV of size 96 bits is REQUIRED with this algorithm.
	 *
	 * The requested size of the Authentication Tag output MUST be 128 bits,
	 * regardless of the key size.
	 */
	{	/* recommended: AES GCM using 128-bit key  */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_AES_GCM,
		"A128GCM", NULL, 128, 128, 96
	},
	{	/* optional: AES GCM using 192-bit key  */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_AES_GCM,
		"A192GCM", NULL, 192, 192, 96
	},
	{	/* recommended: AES GCM using 256-bit key */
		LWS_GENHASH_TYPE_UNKNOWN,
		LWS_GENHMAC_TYPE_UNKNOWN,
		LWS_JOSE_ENCTYPE_NONE,
		LWS_JOSE_ENCTYPE_AES_GCM,
		"A256GCM", NULL, 256, 256, 96
	},
	{ 0, 0, 0, 0, NULL, NULL, 0, 0, 0 } /* sentinel */
};

int
lws_gencrypto_jws_alg_to_definition(const char *alg,
				    const struct lws_jose_jwe_alg **jose)
{
	const struct lws_jose_jwe_alg *a = lws_gencrypto_jws_alg_map;

	while (a->alg) {
		if (!strcmp(alg, a->alg)) {
			*jose = a;

			return 0;
		}
		a++;
	}

	return 1;
}

int
lws_gencrypto_jwe_alg_to_definition(const char *alg,
				    const struct lws_jose_jwe_alg **jose)
{
	const struct lws_jose_jwe_alg *a = lws_gencrypto_jwe_alg_map;

	while (a->alg) {
		if (!strcmp(alg, a->alg)) {
			*jose = a;

			return 0;
		}
		a++;
	}

	return 1;
}

int
lws_gencrypto_jwe_enc_to_definition(const char *enc,
				    const struct lws_jose_jwe_alg **jose)
{
	const struct lws_jose_jwe_alg *e = lws_gencrypto_jwe_enc_map;

	while (e->alg) {
		if (!strcmp(enc, e->alg)) {
			*jose = e;

			return 0;
		}
		e++;
	}

	return 1;
}

size_t
lws_genhash_size(enum lws_genhash_types type)
{
	switch(type) {
	case LWS_GENHASH_TYPE_UNKNOWN:
		return 0;
	case LWS_GENHASH_TYPE_MD5:
		return 16;
	case LWS_GENHASH_TYPE_SHA1:
		return 20;
	case LWS_GENHASH_TYPE_SHA256:
		return 32;
	case LWS_GENHASH_TYPE_SHA384:
		return 48;
	case LWS_GENHASH_TYPE_SHA512:
		return 64;
	}

	return 0;
}

size_t
lws_genhmac_size(enum lws_genhmac_types type)
{
	switch(type) {
	case LWS_GENHMAC_TYPE_UNKNOWN:
		return 0;
	case LWS_GENHMAC_TYPE_SHA1:
		return 20;
	case LWS_GENHMAC_TYPE_SHA256:
		return 32;
	case LWS_GENHMAC_TYPE_SHA384:
		return 48;
	case LWS_GENHMAC_TYPE_SHA512:
		return 64;
	}

	return 0;
}

int
lws_gencrypto_bits_to_bytes(int bits)
{
	if (bits & 7)
		return (bits / 8) + 1;

	return bits / 8;
}

int
lws_base64_size(int bytes)
{
	return ((bytes * 4) / 3) + 6;
}

void
lws_gencrypto_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
{
	int n;

	for (n = 0; n < m; n++)
		if (el[n].buf)
			lws_free_set_NULL(el[n].buf);
}

size_t lws_gencrypto_padded_length(size_t pad_block_size, size_t len)
{
	return (len / pad_block_size + 1) * pad_block_size;
}

int
lws_genhash_render(enum lws_genhash_types type, const uint8_t *hash, char *out, size_t out_len)
{
	size_t hs = lws_genhash_size(type);
	size_t i;

	if (!hs) {
		if (out_len)
			out[0] = '\0';
		return -1;
	}

	if (out_len < (hs * 2) + 1) {
		/* Needs truncation with ellipsis? */
		if (out_len > 4) {
			for (i = 0; i < (out_len - 4) / 2; i++)
				lws_snprintf(out + (i * 2), 3, "%02x", hash[i]);
			lws_strncpy(out + (i * 2), "...", out_len - (i * 2));
			return 0;
		}
		if (out_len)
			out[0] = '\0';
		return -1;
	}

	for (i = 0; i < hs; i++)
		lws_snprintf(out + (i * 2), 3, "%02x", hash[i]);

	out[i * 2] = '\0';

	return 0;
}

int
lws_genhash_render_prefixed(enum lws_genhash_types type, const uint8_t *hash, char *out, size_t out_len)
{
	const char *t;
	int n;

	switch (type) {
	case LWS_GENHASH_TYPE_MD5:	t = "MD5"; break;
	case LWS_GENHASH_TYPE_SHA1:	t = "SHA1"; break;
	case LWS_GENHASH_TYPE_SHA256:	t = "SHA256"; break;
	case LWS_GENHASH_TYPE_SHA384:	t = "SHA384"; break;
	case LWS_GENHASH_TYPE_SHA512:	t = "SHA512"; break;
	default: return -1;
	}

	n = lws_snprintf(out, out_len, "%s:", t);
	if (n < 0 || (size_t)n >= out_len)
		return -1;

	return lws_genhash_render(type, hash, out + n, out_len - (size_t)n);
}

int
lws_genhkdf_extract(enum lws_genhmac_types type, const uint8_t *salt,
                    size_t salt_len, const uint8_t *ikm, size_t ikm_len,
                    uint8_t *prk)
{
	struct lws_genhmac_ctx ctx;
	int ret = -1;
	size_t hs;
	uint8_t z[LWS_GENHASH_LARGEST];

	hs = lws_genhmac_size(type);
	if (!hs)
		return -1;

	if (!salt || !salt_len) {
		memset(z, 0, hs);
		salt = z;
		salt_len = hs;
	}

	if (lws_genhmac_init(&ctx, type, salt, salt_len))
		return -1;

	if (ikm_len && lws_genhmac_update(&ctx, ikm, ikm_len))
		goto bail;

	if (lws_genhmac_destroy(&ctx, prk))
		return -1;

	return 0;

bail:
	lws_genhmac_destroy(&ctx, NULL);
	return ret;
}

int
lws_genhkdf_expand(enum lws_genhmac_types type, const uint8_t *prk,
                   size_t prk_len, const uint8_t *info, size_t info_len,
                   uint8_t *okm, size_t okm_len)
{
	struct lws_genhmac_ctx ctx;
	uint8_t t[LWS_GENHASH_LARGEST];
	size_t hs = lws_genhmac_size(type);
	size_t t_len = 0, remain = okm_len, copy_len;
	uint8_t count = 1;
	int ret = -1;

	if (!hs || !okm_len || !prk || !okm)
		return -1;

	while (remain) {
		if (lws_genhmac_init(&ctx, type, prk, prk_len))
			return -1;

		if (t_len && lws_genhmac_update(&ctx, t, t_len))
			goto bail;

		if (info && info_len && lws_genhmac_update(&ctx, info, info_len))
			goto bail;

		if (lws_genhmac_update(&ctx, &count, 1))
			goto bail;

		if (lws_genhmac_destroy(&ctx, t))
			return -1;

		t_len = hs;
		copy_len = remain > hs ? hs : remain;
		memcpy(okm, t, copy_len);
		okm += copy_len;
		remain -= copy_len;
		count++;
	}

	return 0;

bail:
	lws_genhmac_destroy(&ctx, NULL);
	return ret;
}

int
lws_genhkdf_expand_label(enum lws_genhmac_types type, const uint8_t *prk,
                         size_t prk_len, const char *label,
                         const uint8_t *context, size_t context_len,
                         uint8_t *okm, size_t okm_len)
{
	uint8_t info[256 + 256 + 4];
	size_t info_len = 0;
	size_t label_len;

	if (!label)
		return -1;

	label_len = strlen(label);
	/* "tls13 " length is 6, so label_len + 6 must be <= 255 */
	if (label_len + 6 > 255 || context_len > 255)
		return -1;

	/* Length (uint16) */
	info[info_len++] = (okm_len >> 8) & 0xff;
	info[info_len++] = okm_len & 0xff;

	/* Label length (uint8) */
	info[info_len++] = (uint8_t)(label_len + 6);
	memcpy(&info[info_len], "tls13 ", 6);
	info_len += 6;
	memcpy(&info[info_len], label, label_len);
	info_len += label_len;

	/* Context length (uint8) */
	info[info_len++] = (uint8_t)context_len;
	if (context_len && context) {
		memcpy(&info[info_len], context, context_len);
		info_len += context_len;
	}

	return lws_genhkdf_expand(type, prk, prk_len, info, info_len, okm, okm_len);
}
