Home | History | Annotate | Line # | Download | only in internal
      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 #ifndef OSSL_JSON_ENC_H
     11 #define OSSL_JSON_ENC_H
     12 
     13 #include <openssl/bio.h>
     14 
     15 /*
     16  * JSON Encoder
     17  * ============
     18  *
     19  * This JSON encoder is used for qlog. It supports ordinary JSON (RFC 7159),
     20  * JSON-SEQ (RFC 7464) and I-JSON (RFC 7493). It supports only basic ASCII.
     21  */
     22 
     23 struct json_write_buf {
     24     BIO *bio;
     25     char *buf;
     26     size_t alloc, cur;
     27 };
     28 
     29 typedef struct ossl_json_enc_st {
     30     uint32_t flags;
     31     /* error: 1 if an error has occurred. */
     32     /* state: current state. */
     33     /* stack stores a bitmap. 0=object, 1=array. */
     34     /* stack cur   size: stack_end_byte bytes, stack_end_bit bits. */
     35     /* stack alloc size: stack_bytes bytes. */
     36     unsigned char error, stack_end_bit, state, *stack, defer_indent;
     37     unsigned char stack_small[16];
     38     struct json_write_buf wbuf;
     39     size_t stack_end_byte, stack_bytes;
     40 } OSSL_JSON_ENC;
     41 
     42 /*
     43  * ossl_json_init
     44  * --------------
     45  *
     46  * Initialises a JSON encoder.
     47  *
     48  * If the flag OSSL_JSON_FLAG_SEQ is passed, the output is in JSON-SEQ. The
     49  * caller should use the encoder as though it is encoding members of a JSON
     50  * array (but without calling ossl_json_array_begin() or ossl_json_array_end()).
     51  * Each top-level JSON item (e.g. JSON object) encoded will be separated
     52  * correctly as per the JSON-SEQ format.
     53  *
     54  * If the flag OSSL_JSON_FLAG_SEQ is not passed, the output is in JSON format.
     55  * Generally the caller should encode only a single output item (e.g. a JSON
     56  * object).
     57  *
     58  * By default, JSON output is maximally compact. If OSSL_JSON_FLAG_PRETTY is
     59  * set, JSON/JSON-SEQ output is spaced for optimal human readability.
     60  *
     61  * If OSSL_JSON_FLAG_IJSON is set, integers outside the range `[-2**53 + 1,
     62  * 2**53 - 1]` are automatically converted to decimal strings before
     63  * serialization.
     64  */
     65 #define OSSL_JSON_FLAG_NONE 0
     66 #define OSSL_JSON_FLAG_SEQ (1U << 0)
     67 #define OSSL_JSON_FLAG_PRETTY (1U << 1)
     68 #define OSSL_JSON_FLAG_IJSON (1U << 2)
     69 
     70 int ossl_json_init(OSSL_JSON_ENC *json, BIO *bio, uint32_t flags);
     71 
     72 /*
     73  * ossl_json_cleanup
     74  * -----------------
     75  *
     76  * Destroys a JSON encoder.
     77  */
     78 void ossl_json_cleanup(OSSL_JSON_ENC *json);
     79 
     80 /*
     81  * ossl_json_reset
     82  * ---------------
     83  *
     84  * Resets a JSON encoder, as though it has just been initialised, allowing it
     85  * to be used again for new output syntactically unrelated to any previous
     86  * output. This is similar to calling ossl_json_cleanup followed by
     87  * ossl_json_init but may allow internal buffers to be reused.
     88  *
     89  * If the JSON encoder has entered an error state, this function MAY allow
     90  * recovery from this error state, in which case it will return 1. If this
     91  * function returns 0, the JSON encoder is unrecoverable and
     92  * ossl_json_cleanup() must be called.
     93  *
     94  * Automatically calls ossl_json_flush().
     95  */
     96 int ossl_json_reset(OSSL_JSON_ENC *json);
     97 
     98 /*
     99  * ossl_json_flush
    100  * ---------------
    101  *
    102  * Flushes the JSON encoder, ensuring that any residual bytes in internal
    103  * buffers are written to the provided sink BIO. Flushing may also happen
    104  * autonomously as buffers are filled, but the caller must use this function
    105  * to guarantee all data has been flushed.
    106  */
    107 int ossl_json_flush(OSSL_JSON_ENC *json);
    108 
    109 /*
    110  * ossl_json_flush_cleanup
    111  * -----------------------
    112  *
    113  * Tries to flush as in a call to ossl_json_flush, and then calls
    114  * ossl_json_cleanup regardless of the result. The result of the flush call is
    115  * returned.
    116  */
    117 int ossl_json_flush_cleanup(OSSL_JSON_ENC *json);
    118 
    119 /*
    120  * ossl_json_set0_sink
    121  * -------------------
    122  *
    123  * Changes the sink used by the JSON encoder.
    124  */
    125 int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio);
    126 
    127 /*
    128  * ossl_json_in_error
    129  * ------------------
    130  *
    131  * To enhance the ergonomics of the JSON API, the JSON object uses an implicit
    132  * error tracking model. When a JSON API call fails (for example due to caller
    133  * error, such as trying to close an array which was not opened), the JSON
    134  * object enters an error state and all further calls are silently ignored.
    135  *
    136  * The caller can detect this condition after it is finished making builder
    137  * calls to the JSON object by calling this function. This function returns 1
    138  * if an error occurred. At this point the caller's only recourse is to call
    139  * ossl_json_reset() or ossl_json_cleanup().
    140  *
    141  * Note that partial (i.e., invalid) output may still have been sent to the BIO
    142  * in this case. Since the amount of output which can potentially be produced
    143  * by a JSON object is unbounded, it is impractical to buffer it all before
    144  * flushing. It is expected that errors will ordinarily be either caller errors
    145  * (programming errors) or BIO errors.
    146  */
    147 int ossl_json_in_error(OSSL_JSON_ENC *json);
    148 
    149 /*
    150  * JSON Builder Calls
    151  * ==================
    152  *
    153  * These functions are used to build JSON output. The functions which have
    154  * begin and end function pairs must be called in correctly nested sequence.
    155  * When writing an object, ossl_json_key() must be called exactly once before
    156  * each call to write a JSON item.
    157  *
    158  * The JSON library takes responsibility for enforcing correct usage patterns.
    159  * If a call is made that does not correspond to the JSON syntax, the JSON
    160  * object enters the error state and all subsequent calls are ignored.
    161  *
    162  * In JSON-SEQ mode, the caller should act as though the library implicitly
    163  * places all calls between an ossl_json_array_begin() and
    164  * ossl_json_array_end() pair; for example, the normal usage pattern would be
    165  * to call ossl_json_object_begin() followed by ossl_json_object_end(), in
    166  * repeated sequence.
    167  *
    168  * The library does not enforce non-generation of duplicate keys. Avoiding this
    169  * is the caller's responsibility. It is also the caller's responsibility to
    170  * pass valid UTF-8 strings. All other forms of invalid output will cause an
    171  * error. Note that due to the immediate nature of the API, partial output may
    172  * have already been generated in such a case.
    173  */
    174 
    175 /* Begin a new JSON object. */
    176 void ossl_json_object_begin(OSSL_JSON_ENC *json);
    177 
    178 /* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */
    179 void ossl_json_object_end(OSSL_JSON_ENC *json);
    180 
    181 /* Begin a new JSON array. */
    182 void ossl_json_array_begin(OSSL_JSON_ENC *json);
    183 
    184 /* End a JSON array. Must be matched with a call to ossl_json_array_end(). */
    185 void ossl_json_array_end(OSSL_JSON_ENC *json);
    186 
    187 /*
    188  * Encode a JSON key within an object. Pass a zero-terminated string, which can
    189  * be freed immediately following the call to this function.
    190  */
    191 void ossl_json_key(OSSL_JSON_ENC *json, const char *key);
    192 
    193 /* Encode a JSON 'null' value. */
    194 void ossl_json_null(OSSL_JSON_ENC *json);
    195 
    196 /* Encode a JSON boolean value. */
    197 void ossl_json_bool(OSSL_JSON_ENC *json, int value);
    198 
    199 /* Encode a JSON integer from a uint64_t. */
    200 void ossl_json_u64(OSSL_JSON_ENC *json, uint64_t value);
    201 
    202 /* Encode a JSON integer from an int64_t. */
    203 void ossl_json_i64(OSSL_JSON_ENC *json, int64_t value);
    204 
    205 /*
    206  * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
    207  * can be freed immediately following the call to this function.
    208  */
    209 void ossl_json_str(OSSL_JSON_ENC *json, const char *str);
    210 
    211 /*
    212  * Encode a JSON UTF-8 string from a string with the given length. The string
    213  * passed can be freed immediately following the call to this function.
    214  */
    215 void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len);
    216 
    217 /*
    218  * Encode binary data as a lowercase hex string. data_len is the data length in
    219  * bytes.
    220  */
    221 void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len);
    222 
    223 #endif
    224