Path: blob/main/crypto/openssl/ssl/quic/json_enc.c
48266 views
/*1* Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include "internal/json_enc.h"10#include "internal/nelem.h"11#include "internal/numbers.h"12#include <string.h>1314/*15* wbuf16* ====17*/18static int wbuf_flush(struct json_write_buf *wbuf, int full);1920static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)21{22wbuf->buf = OPENSSL_malloc(alloc);23if (wbuf->buf == NULL)24return 0;2526wbuf->cur = 0;27wbuf->alloc = alloc;28wbuf->bio = bio;29return 1;30}3132static void wbuf_cleanup(struct json_write_buf *wbuf)33{34OPENSSL_free(wbuf->buf);35wbuf->buf = NULL;36wbuf->alloc = 0;37}3839static void wbuf_set0_bio(struct json_write_buf *wbuf, BIO *bio)40{41wbuf->bio = bio;42}4344/* Empty write buffer. */45static ossl_inline void wbuf_clean(struct json_write_buf *wbuf)46{47wbuf->cur = 0;48}4950/* Available data remaining in buffer. */51static ossl_inline size_t wbuf_avail(struct json_write_buf *wbuf)52{53return wbuf->alloc - wbuf->cur;54}5556/* Add character to write buffer, returning 0 on flush failure. */57static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)58{59if (wbuf_avail(wbuf) == 0) {60if (!wbuf_flush(wbuf, /*full=*/0))61return 0;62}6364wbuf->buf[wbuf->cur++] = c;65return 1;66}6768/*69* Write zero-terminated string to write buffer, returning 0 on flush failure.70*/71static int wbuf_write_str(struct json_write_buf *wbuf, const char *s)72{73char c;7475while ((c = *s++) != 0)76if (!wbuf_write_char(wbuf, c))77return 0;7879return 1;80}8182/* Flush write buffer, returning 0 on I/O failure. */83static int wbuf_flush(struct json_write_buf *wbuf, int full)84{85size_t written = 0, total_written = 0;8687while (total_written < wbuf->cur) {88if (!BIO_write_ex(wbuf->bio,89wbuf->buf + total_written,90wbuf->cur - total_written,91&written)) {92memmove(wbuf->buf,93wbuf->buf + total_written,94wbuf->cur - total_written);95wbuf->cur = 0;96return 0;97}9899total_written += written;100}101102wbuf->cur = 0;103104if (full)105(void)BIO_flush(wbuf->bio); /* best effort */106107return 1;108}109110/*111* OSSL_JSON_ENC: Stack Management112* ===============================113*/114115static int json_ensure_stack_size(OSSL_JSON_ENC *json, size_t num_bytes)116{117unsigned char *stack;118119if (json->stack_bytes >= num_bytes)120return 1;121122if (num_bytes <= OSSL_NELEM(json->stack_small)) {123stack = json->stack_small;124} else {125if (json->stack == json->stack_small)126json->stack = NULL;127128stack = OPENSSL_realloc(json->stack, num_bytes);129if (stack == NULL)130return 0;131}132133json->stack = stack;134json->stack_bytes = num_bytes;135return 1;136}137138/* Push one bit onto the stack. Returns 0 on allocation failure. */139static int json_push(OSSL_JSON_ENC *json, unsigned int v)140{141if (v > 1)142return 0;143144if (json->stack_end_byte >= json->stack_bytes) {145size_t new_size146= (json->stack_bytes == 0)147? OSSL_NELEM(json->stack_small)148: (json->stack_bytes * 2);149150if (!json_ensure_stack_size(json, new_size))151return 0;152153json->stack_bytes = new_size;154}155156if (v > 0)157json->stack[json->stack_end_byte] |= (v << json->stack_end_bit);158else159json->stack[json->stack_end_byte] &= ~(1U << json->stack_end_bit);160161json->stack_end_bit = (json->stack_end_bit + 1) % CHAR_BIT;162if (json->stack_end_bit == 0)163++json->stack_end_byte;164165return 1;166}167168/*169* Pop a bit from the stack. Returns 0 if stack is empty. Use json_peek() to get170* the value before calling this.171*/172static int json_pop(OSSL_JSON_ENC *json)173{174if (json->stack_end_byte == 0 && json->stack_end_bit == 0)175return 0;176177if (json->stack_end_bit == 0) {178--json->stack_end_byte;179json->stack_end_bit = CHAR_BIT - 1;180} else {181--json->stack_end_bit;182}183184return 1;185}186187/*188* Returns the bit on the top of the stack, or -1 if the stack is empty.189*/190static int json_peek(OSSL_JSON_ENC *json)191{192size_t obyte, obit;193194obyte = json->stack_end_byte;195obit = json->stack_end_bit;196if (obit == 0) {197if (obyte == 0)198return -1;199200--obyte;201obit = CHAR_BIT - 1;202} else {203--obit;204}205206return (json->stack[obyte] & (1U << obit)) != 0;207}208209/*210* OSSL_JSON_ENC: Initialisation211* =============================212*/213214enum {215STATE_PRE_KEY,216STATE_PRE_ITEM,217STATE_PRE_COMMA218};219220static ossl_inline int in_ijson(const OSSL_JSON_ENC *json)221{222return (json->flags & OSSL_JSON_FLAG_IJSON) != 0;223}224225static ossl_inline int in_seq(const OSSL_JSON_ENC *json)226{227return (json->flags & OSSL_JSON_FLAG_SEQ) != 0;228}229230static ossl_inline int in_pretty(const OSSL_JSON_ENC *json)231{232return (json->flags & OSSL_JSON_FLAG_PRETTY) != 0;233}234235int ossl_json_init(OSSL_JSON_ENC *json, BIO *bio, uint32_t flags)236{237memset(json, 0, sizeof(*json));238json->flags = flags;239json->error = 0;240if (!wbuf_init(&json->wbuf, bio, 4096))241return 0;242243json->state = STATE_PRE_COMMA;244return 1;245}246247void ossl_json_cleanup(OSSL_JSON_ENC *json)248{249wbuf_cleanup(&json->wbuf);250251if (json->stack != json->stack_small)252OPENSSL_free(json->stack);253254json->stack = NULL;255}256257int ossl_json_flush_cleanup(OSSL_JSON_ENC *json)258{259int ok = ossl_json_flush(json);260261ossl_json_cleanup(json);262return ok;263}264265int ossl_json_reset(OSSL_JSON_ENC *json)266{267wbuf_clean(&json->wbuf);268json->stack_end_byte = 0;269json->stack_end_bit = 0;270json->error = 0;271return 1;272}273274int ossl_json_flush(OSSL_JSON_ENC *json)275{276return wbuf_flush(&json->wbuf, /*full=*/1);277}278279int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)280{281wbuf_set0_bio(&json->wbuf, bio);282return 1;283}284285int ossl_json_in_error(OSSL_JSON_ENC *json)286{287return json->error;288}289290/*291* JSON Builder Calls292* ==================293*/294295static void json_write_qstring(OSSL_JSON_ENC *json, const char *str);296static void json_indent(OSSL_JSON_ENC *json);297298static void json_raise_error(OSSL_JSON_ENC *json)299{300json->error = 1;301}302303static void json_undefer(OSSL_JSON_ENC *json)304{305if (!json->defer_indent)306return;307308json_indent(json);309}310311static void json_write_char(OSSL_JSON_ENC *json, char ch)312{313if (ossl_json_in_error(json))314return;315316json_undefer(json);317if (!wbuf_write_char(&json->wbuf, ch))318json_raise_error(json);319}320321static void json_write_str(OSSL_JSON_ENC *json, const char *s)322{323if (ossl_json_in_error(json))324return;325326json_undefer(json);327if (!wbuf_write_str(&json->wbuf, s))328json_raise_error(json);329}330331static void json_indent(OSSL_JSON_ENC *json)332{333size_t i, depth;334335json->defer_indent = 0;336337if (!in_pretty(json))338return;339340json_write_char(json, '\n');341342depth = json->stack_end_byte * 8 + json->stack_end_bit;343for (i = 0; i < depth * 4; ++i)344json_write_str(json, " ");345}346347static int json_pre_item(OSSL_JSON_ENC *json)348{349int s;350351if (ossl_json_in_error(json))352return 0;353354switch (json->state) {355case STATE_PRE_COMMA:356s = json_peek(json);357358if (s == 0) {359json_raise_error(json);360return 0;361}362363if (s == 1) {364json_write_char(json, ',');365if (ossl_json_in_error(json))366return 0;367368json_indent(json);369}370371if (s < 0 && in_seq(json))372json_write_char(json, '\x1E');373374json->state = STATE_PRE_ITEM;375break;376377case STATE_PRE_ITEM:378break;379380case STATE_PRE_KEY:381default:382json_raise_error(json);383return 0;384}385386return 1;387}388389static void json_post_item(OSSL_JSON_ENC *json)390{391int s = json_peek(json);392393json->state = STATE_PRE_COMMA;394395if (s < 0 && in_seq(json))396json_write_char(json, '\n');397}398399/*400* Begin a composite structure (object or array).401*402* type: 0=object, 1=array.403*/404static void composite_begin(OSSL_JSON_ENC *json, int type, char ch)405{406if (!json_pre_item(json)407|| !json_push(json, type))408json_raise_error(json);409410json_write_char(json, ch);411json->defer_indent = 1;412}413414/*415* End a composite structure (object or array).416*417* type: 0=object, 1=array. Errors on mismatch.418*/419static void composite_end(OSSL_JSON_ENC *json, int type, char ch)420{421int was_defer = json->defer_indent;422423if (ossl_json_in_error(json))424return;425426json->defer_indent = 0;427428if (json_peek(json) != type) {429json_raise_error(json);430return;431}432433if (type == 0 && json->state == STATE_PRE_ITEM) {434json_raise_error(json);435return;436}437438if (!json_pop(json)) {439json_raise_error(json);440return;441}442443if (!was_defer)444json_indent(json);445446json_write_char(json, ch);447json_post_item(json);448}449450/* Begin a new JSON object. */451void ossl_json_object_begin(OSSL_JSON_ENC *json)452{453composite_begin(json, 0, '{');454json->state = STATE_PRE_KEY;455}456457/* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */458void ossl_json_object_end(OSSL_JSON_ENC *json)459{460composite_end(json, 0, '}');461}462463/* Begin a new JSON array. */464void ossl_json_array_begin(OSSL_JSON_ENC *json)465{466composite_begin(json, 1, '[');467json->state = STATE_PRE_ITEM;468}469470/* End a JSON array. Must be matched with a call to ossl_json_array_begin(). */471void ossl_json_array_end(OSSL_JSON_ENC *json)472{473composite_end(json, 1, ']');474}475476/*477* Encode a JSON key within an object. Pass a zero-terminated string, which can478* be freed immediately following the call to this function.479*/480void ossl_json_key(OSSL_JSON_ENC *json, const char *key)481{482if (ossl_json_in_error(json))483return;484485if (json_peek(json) != 0) {486/* Not in object */487json_raise_error(json);488return;489}490491if (json->state == STATE_PRE_COMMA) {492json_write_char(json, ',');493json->state = STATE_PRE_KEY;494}495496json_indent(json);497if (json->state != STATE_PRE_KEY) {498json_raise_error(json);499return;500}501502json_write_qstring(json, key);503if (ossl_json_in_error(json))504return;505506json_write_char(json, ':');507if (in_pretty(json))508json_write_char(json, ' ');509510json->state = STATE_PRE_ITEM;511}512513/* Encode a JSON 'null' value. */514void ossl_json_null(OSSL_JSON_ENC *json)515{516if (!json_pre_item(json))517return;518519json_write_str(json, "null");520json_post_item(json);521}522523void ossl_json_bool(OSSL_JSON_ENC *json, int v)524{525if (!json_pre_item(json))526return;527528json_write_str(json, v > 0 ? "true" : "false");529json_post_item(json);530}531532#define POW_53 (((int64_t)1) << 53)533534/* Encode a JSON integer from a uint64_t. */535static void json_u64(OSSL_JSON_ENC *json, uint64_t v, int noquote)536{537char buf[22], *p = buf + sizeof(buf) - 1;538int quote = !noquote && in_ijson(json) && v > (uint64_t)(POW_53 - 1);539540if (!json_pre_item(json))541return;542543if (quote)544json_write_char(json, '"');545546if (v == 0)547p = "0";548else549for (*p = '\0'; v > 0; v /= 10)550*--p = '0' + v % 10;551552json_write_str(json, p);553554if (quote)555json_write_char(json, '"');556557json_post_item(json);558}559560void ossl_json_u64(OSSL_JSON_ENC *json, uint64_t v)561{562json_u64(json, v, 0);563}564565/* Encode a JSON integer from an int64_t. */566void ossl_json_i64(OSSL_JSON_ENC *json, int64_t value)567{568uint64_t uv;569int quote;570571if (value >= 0) {572ossl_json_u64(json, (uint64_t)value);573return;574}575576if (!json_pre_item(json))577return;578579quote = in_ijson(json)580&& (value > POW_53 - 1 || value < -POW_53 + 1);581582if (quote)583json_write_char(json, '"');584585json_write_char(json, '-');586587uv = (value == INT64_MIN)588? ((uint64_t)-(INT64_MIN + 1)) + 1589: (uint64_t)-value;590json_u64(json, uv, /*noquote=*/1);591592if (quote && !ossl_json_in_error(json))593json_write_char(json, '"');594}595596/*597* Encode a JSON UTF-8 string from a zero-terminated string. The string passed598* can be freed immediately following the call to this function.599*/600static ossl_inline int hex_digit(int v)601{602return v >= 10 ? 'a' + (v - 10) : '0' + v;603}604605static ossl_inline void606json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,607int nul_term)608{609char c, *o, obuf[7];610unsigned char *u_str;611int i;612size_t j;613614if (ossl_json_in_error(json))615return;616617json_write_char(json, '"');618619for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {620c = *str;621u_str = (unsigned char*)str;622switch (c) {623case '\n': o = "\\n"; break;624case '\r': o = "\\r"; break;625case '\t': o = "\\t"; break;626case '\b': o = "\\b"; break;627case '\f': o = "\\f"; break;628case '"': o = "\\\""; break;629case '\\': o = "\\\\"; break;630default:631/* valid UTF-8 sequences according to RFC-3629 */632if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2633&& u_str[1] >= 0x80 && u_str[1] <= 0xbf) {634memcpy(obuf, str, 2);635obuf[2] = '\0';636str++, j--;637o = obuf;638break;639}640if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3641&& u_str[1] >= 0x80 && u_str[1] <= 0xbf642&& u_str[2] >= 0x80 && u_str[2] <= 0xbf643&& !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)644&& !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {645memcpy(obuf, str, 3);646obuf[3] = '\0';647str += 2;648j -= 2;649o = obuf;650break;651}652if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4653&& u_str[1] >= 0x80 && u_str[1] <= 0xbf654&& u_str[2] >= 0x80 && u_str[2] <= 0xbf655&& u_str[3] >= 0x80 && u_str[3] <= 0xbf656&& !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)657&& !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {658memcpy(obuf, str, 4);659obuf[4] = '\0';660str += 3;661j -= 3;662o = obuf;663break;664}665if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {666obuf[0] = '\\';667obuf[1] = 'u';668for (i = 0; i < 4; ++i)669obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);670obuf[6] = '\0';671o = obuf;672} else {673json_write_char(json, c);674continue;675}676break;677}678679json_write_str(json, o);680}681682json_write_char(json, '"');683}684685static void686json_write_qstring(OSSL_JSON_ENC *json, const char *str)687{688json_write_qstring_inner(json, str, 0, 1);689}690691static void692json_write_qstring_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)693{694json_write_qstring_inner(json, str, str_len, 0);695}696697void ossl_json_str(OSSL_JSON_ENC *json, const char *str)698{699if (!json_pre_item(json))700return;701702json_write_qstring(json, str);703json_post_item(json);704}705706void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)707{708if (!json_pre_item(json))709return;710711json_write_qstring_len(json, str, str_len);712json_post_item(json);713}714715/*716* Encode binary data as a lowercase hex string. data_len is the data length in717* bytes.718*/719void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len)720{721const unsigned char *b = data, *end = b + data_len;722unsigned char c;723724if (!json_pre_item(json))725return;726727json_write_char(json, '"');728729for (; b < end; ++b) {730c = *b;731json_write_char(json, hex_digit(c >> 4));732json_write_char(json, hex_digit(c & 0x0F));733}734735json_write_char(json, '"');736json_post_item(json);737}738739740