• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 /*! \defgroup jws JSON Web Signature
26  * ## JSON Web Signature API
27  *
28  * Lws provides an API to check and create RFC7515 JSON Web Signatures
29  *
30  * SHA256/384/512 HMAC, and RSA 256/384/512 are supported.
31  *
32  * The API uses your TLS library crypto, but works exactly the same no matter
33  * what your TLS backend is.
34  */
35 ///@{
36 
37 /*
38  * The maps are built to work with both JWS (LJWS_) and JWE (LJWE_), and are
39  * sized to the slightly larger JWE case.
40  */
41 
42 enum enum_jws_sig_elements {
43 
44 	/* JWS block namespace */
45 	LJWS_JOSE,
46 	LJWS_PYLD,
47 	LJWS_SIG,
48 	LJWS_UHDR,
49 
50 	/* JWE block namespace */
51 	LJWE_JOSE = 0,
52 	LJWE_EKEY,
53 	LJWE_IV,
54 	LJWE_CTXT,
55 	LJWE_ATAG,
56 	LJWE_AAD,
57 
58 	LWS_JWS_MAX_COMPACT_BLOCKS
59 };
60 
61 struct lws_jws_map {
62 	const char *buf[LWS_JWS_MAX_COMPACT_BLOCKS];
63 	uint32_t len[LWS_JWS_MAX_COMPACT_BLOCKS];
64 };
65 
66 #define LWS_JWS_MAX_SIGS 3
67 
68 struct lws_jws {
69 	struct lws_jwk *jwk; /* the struct lws_jwk containing the signing key */
70 	struct lws_context *context; /* the lws context (used to get random) */
71 	struct lws_jws_map map, map_b64;
72 };
73 
74 /* jws EC signatures do not have ASN.1 in them, meaning they're incompatible
75  * with generic signatures.
76  */
77 
78 /**
79  * lws_jws_init() - initialize a jws for use
80  *
81  * \param jws: pointer to the jws to initialize
82  * \param jwk: the jwk to use with this jws
83  * \param context: the lws_context to use
84  */
85 LWS_VISIBLE LWS_EXTERN void
86 lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
87 	     struct lws_context *context);
88 
89 /**
90  * lws_jws_destroy() - scrub a jws
91  *
92  * \param jws: pointer to the jws to destroy
93  *
94  * Call before the jws goes out of scope.
95  *
96  * Elements defined in the jws are zeroed.
97  */
98 LWS_VISIBLE LWS_EXTERN void
99 lws_jws_destroy(struct lws_jws *jws);
100 
101 /**
102  * lws_jws_sig_confirm_compact() - check signature
103  *
104  * \param map: pointers and lengths for each of the unencoded JWS elements
105  * \param jwk: public key
106  * \param context: lws_context
107  * \param temp: scratchpad
108  * \param temp_len: length of scratchpad
109  *
110  * Confirms the signature on a JWS.  Use if you have non-b64 plain JWS elements
111  * in a map... it'll make a temp b64 version needed for comparison.  See below
112  * for other variants.
113  *
114  * Returns 0 on match.
115  */
116 LWS_VISIBLE LWS_EXTERN int
117 lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
118 			    struct lws_context *context,
119 			    char *temp, int *temp_len);
120 
121 LWS_VISIBLE LWS_EXTERN int
122 lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
123 				    struct lws_jwk *jwk,
124 			            struct lws_context *context,
125 			            char *temp, int *temp_len);
126 
127 /**
128  * lws_jws_sig_confirm_compact_b64() - check signature on b64 compact JWS
129  *
130  * \param in: pointer to b64 jose.payload[.hdr].sig
131  * \param len: bytes available at \p in
132  * \param map: map to take decoded non-b64 content
133  * \param jwk: public key
134  * \param context: lws_context
135  * \param temp: scratchpad
136  * \param temp_len: size of scratchpad
137  *
138  * Confirms the signature on a JWS.  Use if you have you have b64 compact layout
139  * (jose.payload.hdr.sig) as an aggregated string... it'll make a temp plain
140  * version needed for comparison.
141  *
142  * Returns 0 on match.
143  */
144 LWS_VISIBLE LWS_EXTERN int
145 lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
146 				struct lws_jws_map *map,
147 				struct lws_jwk *jwk,
148 				struct lws_context *context,
149 				char *temp, int *temp_len);
150 
151 /**
152  * lws_jws_sig_confirm() - check signature on plain + b64 JWS elements
153  *
154  * \param map_b64: pointers and lengths for each of the b64-encoded JWS elements
155  * \param map: pointers and lengths for each of the unencoded JWS elements
156  * \param jwk: public key
157  * \param context: lws_context
158  *
159  * Confirms the signature on a JWS.  Use if you have you already have both b64
160  * compact layout (jose.payload.hdr.sig) and decoded JWS elements in maps.
161  *
162  * If you had the b64 string and called lws_jws_compact_decode() on it, you
163  * will end up with both maps, and can use this api version, saving needlessly
164  * regenerating any temp map.
165  *
166  * Returns 0 on match.
167  */
168 LWS_VISIBLE LWS_EXTERN int
169 lws_jws_sig_confirm(struct lws_jws_map *map_b64, /* b64-encoded */
170 		    struct lws_jws_map *map,	/* non-b64 */
171 		    struct lws_jwk *jwk, struct lws_context *context);
172 
173 /**
174  * lws_jws_sign_from_b64() - add b64 sig to b64 hdr + payload
175  *
176  * \param jose: jose header information
177  * \param jws: information to include in the signature
178  * \param b64_sig: output buffer for b64 signature
179  * \param sig_len: size of \p b64_sig output buffer
180  *
181  * This adds a b64-coded JWS signature of the b64-encoded protected header
182  * and b64-encoded payload, at \p b64_sig.  The signature will be as large
183  * as the N element of the RSA key when the RSA key is used, eg, 512 bytes for
184  * a 4096-bit key, and then b64-encoding on top.
185  *
186  * In some special cases, there is only payload to sign and no header, in that
187  * case \p b64_hdr may be NULL, and only the payload will be hashed before
188  * signing.
189  *
190  * Returns the length of the encoded signature written to \p b64_sig, or -1.
191  */
192 LWS_VISIBLE LWS_EXTERN int
193 lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, char *b64_sig,
194 			size_t sig_len);
195 
196 /**
197  * lws_jws_compact_decode() - converts and maps compact serialization b64 sections
198  *
199  * \param in: the incoming compact serialized b64
200  * \param len: the length of the incoming compact serialized b64
201  * \param map: pointer to the results structure
202  * \param map_b64: NULL, or pointer to a second results structure taking block
203  *		   information about the undecoded b64
204  * \param out: buffer to hold decoded results
205  * \param out_len: size of out in bytes
206  *
207  * Returns number of sections (2 if "none", else 3), or -1 if illegal.
208  *
209  * map is set to point to the start and hold the length of each decoded block.
210  * If map_b64 is non-NULL, then it's set with information about the input b64
211  * blocks.
212  */
213 LWS_VISIBLE LWS_EXTERN int
214 lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
215 		struct lws_jws_map *map_b64, char *out, int *out_len);
216 
217 LWS_VISIBLE LWS_EXTERN int
218 lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
219 		       const struct lws_jws_map *map,	/* non-b64 */
220 		       char *buf, int *out_len);
221 
222 LWS_VISIBLE LWS_EXTERN int
223 lws_jws_sig_confirm_json(const char *in, size_t len,
224 			 struct lws_jws *jws, struct lws_jwk *jwk,
225 			 struct lws_context *context,
226 			 char *temp, int *temp_len);
227 
228 /**
229  * lws_jws_write_flattened_json() - create flattened JSON sig
230  *
231  * \param jws: information to include in the signature
232  * \param flattened: output buffer for JSON
233  * \param len: size of \p flattened output buffer
234  *
235  */
236 LWS_VISIBLE LWS_EXTERN int
237 lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len);
238 
239 /**
240  * lws_jws_write_compact() - create flattened JSON sig
241  *
242  * \param jws: information to include in the signature
243  * \param compact: output buffer for compact format
244  * \param len: size of \p flattened output buffer
245  *
246  */
247 LWS_VISIBLE LWS_EXTERN int
248 lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len);
249 
250 
251 
252 /*
253  * below apis are not normally needed if dealing with whole JWS... they're
254  * useful for creating from scratch
255  */
256 
257 
258 /**
259  * lws_jws_dup_element() - allocate space for an element and copy data into it
260  *
261  * \param map: map to create the element in
262  * \param idx: index of element in the map to create
263  * \param temp: space to allocate in
264  * \param temp_len: available space at temp
265  * \param in: data to duplicate into element
266  * \param in_len: length of data to duplicate
267  * \param actual_alloc: 0 for same as in_len, else actual allocation size
268  *
269  * Copies in_len from in to temp, if temp_len is sufficient.
270  *
271  * Returns 0 or -1 if not enough space in temp / temp_len.
272  *
273  * Over-allocation can be acheived by setting actual_alloc to the real
274  * allocation desired... in_len will be copied into it.
275  *
276  * *temp_len is reduced by actual_alloc if successful.
277  */
278 LWS_VISIBLE LWS_EXTERN int
279 lws_jws_dup_element(struct lws_jws_map *map, int idx,
280 		    char *temp, int *temp_len, const void *in, size_t in_len,
281 		    size_t actual_alloc);
282 
283 /**
284  * lws_jws_randomize_element() - create an element and fill with random
285  *
286  * \param context: lws_context used for random
287  * \param map: map to create the element in
288  * \param idx: index of element in the map to create
289  * \param temp: space to allocate in
290  * \param temp_len: available space at temp
291  * \param random_len: length of data to fill with random
292  * \param actual_alloc: 0 for same as random_len, else actual allocation size
293  *
294  * Randomize random_len bytes at temp, if temp_len is sufficient.
295  *
296  * Returns 0 or -1 if not enough space in temp / temp_len.
297  *
298  * Over-allocation can be acheived by setting actual_alloc to the real
299  * allocation desired... the first random_len will be filled with random.
300  *
301  * *temp_len is reduced by actual_alloc if successful.
302  */
303 LWS_VISIBLE LWS_EXTERN int
304 lws_jws_randomize_element(struct lws_context *context,
305 			  struct lws_jws_map *map,
306 			  int idx, char *temp, int *temp_len, size_t random_len,
307 			  size_t actual_alloc);
308 
309 /**
310  * lws_jws_alloc_element() - create an element and reserve space for content
311  *
312  * \param map: map to create the element in
313  * \param idx: index of element in the map to create
314  * \param temp: space to allocate in
315  * \param temp_len: available space at temp
316  * \param len: logical length of element
317  * \param actual_alloc: 0 for same as len, else actual allocation size
318  *
319  * Allocate len bytes at temp, if temp_len is sufficient.
320  *
321  * Returns 0 or -1 if not enough space in temp / temp_len.
322  *
323  * Over-allocation can be acheived by setting actual_alloc to the real
324  * allocation desired... the element logical length will be set to len.
325  *
326  * *temp_len is reduced by actual_alloc if successful.
327  */
328 LWS_VISIBLE LWS_EXTERN int
329 lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
330 		      int *temp_len, size_t len, size_t actual_alloc);
331 
332 /**
333  * lws_jws_encode_b64_element() - create an b64-encoded element
334  *
335  * \param map: map to create the element in
336  * \param idx: index of element in the map to create
337  * \param temp: space to allocate in
338  * \param temp_len: available space at temp
339  * \param in: pointer to unencoded input
340  * \param in_len: length of unencoded input
341  *
342  * Allocate len bytes at temp, if temp_len is sufficient.
343  *
344  * Returns 0 or -1 if not enough space in temp / temp_len.
345  *
346  * Over-allocation can be acheived by setting actual_alloc to the real
347  * allocation desired... the element logical length will be set to len.
348  *
349  * *temp_len is reduced by actual_alloc if successful.
350  */
351 LWS_VISIBLE LWS_EXTERN int
352 lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
353 			   char *temp, int *temp_len, const void *in,
354 			   size_t in_len);
355 
356 
357 /**
358  * lws_jws_b64_compact_map() - find block starts and lengths in compact b64
359  *
360  * \param in: pointer to b64 jose.payload[.hdr].sig
361  * \param len: bytes available at \p in
362  * \param map: output struct with pointers and lengths for each JWS element
363  *
364  * Scans a jose.payload[.hdr].sig b64 string and notes where the blocks start
365  * and their length into \p map.
366  *
367  * Returns number of blocks if OK.  May return <0 if malformed.
368  * May not fill all map entries.
369  */
370 
371 LWS_VISIBLE LWS_EXTERN int
372 lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map);
373 
374 
375 /**
376  * lws_jws_base64_enc() - encode input data into b64url data
377  *
378  * \param in: the incoming plaintext
379  * \param in_len: the length of the incoming plaintext in bytes
380  * \param out: the buffer to store the b64url encoded data to
381  * \param out_max: the length of \p out in bytes
382  *
383  * Returns either -1 if problems, or the number of bytes written to \p out.
384  */
385 LWS_VISIBLE LWS_EXTERN int
386 lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
387 
388 /**
389  * lws_jws_encode_section() - encode input data into b64url data,
390  *				prepending . if not first
391  *
392  * \param in: the incoming plaintext
393  * \param in_len: the length of the incoming plaintext in bytes
394  * \param first: nonzero if the first section
395  * \param p: the buffer to store the b64url encoded data to
396  * \param end: just past the end of p
397  *
398  * Returns either -1 if problems, or the number of bytes written to \p out.
399  * If the section is not the first one, '.' is prepended.
400  */
401 
402 LWS_VISIBLE LWS_EXTERN int
403 lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
404 		       char *end);
405 ///@}
406