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