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