mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-23 00:00:06 +01:00
398 lines
13 KiB
C
398 lines
13 KiB
C
/*
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
*
|
|
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation:
|
|
* version 2.1 of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*
|
|
* included from libwebsockets.h
|
|
*/
|
|
|
|
/*! \defgroup jws JSON Web Signature
|
|
* ## JSON Web Signature API
|
|
*
|
|
* Lws provides an API to check and create RFC7515 JSON Web Signatures
|
|
*
|
|
* SHA256/384/512 HMAC, and RSA 256/384/512 are supported.
|
|
*
|
|
* The API uses your TLS library crypto, but works exactly the same no matter
|
|
* what your TLS backend is.
|
|
*/
|
|
///@{
|
|
|
|
/*
|
|
* The maps are built to work with both JWS (LJWS_) and JWE (LJWE_), and are
|
|
* sized to the slightly larger JWE case.
|
|
*/
|
|
|
|
enum enum_jws_sig_elements {
|
|
|
|
/* JWS block namespace */
|
|
LJWS_JOSE,
|
|
LJWS_PYLD,
|
|
LJWS_SIG,
|
|
LJWS_UHDR,
|
|
|
|
/* JWE block namespace */
|
|
LJWE_JOSE = 0,
|
|
LJWE_EKEY,
|
|
LJWE_IV,
|
|
LJWE_CTXT,
|
|
LJWE_ATAG,
|
|
LJWE_AAD,
|
|
|
|
LWS_JWS_MAX_COMPACT_BLOCKS
|
|
};
|
|
|
|
struct lws_jws_map {
|
|
const char *buf[LWS_JWS_MAX_COMPACT_BLOCKS];
|
|
uint32_t len[LWS_JWS_MAX_COMPACT_BLOCKS];
|
|
};
|
|
|
|
#define LWS_JWS_MAX_SIGS 3
|
|
|
|
struct lws_jws {
|
|
struct lws_jwk *jwk; /* the struct lws_jwk containing the signing key */
|
|
struct lws_context *context; /* the lws context (used to get random) */
|
|
struct lws_jws_map map, map_b64;
|
|
};
|
|
|
|
/* jws EC signatures do not have ASN.1 in them, meaning they're incompatible
|
|
* with generic signatures.
|
|
*/
|
|
|
|
/**
|
|
* lws_jws_init() - initialize a jws for use
|
|
*
|
|
* \param jws: pointer to the jws to initialize
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
|
|
struct lws_context *context);
|
|
|
|
/**
|
|
* lws_jws_destroy() - scrub a jws
|
|
*
|
|
* \param jws: pointer to the jws to destroy
|
|
*
|
|
* Call before the jws goes out of scope.
|
|
*
|
|
* Elements defined in the jws are zeroed.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
lws_jws_destroy(struct lws_jws *jws);
|
|
|
|
/**
|
|
* lws_jws_sig_confirm_compact() - check signature
|
|
*
|
|
* \param map: pointers and lengths for each of the unencoded JWS elements
|
|
* \param jwk: public key
|
|
* \param content: lws_context
|
|
*
|
|
* Confirms the signature on a JWS. Use if you have non-b64 plain JWS elements
|
|
* in a map... it'll make a temp b64 version needed for comparison. See below
|
|
* for other variants.
|
|
*
|
|
* Returns 0 on match.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
|
|
struct lws_context *context,
|
|
char *temp, int *temp_len);
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
|
|
struct lws_jwk *jwk,
|
|
struct lws_context *context,
|
|
char *temp, int *temp_len);
|
|
|
|
/**
|
|
* lws_jws_sig_confirm_compact_b64() - check signature on b64 compact JWS
|
|
*
|
|
* \param in: pointer to b64 jose.payload[.hdr].sig
|
|
* \param len: bytes available at \p in
|
|
* \param map: map to take decoded non-b64 content
|
|
* \param jwk: public key
|
|
* \param content: lws_context
|
|
*
|
|
* Confirms the signature on a JWS. Use if you have you have b64 compact layout
|
|
* (jose.payload.hdr.sig) as an aggregated string... it'll make a temp plain
|
|
* version needed for comparison.
|
|
*
|
|
* Returns 0 on match.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
|
|
struct lws_jws_map *map,
|
|
struct lws_jwk *jwk,
|
|
struct lws_context *context,
|
|
char *temp, int *temp_len);
|
|
|
|
/**
|
|
* lws_jws_sig_confirm() - check signature on plain + b64 JWS elements
|
|
*
|
|
* \param map_b64: pointers and lengths for each of the b64-encoded JWS elements
|
|
* \param map: pointers and lengths for each of the unencoded JWS elements
|
|
* \param jwk: public key
|
|
* \param content: lws_context
|
|
*
|
|
* Confirms the signature on a JWS. Use if you have you already have both b64
|
|
* compact layout (jose.payload.hdr.sig) and decoded JWS elements in maps.
|
|
*
|
|
* If you had the b64 string and called lws_jws_compact_decode() on it, you
|
|
* will end up with both maps, and can use this api version, saving needlessly
|
|
* regenerating any temp map.
|
|
*
|
|
* Returns 0 on match.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_sig_confirm(struct lws_jws_map *map_b64, /* b64-encoded */
|
|
struct lws_jws_map *map, /* non-b64 */
|
|
struct lws_jwk *jwk, struct lws_context *context);
|
|
|
|
/**
|
|
* lws_jws_sign_from_b64() - add b64 sig to b64 hdr + payload
|
|
*
|
|
* \param jose: jose header information
|
|
* \param jws: information to include in the signature
|
|
* \param b64_sig: output buffer for b64 signature
|
|
* \param sig_len: size of \p b64_sig output buffer
|
|
*
|
|
* This adds a b64-coded JWS signature of the b64-encoded protected header
|
|
* and b64-encoded payload, at \p b64_sig. The signature will be as large
|
|
* as the N element of the RSA key when the RSA key is used, eg, 512 bytes for
|
|
* a 4096-bit key, and then b64-encoding on top.
|
|
*
|
|
* In some special cases, there is only payload to sign and no header, in that
|
|
* case \p b64_hdr may be NULL, and only the payload will be hashed before
|
|
* signing.
|
|
*
|
|
* Returns the length of the encoded signature written to \p b64_sig, or -1.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, char *b64_sig,
|
|
size_t sig_len);
|
|
|
|
/**
|
|
* lws_jws_compact_decode() - converts and maps compact serialization b64 sections
|
|
*
|
|
* \param in: the incoming compact serialized b64
|
|
* \param len: the length of the incoming compact serialized b64
|
|
* \param map: pointer to the results structure
|
|
* \param map_b64: NULL, or pointer to a second results structure taking block
|
|
* information about the undecoded b64
|
|
* \param out: buffer to hold decoded results
|
|
* \param out_len: size of out in bytes
|
|
*
|
|
* Returns number of sections (2 if "none", else 3), or -1 if illegal.
|
|
*
|
|
* map is set to point to the start and hold the length of each decoded block.
|
|
* If map_b64 is non-NULL, then it's set with information about the input b64
|
|
* blocks.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
|
|
struct lws_jws_map *map_b64, char *out, int *out_len);
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
|
|
const struct lws_jws_map *map, /* non-b64 */
|
|
char *buf, int *out_len);
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_sig_confirm_json(const char *in, size_t len,
|
|
struct lws_jws *jws, struct lws_jwk *jwk,
|
|
struct lws_context *context,
|
|
char *temp, int *temp_len);
|
|
|
|
/**
|
|
* lws_jws_write_flattened_json() - create flattened JSON sig
|
|
*
|
|
* \param jws: information to include in the signature
|
|
* \param flattened: output buffer for JSON
|
|
* \param len: size of \p flattened output buffer
|
|
*
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len);
|
|
|
|
/**
|
|
* lws_jws_write_compact() - create flattened JSON sig
|
|
*
|
|
* \param jws: information to include in the signature
|
|
* \param compact: output buffer for compact format
|
|
* \param len: size of \p flattened output buffer
|
|
*
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len);
|
|
|
|
|
|
|
|
/*
|
|
* below apis are not normally needed if dealing with whole JWS... they're
|
|
* useful for creating from scratch
|
|
*/
|
|
|
|
|
|
/**
|
|
* lws_jws_dup_element() - allocate space for an element and copy data into it
|
|
*
|
|
* \param map: map to create the element in
|
|
* \param idx: index of element in the map to create
|
|
* \param temp: space to allocate in
|
|
* \param temp_len: available space at temp
|
|
* \param in: data to duplicate into element
|
|
* \param in_len: length of data to duplicate
|
|
* \param actual_alloc: 0 for same as in_len, else actual allocation size
|
|
*
|
|
* Copies in_len from in to temp, if temp_len is sufficient.
|
|
*
|
|
* Returns 0 or -1 if not enough space in temp / temp_len.
|
|
*
|
|
* Over-allocation can be acheived by setting actual_alloc to the real
|
|
* allocation desired... in_len will be copied into it.
|
|
*
|
|
* *temp_len is reduced by actual_alloc if successful.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_dup_element(struct lws_jws_map *map, int idx,
|
|
char *temp, int *temp_len, const void *in, size_t in_len,
|
|
size_t actual_alloc);
|
|
|
|
/**
|
|
* lws_jws_randomize_element() - create an element and fill with random
|
|
*
|
|
* \param context: lws_context used for random
|
|
* \param map: map to create the element in
|
|
* \param idx: index of element in the map to create
|
|
* \param temp: space to allocate in
|
|
* \param temp_len: available space at temp
|
|
* \param random_len: length of data to fill with random
|
|
* \param actual_alloc: 0 for same as random_len, else actual allocation size
|
|
*
|
|
* Randomize random_len bytes at temp, if temp_len is sufficient.
|
|
*
|
|
* Returns 0 or -1 if not enough space in temp / temp_len.
|
|
*
|
|
* Over-allocation can be acheived by setting actual_alloc to the real
|
|
* allocation desired... the first random_len will be filled with random.
|
|
*
|
|
* *temp_len is reduced by actual_alloc if successful.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_randomize_element(struct lws_context *context,
|
|
struct lws_jws_map *map,
|
|
int idx, char *temp, int *temp_len, size_t random_len,
|
|
size_t actual_alloc);
|
|
|
|
/**
|
|
* lws_jws_alloc_element() - create an element and reserve space for content
|
|
*
|
|
* \param map: map to create the element in
|
|
* \param idx: index of element in the map to create
|
|
* \param temp: space to allocate in
|
|
* \param temp_len: available space at temp
|
|
* \param len: logical length of element
|
|
* \param actual_alloc: 0 for same as len, else actual allocation size
|
|
*
|
|
* Allocate len bytes at temp, if temp_len is sufficient.
|
|
*
|
|
* Returns 0 or -1 if not enough space in temp / temp_len.
|
|
*
|
|
* Over-allocation can be acheived by setting actual_alloc to the real
|
|
* allocation desired... the element logical length will be set to len.
|
|
*
|
|
* *temp_len is reduced by actual_alloc if successful.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
|
|
int *temp_len, size_t len, size_t actual_alloc);
|
|
|
|
/**
|
|
* lws_jws_encode_b64_element() - create an b64-encoded element
|
|
*
|
|
* \param map: map to create the element in
|
|
* \param idx: index of element in the map to create
|
|
* \param temp: space to allocate in
|
|
* \param temp_len: available space at temp
|
|
* \param in: pointer to unencoded input
|
|
* \param in_len: length of unencoded input
|
|
*
|
|
* Allocate len bytes at temp, if temp_len is sufficient.
|
|
*
|
|
* Returns 0 or -1 if not enough space in temp / temp_len.
|
|
*
|
|
* Over-allocation can be acheived by setting actual_alloc to the real
|
|
* allocation desired... the element logical length will be set to len.
|
|
*
|
|
* *temp_len is reduced by actual_alloc if successful.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
|
|
char *temp, int *temp_len, const void *in,
|
|
size_t in_len);
|
|
|
|
|
|
/**
|
|
* lws_jws_b64_compact_map() - find block starts and lengths in compact b64
|
|
*
|
|
* \param in: pointer to b64 jose.payload[.hdr].sig
|
|
* \param len: bytes available at \p in
|
|
* \param map: output struct with pointers and lengths for each JWS element
|
|
*
|
|
* Scans a jose.payload[.hdr].sig b64 string and notes where the blocks start
|
|
* and their length into \p map.
|
|
*
|
|
* Returns number of blocks if OK. May return <0 if malformed.
|
|
* May not fill all map entries.
|
|
*/
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map);
|
|
|
|
|
|
/**
|
|
* lws_jws_base64_enc() - encode input data into b64url data
|
|
*
|
|
* \param in: the incoming plaintext
|
|
* \param in_len: the length of the incoming plaintext in bytes
|
|
* \param out: the buffer to store the b64url encoded data to
|
|
* \param out_max: the length of \p out in bytes
|
|
*
|
|
* Returns either -1 if problems, or the number of bytes written to \p out.
|
|
*/
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
|
|
|
|
/**
|
|
* lws_jws_encode_section() - encode input data into b64url data,
|
|
* prepending . if not first
|
|
*
|
|
* \param in: the incoming plaintext
|
|
* \param in_len: the length of the incoming plaintext in bytes
|
|
* \param first: nonzero if the first section
|
|
* \param out: the buffer to store the b64url encoded data to
|
|
* \param out_max: the length of \p out in bytes
|
|
*
|
|
* Returns either -1 if problems, or the number of bytes written to \p out.
|
|
* If the section is not the first one, '.' is prepended.
|
|
*/
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
|
|
char *end);
|
|
///@}
|