123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- /*
- * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
- #include "internal/json_enc.h"
- #include "internal/nelem.h"
- #include "internal/numbers.h"
- #include <string.h>
- #include <math.h>
- /*
- * wbuf
- * ====
- */
- static int wbuf_flush(struct json_write_buf *wbuf, int full);
- static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)
- {
- wbuf->buf = OPENSSL_malloc(alloc);
- if (wbuf->buf == NULL)
- return 0;
- wbuf->cur = 0;
- wbuf->alloc = alloc;
- wbuf->bio = bio;
- return 1;
- }
- static void wbuf_cleanup(struct json_write_buf *wbuf)
- {
- OPENSSL_free(wbuf->buf);
- wbuf->buf = NULL;
- wbuf->alloc = 0;
- }
- static void wbuf_set0_bio(struct json_write_buf *wbuf, BIO *bio)
- {
- wbuf->bio = bio;
- }
- /* Empty write buffer. */
- static ossl_inline void wbuf_clean(struct json_write_buf *wbuf)
- {
- wbuf->cur = 0;
- }
- /* Available data remaining in buffer. */
- static ossl_inline size_t wbuf_avail(struct json_write_buf *wbuf)
- {
- return wbuf->alloc - wbuf->cur;
- }
- /* Add character to write buffer, returning 0 on flush failure. */
- static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)
- {
- if (wbuf_avail(wbuf) == 0) {
- if (!wbuf_flush(wbuf, /*full=*/0))
- return 0;
- }
- wbuf->buf[wbuf->cur++] = c;
- return 1;
- }
- /*
- * Write zero-terminated string to write buffer, returning 0 on flush failure.
- */
- static int wbuf_write_str(struct json_write_buf *wbuf, const char *s)
- {
- char c;
- while ((c = *s++) != 0)
- if (!wbuf_write_char(wbuf, c))
- return 0;
- return 1;
- }
- /* Flush write buffer, returning 0 on I/O failure. */
- static int wbuf_flush(struct json_write_buf *wbuf, int full)
- {
- size_t written = 0, total_written = 0;
- while (total_written < wbuf->cur) {
- if (!BIO_write_ex(wbuf->bio,
- wbuf->buf + total_written,
- wbuf->cur - total_written,
- &written)) {
- memmove(wbuf->buf,
- wbuf->buf + total_written,
- wbuf->cur - total_written);
- wbuf->cur = 0;
- return 0;
- }
- total_written += written;
- }
- wbuf->cur = 0;
- if (full)
- (void)BIO_flush(wbuf->bio); /* best effort */
- return 1;
- }
- /*
- * OSSL_JSON_ENC: Stack Management
- * ===============================
- */
- static int json_ensure_stack_size(OSSL_JSON_ENC *json, size_t num_bytes)
- {
- unsigned char *stack;
- if (json->stack_bytes >= num_bytes)
- return 1;
- if (num_bytes <= OSSL_NELEM(json->stack_small)) {
- stack = json->stack_small;
- } else {
- if (json->stack == json->stack_small)
- json->stack = NULL;
- stack = OPENSSL_realloc(json->stack, num_bytes);
- if (stack == NULL)
- return 0;
- }
- json->stack = stack;
- json->stack_bytes = num_bytes;
- return 1;
- }
- /* Push one bit onto the stack. Returns 0 on allocation failure. */
- static int json_push(OSSL_JSON_ENC *json, unsigned int v)
- {
- if (v > 1)
- return 0;
- if (json->stack_end_byte >= json->stack_bytes) {
- size_t new_size
- = (json->stack_bytes == 0)
- ? OSSL_NELEM(json->stack_small)
- : (json->stack_bytes * 2);
- if (!json_ensure_stack_size(json, new_size))
- return 0;
- json->stack_bytes = new_size;
- }
- if (v > 0)
- json->stack[json->stack_end_byte] |= (v << json->stack_end_bit);
- else
- json->stack[json->stack_end_byte] &= ~(1U << json->stack_end_bit);
- json->stack_end_bit = (json->stack_end_bit + 1) % CHAR_BIT;
- if (json->stack_end_bit == 0)
- ++json->stack_end_byte;
- return 1;
- }
- /*
- * Pop a bit from the stack. Returns 0 if stack is empty. Use json_peek() to get
- * the value before calling this.
- */
- static int json_pop(OSSL_JSON_ENC *json)
- {
- if (json->stack_end_byte == 0 && json->stack_end_bit == 0)
- return 0;
- if (json->stack_end_bit == 0) {
- --json->stack_end_byte;
- json->stack_end_bit = CHAR_BIT - 1;
- } else {
- --json->stack_end_bit;
- }
- return 1;
- }
- /*
- * Returns the bit on the top of the stack, or -1 if the stack is empty.
- */
- static int json_peek(OSSL_JSON_ENC *json)
- {
- size_t obyte, obit;
- obyte = json->stack_end_byte;
- obit = json->stack_end_bit;
- if (obit == 0) {
- if (obyte == 0)
- return -1;
- --obyte;
- obit = CHAR_BIT - 1;
- } else {
- --obit;
- }
- return (json->stack[obyte] & (1U << obit)) != 0;
- }
- /*
- * OSSL_JSON_ENC: Initialisation
- * =============================
- */
- enum {
- STATE_PRE_KEY,
- STATE_PRE_ITEM,
- STATE_PRE_COMMA
- };
- static ossl_inline int in_ijson(const OSSL_JSON_ENC *json)
- {
- return (json->flags & OSSL_JSON_FLAG_IJSON) != 0;
- }
- static ossl_inline int in_seq(const OSSL_JSON_ENC *json)
- {
- return (json->flags & OSSL_JSON_FLAG_SEQ) != 0;
- }
- static ossl_inline int in_pretty(const OSSL_JSON_ENC *json)
- {
- return (json->flags & OSSL_JSON_FLAG_PRETTY) != 0;
- }
- int ossl_json_init(OSSL_JSON_ENC *json, BIO *bio, uint32_t flags)
- {
- memset(json, 0, sizeof(*json));
- json->flags = flags;
- json->error = 0;
- if (!wbuf_init(&json->wbuf, bio, 4096))
- return 0;
- json->state = STATE_PRE_COMMA;
- return 1;
- }
- void ossl_json_cleanup(OSSL_JSON_ENC *json)
- {
- wbuf_cleanup(&json->wbuf);
- if (json->stack != json->stack_small)
- OPENSSL_free(json->stack);
- json->stack = NULL;
- }
- int ossl_json_flush_cleanup(OSSL_JSON_ENC *json)
- {
- int ok = ossl_json_flush(json);
- ossl_json_cleanup(json);
- return ok;
- }
- int ossl_json_reset(OSSL_JSON_ENC *json)
- {
- wbuf_clean(&json->wbuf);
- json->stack_end_byte = 0;
- json->stack_end_bit = 0;
- json->error = 0;
- return 1;
- }
- int ossl_json_flush(OSSL_JSON_ENC *json)
- {
- return wbuf_flush(&json->wbuf, /*full=*/1);
- }
- int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)
- {
- wbuf_set0_bio(&json->wbuf, bio);
- return 1;
- }
- int ossl_json_in_error(OSSL_JSON_ENC *json)
- {
- return json->error;
- }
- /*
- * JSON Builder Calls
- * ==================
- */
- static void json_write_qstring(OSSL_JSON_ENC *json, const char *str);
- static void json_indent(OSSL_JSON_ENC *json);
- static void json_raise_error(OSSL_JSON_ENC *json)
- {
- json->error = 1;
- }
- static void json_undefer(OSSL_JSON_ENC *json)
- {
- if (!json->defer_indent)
- return;
- json_indent(json);
- }
- static void json_write_char(OSSL_JSON_ENC *json, char ch)
- {
- if (ossl_json_in_error(json))
- return;
- json_undefer(json);
- if (!wbuf_write_char(&json->wbuf, ch))
- json_raise_error(json);
- }
- static void json_write_str(OSSL_JSON_ENC *json, const char *s)
- {
- if (ossl_json_in_error(json))
- return;
- json_undefer(json);
- if (!wbuf_write_str(&json->wbuf, s))
- json_raise_error(json);
- }
- static void json_indent(OSSL_JSON_ENC *json)
- {
- size_t i, depth;
- json->defer_indent = 0;
- if (!in_pretty(json))
- return;
- json_write_char(json, '\n');
- depth = json->stack_end_byte * 8 + json->stack_end_bit;
- for (i = 0; i < depth * 4; ++i)
- json_write_str(json, " ");
- }
- static int json_pre_item(OSSL_JSON_ENC *json)
- {
- int s;
- if (ossl_json_in_error(json))
- return 0;
- switch (json->state) {
- case STATE_PRE_COMMA:
- s = json_peek(json);
- if (s == 0) {
- json_raise_error(json);
- return 0;
- }
- if (s == 1) {
- json_write_char(json, ',');
- if (ossl_json_in_error(json))
- return 0;
- json_indent(json);
- }
- if (s < 0 && in_seq(json))
- json_write_char(json, '\x1E');
- json->state = STATE_PRE_ITEM;
- break;
- case STATE_PRE_ITEM:
- break;
- case STATE_PRE_KEY:
- default:
- json_raise_error(json);
- return 0;
- }
- return 1;
- }
- static void json_post_item(OSSL_JSON_ENC *json)
- {
- int s = json_peek(json);
- json->state = STATE_PRE_COMMA;
- if (s < 0 && in_seq(json))
- json_write_char(json, '\n');
- }
- /*
- * Begin a composite structure (object or array).
- *
- * type: 0=object, 1=array.
- */
- static void composite_begin(OSSL_JSON_ENC *json, int type, char ch)
- {
- if (!json_pre_item(json)
- || !json_push(json, type))
- json_raise_error(json);
- json_write_char(json, ch);
- json->defer_indent = 1;
- }
- /*
- * End a composite structure (object or array).
- *
- * type: 0=object, 1=array. Errors on mismatch.
- */
- static void composite_end(OSSL_JSON_ENC *json, int type, char ch)
- {
- int was_defer = json->defer_indent;
- if (ossl_json_in_error(json))
- return;
- json->defer_indent = 0;
- if (json_peek(json) != type) {
- json_raise_error(json);
- return;
- }
- if (type == 0 && json->state == STATE_PRE_ITEM) {
- json_raise_error(json);
- return;
- }
- if (!json_pop(json)) {
- json_raise_error(json);
- return;
- }
- if (!was_defer)
- json_indent(json);
- json_write_char(json, ch);
- json_post_item(json);
- }
- /* Begin a new JSON object. */
- void ossl_json_object_begin(OSSL_JSON_ENC *json)
- {
- composite_begin(json, 0, '{');
- json->state = STATE_PRE_KEY;
- }
- /* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */
- void ossl_json_object_end(OSSL_JSON_ENC *json)
- {
- composite_end(json, 0, '}');
- }
- /* Begin a new JSON array. */
- void ossl_json_array_begin(OSSL_JSON_ENC *json)
- {
- composite_begin(json, 1, '[');
- json->state = STATE_PRE_ITEM;
- }
- /* End a JSON array. Must be matched with a call to ossl_json_array_begin(). */
- void ossl_json_array_end(OSSL_JSON_ENC *json)
- {
- composite_end(json, 1, ']');
- }
- /*
- * Encode a JSON key within an object. Pass a zero-terminated string, which can
- * be freed immediately following the call to this function.
- */
- void ossl_json_key(OSSL_JSON_ENC *json, const char *key)
- {
- if (ossl_json_in_error(json))
- return;
- if (json_peek(json) != 0) {
- /* Not in object */
- json_raise_error(json);
- return;
- }
- if (json->state == STATE_PRE_COMMA) {
- json_write_char(json, ',');
- json->state = STATE_PRE_KEY;
- }
- json_indent(json);
- if (json->state != STATE_PRE_KEY) {
- json_raise_error(json);
- return;
- }
- json_write_qstring(json, key);
- if (ossl_json_in_error(json))
- return;
- json_write_char(json, ':');
- if (in_pretty(json))
- json_write_char(json, ' ');
- json->state = STATE_PRE_ITEM;
- }
- /* Encode a JSON 'null' value. */
- void ossl_json_null(OSSL_JSON_ENC *json)
- {
- if (!json_pre_item(json))
- return;
- json_write_str(json, "null");
- json_post_item(json);
- }
- void ossl_json_bool(OSSL_JSON_ENC *json, int v)
- {
- if (!json_pre_item(json))
- return;
- json_write_str(json, v > 0 ? "true" : "false");
- json_post_item(json);
- }
- #define POW_53 (((int64_t)1) << 53)
- /* Encode a JSON integer from a uint64_t. */
- static void json_u64(OSSL_JSON_ENC *json, uint64_t v, int noquote)
- {
- char buf[22], *p = buf + sizeof(buf) - 1;
- int quote = !noquote && in_ijson(json) && v > (uint64_t)(POW_53 - 1);
- if (!json_pre_item(json))
- return;
- if (quote)
- json_write_char(json, '"');
- if (v == 0)
- p = "0";
- else
- for (*p = '\0'; v > 0; v /= 10)
- *--p = '0' + v % 10;
- json_write_str(json, p);
- if (quote)
- json_write_char(json, '"');
- json_post_item(json);
- }
- void ossl_json_u64(OSSL_JSON_ENC *json, uint64_t v)
- {
- json_u64(json, v, 0);
- }
- /* Encode a JSON integer from an int64_t. */
- void ossl_json_i64(OSSL_JSON_ENC *json, int64_t value)
- {
- uint64_t uv;
- int quote;
- if (value >= 0) {
- ossl_json_u64(json, (uint64_t)value);
- return;
- }
- if (!json_pre_item(json))
- return;
- quote = in_ijson(json)
- && (value > POW_53 - 1 || value < -POW_53 + 1);
- if (quote)
- json_write_char(json, '"');
- json_write_char(json, '-');
- uv = (value == INT64_MIN)
- ? ((uint64_t)-(INT64_MIN + 1)) + 1
- : (uint64_t)-value;
- json_u64(json, uv, /*noquote=*/1);
- if (quote && !ossl_json_in_error(json))
- json_write_char(json, '"');
- }
- /* Encode a JSON number from a 64-bit floating point value. */
- void ossl_json_f64(OSSL_JSON_ENC *json, double value)
- {
- char buf[32];
- if (!json_pre_item(json))
- return;
- #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
- {
- int checks = isnan(value);
- # if !defined(OPENSSL_SYS_VMS)
- checks |= isinf(value);
- # endif
- if (checks) {
- json_raise_error(json);
- return;
- }
- }
- #endif
- BIO_snprintf(buf, sizeof(buf), "%1.17g", value);
- json_write_str(json, buf);
- json_post_item(json);
- }
- /*
- * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
- * can be freed immediately following the call to this function.
- */
- static ossl_inline int hex_digit(int v)
- {
- return v >= 10 ? 'a' + (v - 10) : '0' + v;
- }
- static ossl_inline void
- json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
- int nul_term)
- {
- char c, *o, obuf[7];
- unsigned char *u_str;
- int i;
- size_t j;
- if (ossl_json_in_error(json))
- return;
- json_write_char(json, '"');
- for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {
- c = *str;
- u_str = (unsigned char*)str;
- switch (c) {
- case '\n': o = "\\n"; break;
- case '\r': o = "\\r"; break;
- case '\t': o = "\\t"; break;
- case '\b': o = "\\b"; break;
- case '\f': o = "\\f"; break;
- case '"': o = "\\\""; break;
- case '\\': o = "\\\\"; break;
- default:
- /* valid UTF-8 sequences according to RFC-3629 */
- if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2
- && u_str[1] >= 0x80 && u_str[1] <= 0xbf) {
- memcpy(obuf, str, 2);
- obuf[2] = '\0';
- str++, j--;
- o = obuf;
- break;
- }
- if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3
- && u_str[1] >= 0x80 && u_str[1] <= 0xbf
- && u_str[2] >= 0x80 && u_str[2] <= 0xbf
- && !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)
- && !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {
- memcpy(obuf, str, 3);
- obuf[3] = '\0';
- str += 2;
- j -= 2;
- o = obuf;
- break;
- }
- if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4
- && u_str[1] >= 0x80 && u_str[1] <= 0xbf
- && u_str[2] >= 0x80 && u_str[2] <= 0xbf
- && u_str[3] >= 0x80 && u_str[3] <= 0xbf
- && !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)
- && !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {
- memcpy(obuf, str, 4);
- obuf[4] = '\0';
- str += 3;
- j -= 3;
- o = obuf;
- break;
- }
- if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {
- obuf[0] = '\\';
- obuf[1] = 'u';
- for (i = 0; i < 4; ++i)
- obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);
- obuf[6] = '\0';
- o = obuf;
- } else {
- json_write_char(json, c);
- continue;
- }
- break;
- }
- json_write_str(json, o);
- }
- json_write_char(json, '"');
- }
- static void
- json_write_qstring(OSSL_JSON_ENC *json, const char *str)
- {
- json_write_qstring_inner(json, str, 0, 1);
- }
- static void
- json_write_qstring_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
- {
- json_write_qstring_inner(json, str, str_len, 0);
- }
- void ossl_json_str(OSSL_JSON_ENC *json, const char *str)
- {
- if (!json_pre_item(json))
- return;
- json_write_qstring(json, str);
- json_post_item(json);
- }
- void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
- {
- if (!json_pre_item(json))
- return;
- json_write_qstring_len(json, str, str_len);
- json_post_item(json);
- }
- /*
- * Encode binary data as a lowercase hex string. data_len is the data length in
- * bytes.
- */
- void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len)
- {
- const unsigned char *b = data, *end = b + data_len;
- unsigned char c;
- if (!json_pre_item(json))
- return;
- json_write_char(json, '"');
- for (; b < end; ++b) {
- c = *b;
- json_write_char(json, hex_digit(c >> 4));
- json_write_char(json, hex_digit(c & 0x0F));
- }
- json_write_char(json, '"');
- json_post_item(json);
- }
|