Home | History | Annotate | Line # | Download | only in quic
      1 /*
      2  * Copyright 2023-2025 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 "internal/numbers.h"
     13 #include <string.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 /*
    598  * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
    599  * can be freed immediately following the call to this function.
    600  */
    601 static ossl_inline int hex_digit(int v)
    602 {
    603     return v >= 10 ? 'a' + (v - 10) : '0' + v;
    604 }
    605 
    606 static ossl_inline void
    607 json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
    608     int nul_term)
    609 {
    610     char c, *o, obuf[7];
    611     unsigned char *u_str;
    612     int i;
    613     size_t j;
    614 
    615     if (ossl_json_in_error(json))
    616         return;
    617 
    618     json_write_char(json, '"');
    619 
    620     for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {
    621         c = *str;
    622         u_str = (unsigned char *)str;
    623         switch (c) {
    624         case '\n':
    625             o = "\\n";
    626             break;
    627         case '\r':
    628             o = "\\r";
    629             break;
    630         case '\t':
    631             o = "\\t";
    632             break;
    633         case '\b':
    634             o = "\\b";
    635             break;
    636         case '\f':
    637             o = "\\f";
    638             break;
    639         case '"':
    640             o = "\\\"";
    641             break;
    642         case '\\':
    643             o = "\\\\";
    644             break;
    645         default:
    646             /* valid UTF-8 sequences according to RFC-3629 */
    647             if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2
    648                 && u_str[1] >= 0x80 && u_str[1] <= 0xbf) {
    649                 memcpy(obuf, str, 2);
    650                 obuf[2] = '\0';
    651                 str++, j--;
    652                 o = obuf;
    653                 break;
    654             }
    655             if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3
    656                 && u_str[1] >= 0x80 && u_str[1] <= 0xbf
    657                 && u_str[2] >= 0x80 && u_str[2] <= 0xbf
    658                 && !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)
    659                 && !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {
    660                 memcpy(obuf, str, 3);
    661                 obuf[3] = '\0';
    662                 str += 2;
    663                 j -= 2;
    664                 o = obuf;
    665                 break;
    666             }
    667             if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4
    668                 && u_str[1] >= 0x80 && u_str[1] <= 0xbf
    669                 && u_str[2] >= 0x80 && u_str[2] <= 0xbf
    670                 && u_str[3] >= 0x80 && u_str[3] <= 0xbf
    671                 && !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)
    672                 && !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {
    673                 memcpy(obuf, str, 4);
    674                 obuf[4] = '\0';
    675                 str += 3;
    676                 j -= 3;
    677                 o = obuf;
    678                 break;
    679             }
    680             if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {
    681                 obuf[0] = '\\';
    682                 obuf[1] = 'u';
    683                 for (i = 0; i < 4; ++i)
    684                     obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);
    685                 obuf[6] = '\0';
    686                 o = obuf;
    687             } else {
    688                 json_write_char(json, c);
    689                 continue;
    690             }
    691             break;
    692         }
    693 
    694         json_write_str(json, o);
    695     }
    696 
    697     json_write_char(json, '"');
    698 }
    699 
    700 static void
    701 json_write_qstring(OSSL_JSON_ENC *json, const char *str)
    702 {
    703     json_write_qstring_inner(json, str, 0, 1);
    704 }
    705 
    706 static void
    707 json_write_qstring_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
    708 {
    709     json_write_qstring_inner(json, str, str_len, 0);
    710 }
    711 
    712 void ossl_json_str(OSSL_JSON_ENC *json, const char *str)
    713 {
    714     if (!json_pre_item(json))
    715         return;
    716 
    717     json_write_qstring(json, str);
    718     json_post_item(json);
    719 }
    720 
    721 void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
    722 {
    723     if (!json_pre_item(json))
    724         return;
    725 
    726     json_write_qstring_len(json, str, str_len);
    727     json_post_item(json);
    728 }
    729 
    730 /*
    731  * Encode binary data as a lowercase hex string. data_len is the data length in
    732  * bytes.
    733  */
    734 void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len)
    735 {
    736     const unsigned char *b = data, *end = b + data_len;
    737     unsigned char c;
    738 
    739     if (!json_pre_item(json))
    740         return;
    741 
    742     json_write_char(json, '"');
    743 
    744     for (; b < end; ++b) {
    745         c = *b;
    746         json_write_char(json, hex_digit(c >> 4));
    747         json_write_char(json, hex_digit(c & 0x0F));
    748     }
    749 
    750     json_write_char(json, '"');
    751     json_post_item(json);
    752 }
    753