]>
git.ipfire.org Git - thirdparty/openssl.git/blob - ssl/quic/json_enc.c
2 * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include "internal/json_enc.h"
11 #include "internal/nelem.h"
12 #include "internal/numbers.h"
20 static int wbuf_flush(struct json_write_buf
*wbuf
, int full
);
22 static int wbuf_init(struct json_write_buf
*wbuf
, BIO
*bio
, size_t alloc
)
24 wbuf
->buf
= OPENSSL_malloc(alloc
);
25 if (wbuf
->buf
== NULL
)
34 static void wbuf_cleanup(struct json_write_buf
*wbuf
)
36 OPENSSL_free(wbuf
->buf
);
41 static void wbuf_set0_bio(struct json_write_buf
*wbuf
, BIO
*bio
)
46 /* Empty write buffer. */
47 static ossl_inline
void wbuf_clean(struct json_write_buf
*wbuf
)
52 /* Available data remaining in buffer. */
53 static ossl_inline
size_t wbuf_avail(struct json_write_buf
*wbuf
)
55 return wbuf
->alloc
- wbuf
->cur
;
58 /* Add character to write buffer, returning 0 on flush failure. */
59 static ossl_inline
int wbuf_write_char(struct json_write_buf
*wbuf
, char c
)
61 if (wbuf_avail(wbuf
) == 0) {
62 if (!wbuf_flush(wbuf
, /*full=*/0))
66 wbuf
->buf
[wbuf
->cur
++] = c
;
71 * Write zero-terminated string to write buffer, returning 0 on flush failure.
73 static int wbuf_write_str(struct json_write_buf
*wbuf
, const char *s
)
77 while ((c
= *s
++) != 0)
78 if (!wbuf_write_char(wbuf
, c
))
84 /* Flush write buffer, returning 0 on I/O failure. */
85 static int wbuf_flush(struct json_write_buf
*wbuf
, int full
)
87 size_t written
= 0, total_written
= 0;
89 while (total_written
< wbuf
->cur
) {
90 if (!BIO_write_ex(wbuf
->bio
,
91 wbuf
->buf
+ total_written
,
92 wbuf
->cur
- total_written
,
95 wbuf
->buf
+ total_written
,
96 wbuf
->cur
- total_written
);
101 total_written
+= written
;
107 (void)BIO_flush(wbuf
->bio
); /* best effort */
113 * OSSL_JSON_ENC: Stack Management
114 * ===============================
117 static int json_ensure_stack_size(OSSL_JSON_ENC
*json
, size_t num_bytes
)
119 unsigned char *stack
;
121 if (json
->stack_bytes
>= num_bytes
)
124 if (num_bytes
<= OSSL_NELEM(json
->stack_small
)) {
125 stack
= json
->stack_small
;
127 if (json
->stack
== json
->stack_small
)
130 stack
= OPENSSL_realloc(json
->stack
, num_bytes
);
136 json
->stack_bytes
= num_bytes
;
140 /* Push one bit onto the stack. Returns 0 on allocation failure. */
141 static int json_push(OSSL_JSON_ENC
*json
, unsigned int v
)
146 if (json
->stack_end_byte
>= json
->stack_bytes
) {
148 = (json
->stack_bytes
== 0)
149 ? OSSL_NELEM(json
->stack_small
)
150 : (json
->stack_bytes
* 2);
152 if (!json_ensure_stack_size(json
, new_size
))
155 json
->stack_bytes
= new_size
;
159 json
->stack
[json
->stack_end_byte
] |= (v
<< json
->stack_end_bit
);
161 json
->stack
[json
->stack_end_byte
] &= ~(1U << json
->stack_end_bit
);
163 json
->stack_end_bit
= (json
->stack_end_bit
+ 1) % CHAR_BIT
;
164 if (json
->stack_end_bit
== 0)
165 ++json
->stack_end_byte
;
171 * Pop a bit from the stack. Returns 0 if stack is empty. Use json_peek() to get
172 * the value before calling this.
174 static int json_pop(OSSL_JSON_ENC
*json
)
176 if (json
->stack_end_byte
== 0 && json
->stack_end_bit
== 0)
179 if (json
->stack_end_bit
== 0) {
180 --json
->stack_end_byte
;
181 json
->stack_end_bit
= CHAR_BIT
- 1;
183 --json
->stack_end_bit
;
190 * Returns the bit on the top of the stack, or -1 if the stack is empty.
192 static int json_peek(OSSL_JSON_ENC
*json
)
196 obyte
= json
->stack_end_byte
;
197 obit
= json
->stack_end_bit
;
208 return (json
->stack
[obyte
] & (1U << obit
)) != 0;
212 * OSSL_JSON_ENC: Initialisation
213 * =============================
222 static ossl_inline
int in_ijson(const OSSL_JSON_ENC
*json
)
224 return (json
->flags
& OSSL_JSON_FLAG_IJSON
) != 0;
227 static ossl_inline
int in_seq(const OSSL_JSON_ENC
*json
)
229 return (json
->flags
& OSSL_JSON_FLAG_SEQ
) != 0;
232 static ossl_inline
int in_pretty(const OSSL_JSON_ENC
*json
)
234 return (json
->flags
& OSSL_JSON_FLAG_PRETTY
) != 0;
237 int ossl_json_init(OSSL_JSON_ENC
*json
, BIO
*bio
, uint32_t flags
)
239 memset(json
, 0, sizeof(*json
));
242 if (!wbuf_init(&json
->wbuf
, bio
, 4096))
245 json
->state
= STATE_PRE_COMMA
;
249 void ossl_json_cleanup(OSSL_JSON_ENC
*json
)
251 wbuf_cleanup(&json
->wbuf
);
253 if (json
->stack
!= json
->stack_small
)
254 OPENSSL_free(json
->stack
);
259 int ossl_json_flush_cleanup(OSSL_JSON_ENC
*json
)
261 int ok
= ossl_json_flush(json
);
263 ossl_json_cleanup(json
);
267 int ossl_json_reset(OSSL_JSON_ENC
*json
)
269 wbuf_clean(&json
->wbuf
);
270 json
->stack_end_byte
= 0;
271 json
->stack_end_bit
= 0;
276 int ossl_json_flush(OSSL_JSON_ENC
*json
)
278 return wbuf_flush(&json
->wbuf
, /*full=*/1);
281 int ossl_json_set0_sink(OSSL_JSON_ENC
*json
, BIO
*bio
)
283 wbuf_set0_bio(&json
->wbuf
, bio
);
287 int ossl_json_in_error(OSSL_JSON_ENC
*json
)
297 static void json_write_qstring(OSSL_JSON_ENC
*json
, const char *str
);
298 static void json_indent(OSSL_JSON_ENC
*json
);
300 static void json_raise_error(OSSL_JSON_ENC
*json
)
305 static void json_undefer(OSSL_JSON_ENC
*json
)
307 if (!json
->defer_indent
)
313 static void json_write_char(OSSL_JSON_ENC
*json
, char ch
)
315 if (ossl_json_in_error(json
))
319 if (!wbuf_write_char(&json
->wbuf
, ch
))
320 json_raise_error(json
);
323 static void json_write_str(OSSL_JSON_ENC
*json
, const char *s
)
325 if (ossl_json_in_error(json
))
329 if (!wbuf_write_str(&json
->wbuf
, s
))
330 json_raise_error(json
);
333 static void json_indent(OSSL_JSON_ENC
*json
)
337 json
->defer_indent
= 0;
339 if (!in_pretty(json
))
342 json_write_char(json
, '\n');
344 depth
= json
->stack_end_byte
* 8 + json
->stack_end_bit
;
345 for (i
= 0; i
< depth
* 4; ++i
)
346 json_write_str(json
, " ");
349 static int json_pre_item(OSSL_JSON_ENC
*json
)
353 if (ossl_json_in_error(json
))
356 switch (json
->state
) {
357 case STATE_PRE_COMMA
:
361 json_raise_error(json
);
366 json_write_char(json
, ',');
367 if (ossl_json_in_error(json
))
373 if (s
< 0 && in_seq(json
))
374 json_write_char(json
, '\x1E');
376 json
->state
= STATE_PRE_ITEM
;
384 json_raise_error(json
);
391 static void json_post_item(OSSL_JSON_ENC
*json
)
393 int s
= json_peek(json
);
395 json
->state
= STATE_PRE_COMMA
;
397 if (s
< 0 && in_seq(json
))
398 json_write_char(json
, '\n');
402 * Begin a composite structure (object or array).
404 * type: 0=object, 1=array.
406 static void composite_begin(OSSL_JSON_ENC
*json
, int type
, char ch
)
408 if (!json_pre_item(json
)
409 || !json_push(json
, type
))
410 json_raise_error(json
);
412 json_write_char(json
, ch
);
413 json
->defer_indent
= 1;
417 * End a composite structure (object or array).
419 * type: 0=object, 1=array. Errors on mismatch.
421 static void composite_end(OSSL_JSON_ENC
*json
, int type
, char ch
)
423 int was_defer
= json
->defer_indent
;
425 if (ossl_json_in_error(json
))
428 json
->defer_indent
= 0;
430 if (json_peek(json
) != type
) {
431 json_raise_error(json
);
435 if (type
== 0 && json
->state
== STATE_PRE_ITEM
) {
436 json_raise_error(json
);
440 if (!json_pop(json
)) {
441 json_raise_error(json
);
448 json_write_char(json
, ch
);
449 json_post_item(json
);
452 /* Begin a new JSON object. */
453 void ossl_json_object_begin(OSSL_JSON_ENC
*json
)
455 composite_begin(json
, 0, '{');
456 json
->state
= STATE_PRE_KEY
;
459 /* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */
460 void ossl_json_object_end(OSSL_JSON_ENC
*json
)
462 composite_end(json
, 0, '}');
465 /* Begin a new JSON array. */
466 void ossl_json_array_begin(OSSL_JSON_ENC
*json
)
468 composite_begin(json
, 1, '[');
469 json
->state
= STATE_PRE_ITEM
;
472 /* End a JSON array. Must be matched with a call to ossl_json_array_begin(). */
473 void ossl_json_array_end(OSSL_JSON_ENC
*json
)
475 composite_end(json
, 1, ']');
479 * Encode a JSON key within an object. Pass a zero-terminated string, which can
480 * be freed immediately following the call to this function.
482 void ossl_json_key(OSSL_JSON_ENC
*json
, const char *key
)
484 if (ossl_json_in_error(json
))
487 if (json_peek(json
) != 0) {
489 json_raise_error(json
);
493 if (json
->state
== STATE_PRE_COMMA
) {
494 json_write_char(json
, ',');
495 json
->state
= STATE_PRE_KEY
;
499 if (json
->state
!= STATE_PRE_KEY
) {
500 json_raise_error(json
);
504 json_write_qstring(json
, key
);
505 if (ossl_json_in_error(json
))
508 json_write_char(json
, ':');
510 json_write_char(json
, ' ');
512 json
->state
= STATE_PRE_ITEM
;
515 /* Encode a JSON 'null' value. */
516 void ossl_json_null(OSSL_JSON_ENC
*json
)
518 if (!json_pre_item(json
))
521 json_write_str(json
, "null");
522 json_post_item(json
);
525 void ossl_json_bool(OSSL_JSON_ENC
*json
, int v
)
527 if (!json_pre_item(json
))
530 json_write_str(json
, v
> 0 ? "true" : "false");
531 json_post_item(json
);
534 #define POW_53 (((int64_t)1) << 53)
536 /* Encode a JSON integer from a uint64_t. */
537 static void json_u64(OSSL_JSON_ENC
*json
, uint64_t v
, int noquote
)
539 char buf
[22], *p
= buf
+ sizeof(buf
) - 1;
540 int quote
= !noquote
&& in_ijson(json
) && v
> (uint64_t)(POW_53
- 1);
542 if (!json_pre_item(json
))
546 json_write_char(json
, '"');
551 for (*p
= '\0'; v
> 0; v
/= 10)
554 json_write_str(json
, p
);
557 json_write_char(json
, '"');
559 json_post_item(json
);
562 void ossl_json_u64(OSSL_JSON_ENC
*json
, uint64_t v
)
564 json_u64(json
, v
, 0);
567 /* Encode a JSON integer from an int64_t. */
568 void ossl_json_i64(OSSL_JSON_ENC
*json
, int64_t value
)
574 ossl_json_u64(json
, (uint64_t)value
);
578 if (!json_pre_item(json
))
581 quote
= in_ijson(json
)
582 && (value
> POW_53
- 1 || value
< -POW_53
+ 1);
585 json_write_char(json
, '"');
587 json_write_char(json
, '-');
589 uv
= (value
== INT64_MIN
)
590 ? ((uint64_t)-(INT64_MIN
+ 1)) + 1
592 json_u64(json
, uv
, /*noquote=*/1);
594 if (quote
&& !ossl_json_in_error(json
))
595 json_write_char(json
, '"');
598 /* Encode a JSON number from a 64-bit floating point value. */
599 void ossl_json_f64(OSSL_JSON_ENC
*json
, double value
)
603 if (!json_pre_item(json
))
606 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
608 int checks
= isnan(value
);
609 # if !defined(OPENSSL_SYS_VMS)
610 checks
|= isinf(value
);
614 json_raise_error(json
);
620 BIO_snprintf(buf
, sizeof(buf
), "%1.17g", value
);
621 json_write_str(json
, buf
);
622 json_post_item(json
);
626 * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
627 * can be freed immediately following the call to this function.
629 static ossl_inline
int hex_digit(int v
)
631 return v
>= 10 ? 'a' + (v
- 10) : '0' + v
;
634 static ossl_inline
void
635 json_write_qstring_inner(OSSL_JSON_ENC
*json
, const char *str
, size_t str_len
,
639 unsigned char *u_str
;
643 if (ossl_json_in_error(json
))
646 json_write_char(json
, '"');
648 for (j
= nul_term
? strlen(str
) : str_len
; j
> 0; str
++, j
--) {
650 u_str
= (unsigned char*)str
;
652 case '\n': o
= "\\n"; break;
653 case '\r': o
= "\\r"; break;
654 case '\t': o
= "\\t"; break;
655 case '\b': o
= "\\b"; break;
656 case '\f': o
= "\\f"; break;
657 case '"': o
= "\\\""; break;
658 case '\\': o
= "\\\\"; break;
660 /* valid UTF-8 sequences according to RFC-3629 */
661 if (u_str
[0] >= 0xc2 && u_str
[0] <= 0xdf && j
>= 2
662 && u_str
[1] >= 0x80 && u_str
[1] <= 0xbf) {
663 memcpy(obuf
, str
, 2);
669 if (u_str
[0] >= 0xe0 && u_str
[0] <= 0xef && j
>= 3
670 && u_str
[1] >= 0x80 && u_str
[1] <= 0xbf
671 && u_str
[2] >= 0x80 && u_str
[2] <= 0xbf
672 && !(u_str
[0] == 0xe0 && u_str
[1] <= 0x9f)
673 && !(u_str
[0] == 0xed && u_str
[1] >= 0xa0)) {
674 memcpy(obuf
, str
, 3);
681 if (u_str
[0] >= 0xf0 && u_str
[0] <= 0xf4 && j
>= 4
682 && u_str
[1] >= 0x80 && u_str
[1] <= 0xbf
683 && u_str
[2] >= 0x80 && u_str
[2] <= 0xbf
684 && u_str
[3] >= 0x80 && u_str
[3] <= 0xbf
685 && !(u_str
[0] == 0xf0 && u_str
[1] <= 0x8f)
686 && !(u_str
[0] == 0xf4 && u_str
[1] >= 0x90)) {
687 memcpy(obuf
, str
, 4);
694 if (u_str
[0] < 0x20 || u_str
[0] >= 0x7f) {
697 for (i
= 0; i
< 4; ++i
)
698 obuf
[2 + i
] = hex_digit((u_str
[0] >> ((3 - i
) * 4)) & 0x0F);
702 json_write_char(json
, c
);
708 json_write_str(json
, o
);
711 json_write_char(json
, '"');
715 json_write_qstring(OSSL_JSON_ENC
*json
, const char *str
)
717 json_write_qstring_inner(json
, str
, 0, 1);
721 json_write_qstring_len(OSSL_JSON_ENC
*json
, const char *str
, size_t str_len
)
723 json_write_qstring_inner(json
, str
, str_len
, 0);
726 void ossl_json_str(OSSL_JSON_ENC
*json
, const char *str
)
728 if (!json_pre_item(json
))
731 json_write_qstring(json
, str
);
732 json_post_item(json
);
735 void ossl_json_str_len(OSSL_JSON_ENC
*json
, const char *str
, size_t str_len
)
737 if (!json_pre_item(json
))
740 json_write_qstring_len(json
, str
, str_len
);
741 json_post_item(json
);
745 * Encode binary data as a lowercase hex string. data_len is the data length in
748 void ossl_json_str_hex(OSSL_JSON_ENC
*json
, const void *data
, size_t data_len
)
750 const unsigned char *b
= data
, *end
= b
+ data_len
;
753 if (!json_pre_item(json
))
756 json_write_char(json
, '"');
758 for (; b
< end
; ++b
) {
760 json_write_char(json
, hex_digit(c
>> 4));
761 json_write_char(json
, hex_digit(c
& 0x0F));
764 json_write_char(json
, '"');
765 json_post_item(json
);