1 | /*
|
---|
2 | * Copyright 2023-2024 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 | /* Encode a JSON number from a 64-bit floating point value. */
|
---|
206 | void ossl_json_f64(OSSL_JSON_ENC *json, double value);
|
---|
207 |
|
---|
208 | /*
|
---|
209 | * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
|
---|
210 | * can be freed immediately following the call to this function.
|
---|
211 | */
|
---|
212 | void ossl_json_str(OSSL_JSON_ENC *json, const char *str);
|
---|
213 |
|
---|
214 | /*
|
---|
215 | * Encode a JSON UTF-8 string from a string with the given length. The string
|
---|
216 | * passed can be freed immediately following the call to this function.
|
---|
217 | */
|
---|
218 | void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len);
|
---|
219 |
|
---|
220 | /*
|
---|
221 | * Encode binary data as a lowercase hex string. data_len is the data length in
|
---|
222 | * bytes.
|
---|
223 | */
|
---|
224 | void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len);
|
---|
225 |
|
---|
226 | #endif
|
---|