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