JSON_ENC: Ensure ossl_json_flush() really flushes the BIO
[openssl.git] / ssl / quic / json_enc.c
1 /*
2  * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/json_enc.h"
11 #include "internal/nelem.h"
12 #include <string.h>
13 #include <math.h>
14
15 /*
16  * wbuf
17  * ====
18  */
19 static int wbuf_flush(struct json_write_buf *wbuf, int full);
20
21 static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)
22 {
23     wbuf->buf = OPENSSL_malloc(alloc);
24     if (wbuf->buf == NULL)
25         return 0;
26
27     wbuf->cur   = 0;
28     wbuf->alloc = alloc;
29     wbuf->bio   = bio;
30     return 1;
31 }
32
33 static void wbuf_cleanup(struct json_write_buf *wbuf)
34 {
35     OPENSSL_free(wbuf->buf);
36     wbuf->buf   = NULL;
37     wbuf->alloc = 0;
38 }
39
40 static void wbuf_set0_bio(struct json_write_buf *wbuf, BIO *bio)
41 {
42     wbuf->bio = bio;
43 }
44
45 /* Empty write buffer. */
46 static ossl_inline void wbuf_clean(struct json_write_buf *wbuf)
47 {
48     wbuf->cur = 0;
49 }
50
51 /* Available data remaining in buffer. */
52 static ossl_inline size_t wbuf_avail(struct json_write_buf *wbuf)
53 {
54     return wbuf->alloc - wbuf->cur;
55 }
56
57 /* Add character to write buffer, returning 0 on flush failure. */
58 static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)
59 {
60     if (wbuf_avail(wbuf) == 0) {
61         if (!wbuf_flush(wbuf, /*full=*/0))
62             return 0;
63     }
64
65     wbuf->buf[wbuf->cur++] = c;
66     return 1;
67 }
68
69 /*
70  * Write zero-terminated string to write buffer, returning 0 on flush failure.
71  */
72 static int wbuf_write_str(struct json_write_buf *wbuf, const char *s)
73 {
74     char c;
75
76     while ((c = *s++) != 0)
77         if (!wbuf_write_char(wbuf, c))
78             return 0;
79
80     return 1;
81 }
82
83 /* Flush write buffer, returning 0 on I/O failure. */
84 static int wbuf_flush(struct json_write_buf *wbuf, int full)
85 {
86     size_t written = 0, total_written = 0;
87
88     while (total_written < wbuf->cur) {
89         if (!BIO_write_ex(wbuf->bio,
90                           wbuf->buf + total_written,
91                           wbuf->cur - total_written,
92                           &written)) {
93             memmove(wbuf->buf,
94                     wbuf->buf + total_written,
95                     wbuf->cur - total_written);
96             wbuf->cur = 0;
97             return 0;
98         }
99
100         total_written += written;
101     }
102
103     wbuf->cur = 0;
104
105     if (full)
106         (void)BIO_flush(wbuf->bio); /* best effort */
107
108     return 1;
109 }
110
111 /*
112  * OSSL_JSON_ENC: Stack Management
113  * ===============================
114  */
115
116 static int json_ensure_stack_size(OSSL_JSON_ENC *json, size_t num_bytes)
117 {
118     unsigned char *stack;
119
120     if (json->stack_bytes >= num_bytes)
121         return 1;
122
123     if (num_bytes <= OSSL_NELEM(json->stack_small)) {
124         stack = json->stack_small;
125     } else {
126         if (json->stack == json->stack_small)
127             json->stack = NULL;
128
129         stack = OPENSSL_realloc(json->stack, num_bytes);
130         if (stack == NULL)
131             return 0;
132     }
133
134     json->stack         = stack;
135     json->stack_bytes   = num_bytes;
136     return 1;
137 }
138
139 /* Push one bit onto the stack. Returns 0 on allocation failure. */
140 static int json_push(OSSL_JSON_ENC *json, unsigned int v)
141 {
142     if (v > 1)
143         return 0;
144
145     if (json->stack_end_byte >= json->stack_bytes) {
146         size_t new_size
147             = (json->stack_bytes == 0)
148             ? OSSL_NELEM(json->stack_small)
149             : (json->stack_bytes * 2);
150
151         if (!json_ensure_stack_size(json, new_size))
152             return 0;
153
154         json->stack_bytes = new_size;
155     }
156
157     if (v > 0)
158         json->stack[json->stack_end_byte] |= (v << json->stack_end_bit);
159     else
160         json->stack[json->stack_end_byte] &= ~(1U << json->stack_end_bit);
161
162     json->stack_end_bit = (json->stack_end_bit + 1) % CHAR_BIT;
163     if (json->stack_end_bit == 0)
164         ++json->stack_end_byte;
165
166     return 1;
167 }
168
169 /*
170  * Pop a bit from the stack. Returns 0 if stack is empty. Use json_peek() to get
171  * the value before calling this.
172  */
173 static int json_pop(OSSL_JSON_ENC *json)
174 {
175     if (json->stack_end_byte == 0 && json->stack_end_bit == 0)
176         return 0;
177
178     if (json->stack_end_bit == 0) {
179         --json->stack_end_byte;
180         json->stack_end_bit = CHAR_BIT - 1;
181     } else {
182         --json->stack_end_bit;
183     }
184
185     return 1;
186 }
187
188 /*
189  * Returns the bit on the top of the stack, or -1 if the stack is empty.
190  */
191 static int json_peek(OSSL_JSON_ENC *json)
192 {
193     size_t obyte, obit;
194
195     obyte = json->stack_end_byte;
196     obit  = json->stack_end_bit;
197     if (obit == 0) {
198        if (obyte == 0)
199            return -1;
200
201         --obyte;
202         obit = CHAR_BIT - 1;
203     } else {
204         --obit;
205     }
206
207     return (json->stack[obyte] & (1U << obit)) != 0;
208 }
209
210 /*
211  * OSSL_JSON_ENC: Initialisation
212  * =============================
213  */
214
215 enum {
216     STATE_PRE_KEY,
217     STATE_PRE_ITEM,
218     STATE_PRE_COMMA
219 };
220
221 static ossl_inline int in_ijson(const OSSL_JSON_ENC *json)
222 {
223     return (json->flags & OSSL_JSON_FLAG_IJSON) != 0;
224 }
225
226 static ossl_inline int in_seq(const OSSL_JSON_ENC *json)
227 {
228     return (json->flags & OSSL_JSON_FLAG_SEQ) != 0;
229 }
230
231 static ossl_inline int in_pretty(const OSSL_JSON_ENC *json)
232 {
233     return (json->flags & OSSL_JSON_FLAG_PRETTY) != 0;
234 }
235
236 int ossl_json_init(OSSL_JSON_ENC *json, BIO *bio, uint32_t flags)
237 {
238     memset(json, 0, sizeof(*json));
239     json->flags     = flags;
240     json->error     = 0;
241     if (!wbuf_init(&json->wbuf, bio, 4096))
242         return 0;
243
244     json->state = STATE_PRE_COMMA;
245     return 1;
246 }
247
248 void ossl_json_cleanup(OSSL_JSON_ENC *json)
249 {
250     wbuf_cleanup(&json->wbuf);
251
252     if (json->stack != json->stack_small)
253         OPENSSL_free(json->stack);
254
255     json->stack = NULL;
256 }
257
258 int ossl_json_flush_cleanup(OSSL_JSON_ENC *json)
259 {
260     int ok = ossl_json_flush(json);
261
262     ossl_json_cleanup(json);
263     return ok;
264 }
265
266 int ossl_json_reset(OSSL_JSON_ENC *json)
267 {
268     wbuf_clean(&json->wbuf);
269     json->stack_end_byte    = 0;
270     json->stack_end_bit     = 0;
271     json->error             = 0;
272     return 1;
273 }
274
275 int ossl_json_flush(OSSL_JSON_ENC *json)
276 {
277     return wbuf_flush(&json->wbuf, /*full=*/1);
278 }
279
280 int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)
281 {
282     wbuf_set0_bio(&json->wbuf, bio);
283     return 1;
284 }
285
286 int ossl_json_in_error(OSSL_JSON_ENC *json)
287 {
288     return json->error;
289 }
290
291 /*
292  * JSON Builder Calls
293  * ==================
294  */
295
296 static void json_write_qstring(OSSL_JSON_ENC *json, const char *str);
297 static void json_indent(OSSL_JSON_ENC *json);
298
299 static void json_raise_error(OSSL_JSON_ENC *json)
300 {
301     json->error = 1;
302 }
303
304 static void json_undefer(OSSL_JSON_ENC *json)
305 {
306     if (!json->defer_indent)
307         return;
308
309     json_indent(json);
310 }
311
312 static void json_write_char(OSSL_JSON_ENC *json, char ch)
313 {
314     if (ossl_json_in_error(json))
315         return;
316
317     json_undefer(json);
318     if (!wbuf_write_char(&json->wbuf, ch))
319         json_raise_error(json);
320 }
321
322 static void json_write_str(OSSL_JSON_ENC *json, const char *s)
323 {
324     if (ossl_json_in_error(json))
325         return;
326
327     json_undefer(json);
328     if (!wbuf_write_str(&json->wbuf, s))
329         json_raise_error(json);
330 }
331
332 static void json_indent(OSSL_JSON_ENC *json)
333 {
334     size_t i, depth;
335
336     json->defer_indent = 0;
337
338     if (!in_pretty(json))
339         return;
340
341     json_write_char(json, '\n');
342
343     depth = json->stack_end_byte * 8 + json->stack_end_bit;
344     for (i = 0; i < depth * 4; ++i)
345         json_write_str(json, "    ");
346 }
347
348 static int json_pre_item(OSSL_JSON_ENC *json)
349 {
350     int s;
351
352     if (ossl_json_in_error(json))
353         return 0;
354
355     switch (json->state) {
356     case STATE_PRE_COMMA:
357         s = json_peek(json);
358
359         if (s == 0) {
360             json_raise_error(json);
361             return 0;
362         }
363
364         if (s == 1) {
365             json_write_char(json, ',');
366             if (ossl_json_in_error(json))
367                 return 0;
368
369             json_indent(json);
370         }
371
372         if (s < 0 && in_seq(json))
373             json_write_char(json, '\x1E');
374
375         json->state = STATE_PRE_ITEM;
376         break;
377
378     case STATE_PRE_ITEM:
379         break;
380
381     case STATE_PRE_KEY:
382     default:
383         json_raise_error(json);
384         return 0;
385     }
386
387     return 1;
388 }
389
390 static void json_post_item(OSSL_JSON_ENC *json)
391 {
392     int s = json_peek(json);
393
394     json->state = STATE_PRE_COMMA;
395
396     if (s < 0 && in_seq(json))
397         json_write_char(json, '\n');
398 }
399
400 /*
401  * Begin a composite structure (object or array).
402  *
403  * type: 0=object, 1=array.
404  */
405 static void composite_begin(OSSL_JSON_ENC *json, int type, char ch)
406 {
407     if (!json_pre_item(json)
408         || !json_push(json, type))
409         json_raise_error(json);
410
411     json_write_char(json, ch);
412     json->defer_indent = 1;
413 }
414
415 /*
416  * End a composite structure (object or array).
417  *
418  * type: 0=object, 1=array. Errors on mismatch.
419  */
420 static void composite_end(OSSL_JSON_ENC *json, int type, char ch)
421 {
422     int was_defer = json->defer_indent;
423
424     if (ossl_json_in_error(json))
425         return;
426
427     json->defer_indent = 0;
428
429     if (json_peek(json) != type) {
430         json_raise_error(json);
431         return;
432     }
433
434     if (type == 0 && json->state == STATE_PRE_ITEM) {
435         json_raise_error(json);
436         return;
437     }
438
439     if (!json_pop(json)) {
440         json_raise_error(json);
441         return;
442     }
443
444     if (!was_defer)
445         json_indent(json);
446
447     json_write_char(json, ch);
448     json_post_item(json);
449 }
450
451 /* Begin a new JSON object. */
452 void ossl_json_object_begin(OSSL_JSON_ENC *json)
453 {
454     composite_begin(json, 0, '{');
455     json->state = STATE_PRE_KEY;
456 }
457
458 /* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */
459 void ossl_json_object_end(OSSL_JSON_ENC *json)
460 {
461     composite_end(json, 0, '}');
462 }
463
464 /* Begin a new JSON array. */
465 void ossl_json_array_begin(OSSL_JSON_ENC *json)
466 {
467     composite_begin(json, 1, '[');
468     json->state = STATE_PRE_ITEM;
469 }
470
471 /* End a JSON array. Must be matched with a call to ossl_json_array_begin(). */
472 void ossl_json_array_end(OSSL_JSON_ENC *json)
473 {
474     composite_end(json, 1, ']');
475 }
476
477 /*
478  * Encode a JSON key within an object. Pass a zero-terminated string, which can
479  * be freed immediately following the call to this function.
480  */
481 void ossl_json_key(OSSL_JSON_ENC *json, const char *key)
482 {
483     if (ossl_json_in_error(json))
484         return;
485
486     if (json_peek(json) != 0) {
487         /* Not in object */
488         json_raise_error(json);
489         return;
490     }
491
492     if (json->state == STATE_PRE_COMMA) {
493         json_write_char(json, ',');
494         json->state = STATE_PRE_KEY;
495     }
496
497     json_indent(json);
498     if (json->state != STATE_PRE_KEY) {
499         json_raise_error(json);
500         return;
501     }
502
503     json_write_qstring(json, key);
504     if (ossl_json_in_error(json))
505         return;
506
507     json_write_char(json, ':');
508     if (in_pretty(json))
509         json_write_char(json, ' ');
510
511     json->state = STATE_PRE_ITEM;
512 }
513
514 /* Encode a JSON 'null' value. */
515 void ossl_json_null(OSSL_JSON_ENC *json)
516 {
517     if (!json_pre_item(json))
518         return;
519
520     json_write_str(json, "null");
521     json_post_item(json);
522 }
523
524 void ossl_json_bool(OSSL_JSON_ENC *json, int v)
525 {
526     if (!json_pre_item(json))
527         return;
528
529     json_write_str(json, v > 0 ? "true" : "false");
530     json_post_item(json);
531 }
532
533 #define POW_53 (((int64_t)1) << 53)
534
535 /* Encode a JSON integer from a uint64_t. */
536 static void json_u64(OSSL_JSON_ENC *json, uint64_t v, int noquote)
537 {
538     char buf[22], *p = buf + sizeof(buf) - 1;
539     int quote = !noquote && in_ijson(json) && v > (uint64_t)(POW_53 - 1);
540
541     if (!json_pre_item(json))
542         return;
543
544     if (quote)
545         json_write_char(json, '"');
546
547     if (v == 0)
548         p = "0";
549     else
550         for (*p = '\0'; v > 0; v /= 10)
551             *--p = '0' + v % 10;
552
553     json_write_str(json, p);
554
555     if (quote)
556         json_write_char(json, '"');
557
558     json_post_item(json);
559 }
560
561 void ossl_json_u64(OSSL_JSON_ENC *json, uint64_t v)
562 {
563     json_u64(json, v, 0);
564 }
565
566 /* Encode a JSON integer from an int64_t. */
567 void ossl_json_i64(OSSL_JSON_ENC *json, int64_t value)
568 {
569     uint64_t uv;
570     int quote;
571
572     if (value >= 0) {
573         ossl_json_u64(json, (uint64_t)value);
574         return;
575     }
576
577     if (!json_pre_item(json))
578         return;
579
580     quote = in_ijson(json)
581         && (value > POW_53 - 1 || value < -POW_53 + 1);
582
583     if (quote)
584         json_write_char(json, '"');
585
586     json_write_char(json, '-');
587
588     uv = (value == INT64_MIN)
589         ? ((uint64_t)-(INT64_MIN + 1)) + 1
590         : (uint64_t)-value;
591     json_u64(json, uv, /*noquote=*/1);
592
593     if (quote && !ossl_json_in_error(json))
594         json_write_char(json, '"');
595 }
596
597 /* Encode a JSON number from a 64-bit floating point value. */
598 void ossl_json_f64(OSSL_JSON_ENC *json, double value)
599 {
600     char buf[32];
601
602     if (!json_pre_item(json))
603         return;
604
605     if (isnan(value) || isinf(value)) {
606         json_raise_error(json);
607         return;
608     }
609
610     BIO_snprintf(buf, sizeof(buf), "%1.17g", value);
611     json_write_str(json, buf);
612     json_post_item(json);
613 }
614
615 /*
616  * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
617  * can be freed immediately following the call to this function.
618  */
619 static ossl_inline int hex_digit(int v)
620 {
621     return v >= 10 ? 'a' + (v - 10) : '0' + v;
622 }
623
624 static ossl_inline void
625 json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
626                          int nul_term)
627 {
628     char c, *o, obuf[7];
629     int i;
630     size_t j;
631
632     if (ossl_json_in_error(json))
633         return;
634
635     json_write_char(json, '"');
636
637     for (j = 0; (nul_term && *str != '\0')
638                 || (!nul_term && j < str_len); ++str, ++j) {
639         c = *str;
640         switch (c) {
641         case '\n': o = "\\n"; break;
642         case '\r': o = "\\r"; break;
643         case '\t': o = "\\t"; break;
644         case '\b': o = "\\b"; break;
645         case '\f': o = "\\f"; break;
646         case '"': o = "\\\""; break;
647         case '\\': o = "\\\\"; break;
648         default:
649             if ((unsigned char)c >= 0x80) {
650                 json_raise_error(json);
651                 return;
652             }
653             if ((unsigned char)c < 0x20 || (unsigned char)c >= 0x7f) {
654                 obuf[0] = '\\';
655                 obuf[1] = 'u';
656                 for (i = 0; i < 4; ++i)
657                     obuf[2 + i] = hex_digit((c >> ((3 - i) * 4)) & 0x0F);
658                 obuf[6] = '\0';
659                 o = obuf;
660             } else {
661                 json_write_char(json, c);
662                 continue;
663             }
664             break;
665         }
666
667         json_write_str(json, o);
668     }
669
670     json_write_char(json, '"');
671 }
672
673 static void
674 json_write_qstring(OSSL_JSON_ENC *json, const char *str)
675 {
676     json_write_qstring_inner(json, str, 0, 1);
677 }
678
679 static void
680 json_write_qstring_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
681 {
682     json_write_qstring_inner(json, str, str_len, 0);
683 }
684
685 void ossl_json_str(OSSL_JSON_ENC *json, const char *str)
686 {
687     if (!json_pre_item(json))
688         return;
689
690     json_write_qstring(json, str);
691     json_post_item(json);
692 }
693
694 void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
695 {
696     if (!json_pre_item(json))
697         return;
698
699     json_write_qstring_len(json, str, str_len);
700     json_post_item(json);
701 }
702
703 /*
704  * Encode binary data as a lowercase hex string. data_len is the data length in
705  * bytes.
706  */
707 void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len)
708 {
709     const unsigned char *b = data, *end = b + data_len;
710     unsigned char c;
711
712     if (!json_pre_item(json))
713         return;
714
715     json_write_char(json, '"');
716
717     for (; b < end; ++b) {
718         c = *b;
719         json_write_char(json, hex_digit(c >> 4));
720         json_write_char(json, hex_digit(c & 0x0F));
721     }
722
723     json_write_char(json, '"');
724     json_post_item(json);
725 }