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 #include "internal/json_enc.h"
11 #include "internal/nelem.h"
12 #include "internal/numbers.h"
13 #include <string.h>
14
15 /*
16 * wbuf
17 * ====
18 */
19 static int wbuf_flush(struct json_write_buf *wbuf, int full);
20
wbuf_init(struct json_write_buf * wbuf,BIO * bio,size_t alloc)21 static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)
22 {
23 wbuf->buf = OPENSSL_malloc(alloc);
24 if (wbuf->buf == NULL)
25 return 0;
26
27 wbuf->cur = 0;
28 wbuf->alloc = alloc;
29 wbuf->bio = bio;
30 return 1;
31 }
32
wbuf_cleanup(struct json_write_buf * wbuf)33 static void wbuf_cleanup(struct json_write_buf *wbuf)
34 {
35 OPENSSL_free(wbuf->buf);
36 wbuf->buf = NULL;
37 wbuf->alloc = 0;
38 }
39
wbuf_set0_bio(struct json_write_buf * wbuf,BIO * bio)40 static void wbuf_set0_bio(struct json_write_buf *wbuf, BIO *bio)
41 {
42 wbuf->bio = bio;
43 }
44
45 /* Empty write buffer. */
wbuf_clean(struct json_write_buf * wbuf)46 static ossl_inline void wbuf_clean(struct json_write_buf *wbuf)
47 {
48 wbuf->cur = 0;
49 }
50
51 /* Available data remaining in buffer. */
wbuf_avail(struct json_write_buf * wbuf)52 static ossl_inline size_t wbuf_avail(struct json_write_buf *wbuf)
53 {
54 return wbuf->alloc - wbuf->cur;
55 }
56
57 /* Add character to write buffer, returning 0 on flush failure. */
wbuf_write_char(struct json_write_buf * wbuf,char c)58 static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)
59 {
60 if (wbuf_avail(wbuf) == 0) {
61 if (!wbuf_flush(wbuf, /*full=*/0))
62 return 0;
63 }
64
65 wbuf->buf[wbuf->cur++] = c;
66 return 1;
67 }
68
69 /*
70 * Write zero-terminated string to write buffer, returning 0 on flush failure.
71 */
wbuf_write_str(struct json_write_buf * wbuf,const char * s)72 static int wbuf_write_str(struct json_write_buf *wbuf, const char *s)
73 {
74 char c;
75
76 while ((c = *s++) != 0)
77 if (!wbuf_write_char(wbuf, c))
78 return 0;
79
80 return 1;
81 }
82
83 /* Flush write buffer, returning 0 on I/O failure. */
wbuf_flush(struct json_write_buf * wbuf,int full)84 static int wbuf_flush(struct json_write_buf *wbuf, int full)
85 {
86 size_t written = 0, total_written = 0;
87
88 while (total_written < wbuf->cur) {
89 if (!BIO_write_ex(wbuf->bio,
90 wbuf->buf + total_written,
91 wbuf->cur - total_written,
92 &written)) {
93 memmove(wbuf->buf,
94 wbuf->buf + total_written,
95 wbuf->cur - total_written);
96 wbuf->cur = 0;
97 return 0;
98 }
99
100 total_written += written;
101 }
102
103 wbuf->cur = 0;
104
105 if (full)
106 (void)BIO_flush(wbuf->bio); /* best effort */
107
108 return 1;
109 }
110
111 /*
112 * OSSL_JSON_ENC: Stack Management
113 * ===============================
114 */
115
json_ensure_stack_size(OSSL_JSON_ENC * json,size_t num_bytes)116 static int json_ensure_stack_size(OSSL_JSON_ENC *json, size_t num_bytes)
117 {
118 unsigned char *stack;
119
120 if (json->stack_bytes >= num_bytes)
121 return 1;
122
123 if (num_bytes <= OSSL_NELEM(json->stack_small)) {
124 stack = json->stack_small;
125 } else {
126 if (json->stack == json->stack_small)
127 json->stack = NULL;
128
129 stack = OPENSSL_realloc(json->stack, num_bytes);
130 if (stack == NULL)
131 return 0;
132 }
133
134 json->stack = stack;
135 json->stack_bytes = num_bytes;
136 return 1;
137 }
138
139 /* Push one bit onto the stack. Returns 0 on allocation failure. */
json_push(OSSL_JSON_ENC * json,unsigned int v)140 static int json_push(OSSL_JSON_ENC *json, unsigned int v)
141 {
142 if (v > 1)
143 return 0;
144
145 if (json->stack_end_byte >= json->stack_bytes) {
146 size_t new_size
147 = (json->stack_bytes == 0)
148 ? OSSL_NELEM(json->stack_small)
149 : (json->stack_bytes * 2);
150
151 if (!json_ensure_stack_size(json, new_size))
152 return 0;
153
154 json->stack_bytes = new_size;
155 }
156
157 if (v > 0)
158 json->stack[json->stack_end_byte] |= (v << json->stack_end_bit);
159 else
160 json->stack[json->stack_end_byte] &= ~(1U << json->stack_end_bit);
161
162 json->stack_end_bit = (json->stack_end_bit + 1) % CHAR_BIT;
163 if (json->stack_end_bit == 0)
164 ++json->stack_end_byte;
165
166 return 1;
167 }
168
169 /*
170 * Pop a bit from the stack. Returns 0 if stack is empty. Use json_peek() to get
171 * the value before calling this.
172 */
json_pop(OSSL_JSON_ENC * json)173 static int json_pop(OSSL_JSON_ENC *json)
174 {
175 if (json->stack_end_byte == 0 && json->stack_end_bit == 0)
176 return 0;
177
178 if (json->stack_end_bit == 0) {
179 --json->stack_end_byte;
180 json->stack_end_bit = CHAR_BIT - 1;
181 } else {
182 --json->stack_end_bit;
183 }
184
185 return 1;
186 }
187
188 /*
189 * Returns the bit on the top of the stack, or -1 if the stack is empty.
190 */
json_peek(OSSL_JSON_ENC * json)191 static int json_peek(OSSL_JSON_ENC *json)
192 {
193 size_t obyte, obit;
194
195 obyte = json->stack_end_byte;
196 obit = json->stack_end_bit;
197 if (obit == 0) {
198 if (obyte == 0)
199 return -1;
200
201 --obyte;
202 obit = CHAR_BIT - 1;
203 } else {
204 --obit;
205 }
206
207 return (json->stack[obyte] & (1U << obit)) != 0;
208 }
209
210 /*
211 * OSSL_JSON_ENC: Initialisation
212 * =============================
213 */
214
215 enum {
216 STATE_PRE_KEY,
217 STATE_PRE_ITEM,
218 STATE_PRE_COMMA
219 };
220
in_ijson(const OSSL_JSON_ENC * json)221 static ossl_inline int in_ijson(const OSSL_JSON_ENC *json)
222 {
223 return (json->flags & OSSL_JSON_FLAG_IJSON) != 0;
224 }
225
in_seq(const OSSL_JSON_ENC * json)226 static ossl_inline int in_seq(const OSSL_JSON_ENC *json)
227 {
228 return (json->flags & OSSL_JSON_FLAG_SEQ) != 0;
229 }
230
in_pretty(const OSSL_JSON_ENC * json)231 static ossl_inline int in_pretty(const OSSL_JSON_ENC *json)
232 {
233 return (json->flags & OSSL_JSON_FLAG_PRETTY) != 0;
234 }
235
ossl_json_init(OSSL_JSON_ENC * json,BIO * bio,uint32_t flags)236 int ossl_json_init(OSSL_JSON_ENC *json, BIO *bio, uint32_t flags)
237 {
238 memset(json, 0, sizeof(*json));
239 json->flags = flags;
240 json->error = 0;
241 if (!wbuf_init(&json->wbuf, bio, 4096))
242 return 0;
243
244 json->state = STATE_PRE_COMMA;
245 return 1;
246 }
247
ossl_json_cleanup(OSSL_JSON_ENC * json)248 void ossl_json_cleanup(OSSL_JSON_ENC *json)
249 {
250 wbuf_cleanup(&json->wbuf);
251
252 if (json->stack != json->stack_small)
253 OPENSSL_free(json->stack);
254
255 json->stack = NULL;
256 }
257
ossl_json_flush_cleanup(OSSL_JSON_ENC * json)258 int ossl_json_flush_cleanup(OSSL_JSON_ENC *json)
259 {
260 int ok = ossl_json_flush(json);
261
262 ossl_json_cleanup(json);
263 return ok;
264 }
265
ossl_json_reset(OSSL_JSON_ENC * json)266 int ossl_json_reset(OSSL_JSON_ENC *json)
267 {
268 wbuf_clean(&json->wbuf);
269 json->stack_end_byte = 0;
270 json->stack_end_bit = 0;
271 json->error = 0;
272 return 1;
273 }
274
ossl_json_flush(OSSL_JSON_ENC * json)275 int ossl_json_flush(OSSL_JSON_ENC *json)
276 {
277 return wbuf_flush(&json->wbuf, /*full=*/1);
278 }
279
ossl_json_set0_sink(OSSL_JSON_ENC * json,BIO * bio)280 int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)
281 {
282 wbuf_set0_bio(&json->wbuf, bio);
283 return 1;
284 }
285
ossl_json_in_error(OSSL_JSON_ENC * json)286 int ossl_json_in_error(OSSL_JSON_ENC *json)
287 {
288 return json->error;
289 }
290
291 /*
292 * JSON Builder Calls
293 * ==================
294 */
295
296 static void json_write_qstring(OSSL_JSON_ENC *json, const char *str);
297 static void json_indent(OSSL_JSON_ENC *json);
298
json_raise_error(OSSL_JSON_ENC * json)299 static void json_raise_error(OSSL_JSON_ENC *json)
300 {
301 json->error = 1;
302 }
303
json_undefer(OSSL_JSON_ENC * json)304 static void json_undefer(OSSL_JSON_ENC *json)
305 {
306 if (!json->defer_indent)
307 return;
308
309 json_indent(json);
310 }
311
json_write_char(OSSL_JSON_ENC * json,char ch)312 static void json_write_char(OSSL_JSON_ENC *json, char ch)
313 {
314 if (ossl_json_in_error(json))
315 return;
316
317 json_undefer(json);
318 if (!wbuf_write_char(&json->wbuf, ch))
319 json_raise_error(json);
320 }
321
json_write_str(OSSL_JSON_ENC * json,const char * s)322 static void json_write_str(OSSL_JSON_ENC *json, const char *s)
323 {
324 if (ossl_json_in_error(json))
325 return;
326
327 json_undefer(json);
328 if (!wbuf_write_str(&json->wbuf, s))
329 json_raise_error(json);
330 }
331
json_indent(OSSL_JSON_ENC * json)332 static void json_indent(OSSL_JSON_ENC *json)
333 {
334 size_t i, depth;
335
336 json->defer_indent = 0;
337
338 if (!in_pretty(json))
339 return;
340
341 json_write_char(json, '\n');
342
343 depth = json->stack_end_byte * 8 + json->stack_end_bit;
344 for (i = 0; i < depth * 4; ++i)
345 json_write_str(json, " ");
346 }
347
json_pre_item(OSSL_JSON_ENC * json)348 static int json_pre_item(OSSL_JSON_ENC *json)
349 {
350 int s;
351
352 if (ossl_json_in_error(json))
353 return 0;
354
355 switch (json->state) {
356 case STATE_PRE_COMMA:
357 s = json_peek(json);
358
359 if (s == 0) {
360 json_raise_error(json);
361 return 0;
362 }
363
364 if (s == 1) {
365 json_write_char(json, ',');
366 if (ossl_json_in_error(json))
367 return 0;
368
369 json_indent(json);
370 }
371
372 if (s < 0 && in_seq(json))
373 json_write_char(json, '\x1E');
374
375 json->state = STATE_PRE_ITEM;
376 break;
377
378 case STATE_PRE_ITEM:
379 break;
380
381 case STATE_PRE_KEY:
382 default:
383 json_raise_error(json);
384 return 0;
385 }
386
387 return 1;
388 }
389
json_post_item(OSSL_JSON_ENC * json)390 static void json_post_item(OSSL_JSON_ENC *json)
391 {
392 int s = json_peek(json);
393
394 json->state = STATE_PRE_COMMA;
395
396 if (s < 0 && in_seq(json))
397 json_write_char(json, '\n');
398 }
399
400 /*
401 * Begin a composite structure (object or array).
402 *
403 * type: 0=object, 1=array.
404 */
composite_begin(OSSL_JSON_ENC * json,int type,char ch)405 static void composite_begin(OSSL_JSON_ENC *json, int type, char ch)
406 {
407 if (!json_pre_item(json)
408 || !json_push(json, type))
409 json_raise_error(json);
410
411 json_write_char(json, ch);
412 json->defer_indent = 1;
413 }
414
415 /*
416 * End a composite structure (object or array).
417 *
418 * type: 0=object, 1=array. Errors on mismatch.
419 */
composite_end(OSSL_JSON_ENC * json,int type,char ch)420 static void composite_end(OSSL_JSON_ENC *json, int type, char ch)
421 {
422 int was_defer = json->defer_indent;
423
424 if (ossl_json_in_error(json))
425 return;
426
427 json->defer_indent = 0;
428
429 if (json_peek(json) != type) {
430 json_raise_error(json);
431 return;
432 }
433
434 if (type == 0 && json->state == STATE_PRE_ITEM) {
435 json_raise_error(json);
436 return;
437 }
438
439 if (!json_pop(json)) {
440 json_raise_error(json);
441 return;
442 }
443
444 if (!was_defer)
445 json_indent(json);
446
447 json_write_char(json, ch);
448 json_post_item(json);
449 }
450
451 /* Begin a new JSON object. */
ossl_json_object_begin(OSSL_JSON_ENC * json)452 void ossl_json_object_begin(OSSL_JSON_ENC *json)
453 {
454 composite_begin(json, 0, '{');
455 json->state = STATE_PRE_KEY;
456 }
457
458 /* End a JSON object. Must be matched with a call to ossl_json_object_begin(). */
ossl_json_object_end(OSSL_JSON_ENC * json)459 void ossl_json_object_end(OSSL_JSON_ENC *json)
460 {
461 composite_end(json, 0, '}');
462 }
463
464 /* Begin a new JSON array. */
ossl_json_array_begin(OSSL_JSON_ENC * json)465 void ossl_json_array_begin(OSSL_JSON_ENC *json)
466 {
467 composite_begin(json, 1, '[');
468 json->state = STATE_PRE_ITEM;
469 }
470
471 /* End a JSON array. Must be matched with a call to ossl_json_array_begin(). */
ossl_json_array_end(OSSL_JSON_ENC * json)472 void ossl_json_array_end(OSSL_JSON_ENC *json)
473 {
474 composite_end(json, 1, ']');
475 }
476
477 /*
478 * Encode a JSON key within an object. Pass a zero-terminated string, which can
479 * be freed immediately following the call to this function.
480 */
ossl_json_key(OSSL_JSON_ENC * json,const char * key)481 void ossl_json_key(OSSL_JSON_ENC *json, const char *key)
482 {
483 if (ossl_json_in_error(json))
484 return;
485
486 if (json_peek(json) != 0) {
487 /* Not in object */
488 json_raise_error(json);
489 return;
490 }
491
492 if (json->state == STATE_PRE_COMMA) {
493 json_write_char(json, ',');
494 json->state = STATE_PRE_KEY;
495 }
496
497 json_indent(json);
498 if (json->state != STATE_PRE_KEY) {
499 json_raise_error(json);
500 return;
501 }
502
503 json_write_qstring(json, key);
504 if (ossl_json_in_error(json))
505 return;
506
507 json_write_char(json, ':');
508 if (in_pretty(json))
509 json_write_char(json, ' ');
510
511 json->state = STATE_PRE_ITEM;
512 }
513
514 /* Encode a JSON 'null' value. */
ossl_json_null(OSSL_JSON_ENC * json)515 void ossl_json_null(OSSL_JSON_ENC *json)
516 {
517 if (!json_pre_item(json))
518 return;
519
520 json_write_str(json, "null");
521 json_post_item(json);
522 }
523
ossl_json_bool(OSSL_JSON_ENC * json,int v)524 void ossl_json_bool(OSSL_JSON_ENC *json, int v)
525 {
526 if (!json_pre_item(json))
527 return;
528
529 json_write_str(json, v > 0 ? "true" : "false");
530 json_post_item(json);
531 }
532
533 #define POW_53 (((int64_t)1) << 53)
534
535 /* Encode a JSON integer from a uint64_t. */
json_u64(OSSL_JSON_ENC * json,uint64_t v,int noquote)536 static void json_u64(OSSL_JSON_ENC *json, uint64_t v, int noquote)
537 {
538 char buf[22], *p = buf + sizeof(buf) - 1;
539 int quote = !noquote && in_ijson(json) && v > (uint64_t)(POW_53 - 1);
540
541 if (!json_pre_item(json))
542 return;
543
544 if (quote)
545 json_write_char(json, '"');
546
547 if (v == 0)
548 p = "0";
549 else
550 for (*p = '\0'; v > 0; v /= 10)
551 *--p = '0' + v % 10;
552
553 json_write_str(json, p);
554
555 if (quote)
556 json_write_char(json, '"');
557
558 json_post_item(json);
559 }
560
ossl_json_u64(OSSL_JSON_ENC * json,uint64_t v)561 void ossl_json_u64(OSSL_JSON_ENC *json, uint64_t v)
562 {
563 json_u64(json, v, 0);
564 }
565
566 /* Encode a JSON integer from an int64_t. */
ossl_json_i64(OSSL_JSON_ENC * json,int64_t value)567 void ossl_json_i64(OSSL_JSON_ENC *json, int64_t value)
568 {
569 uint64_t uv;
570 int quote;
571
572 if (value >= 0) {
573 ossl_json_u64(json, (uint64_t)value);
574 return;
575 }
576
577 if (!json_pre_item(json))
578 return;
579
580 quote = in_ijson(json)
581 && (value > POW_53 - 1 || value < -POW_53 + 1);
582
583 if (quote)
584 json_write_char(json, '"');
585
586 json_write_char(json, '-');
587
588 uv = (value == INT64_MIN)
589 ? ((uint64_t)-(INT64_MIN + 1)) + 1
590 : (uint64_t)-value;
591 json_u64(json, uv, /*noquote=*/1);
592
593 if (quote && !ossl_json_in_error(json))
594 json_write_char(json, '"');
595 }
596
597 /*
598 * Encode a JSON UTF-8 string from a zero-terminated string. The string passed
599 * can be freed immediately following the call to this function.
600 */
hex_digit(int v)601 static ossl_inline int hex_digit(int v)
602 {
603 return v >= 10 ? 'a' + (v - 10) : '0' + v;
604 }
605
606 static ossl_inline void
json_write_qstring_inner(OSSL_JSON_ENC * json,const char * str,size_t str_len,int nul_term)607 json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
608 int nul_term)
609 {
610 char c, *o, obuf[7];
611 unsigned char *u_str;
612 int i;
613 size_t j;
614
615 if (ossl_json_in_error(json))
616 return;
617
618 json_write_char(json, '"');
619
620 for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {
621 c = *str;
622 u_str = (unsigned char*)str;
623 switch (c) {
624 case '\n': o = "\\n"; break;
625 case '\r': o = "\\r"; break;
626 case '\t': o = "\\t"; break;
627 case '\b': o = "\\b"; break;
628 case '\f': o = "\\f"; break;
629 case '"': o = "\\\""; break;
630 case '\\': o = "\\\\"; break;
631 default:
632 /* valid UTF-8 sequences according to RFC-3629 */
633 if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2
634 && u_str[1] >= 0x80 && u_str[1] <= 0xbf) {
635 memcpy(obuf, str, 2);
636 obuf[2] = '\0';
637 str++, j--;
638 o = obuf;
639 break;
640 }
641 if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3
642 && u_str[1] >= 0x80 && u_str[1] <= 0xbf
643 && u_str[2] >= 0x80 && u_str[2] <= 0xbf
644 && !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)
645 && !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {
646 memcpy(obuf, str, 3);
647 obuf[3] = '\0';
648 str += 2;
649 j -= 2;
650 o = obuf;
651 break;
652 }
653 if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4
654 && u_str[1] >= 0x80 && u_str[1] <= 0xbf
655 && u_str[2] >= 0x80 && u_str[2] <= 0xbf
656 && u_str[3] >= 0x80 && u_str[3] <= 0xbf
657 && !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)
658 && !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {
659 memcpy(obuf, str, 4);
660 obuf[4] = '\0';
661 str += 3;
662 j -= 3;
663 o = obuf;
664 break;
665 }
666 if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {
667 obuf[0] = '\\';
668 obuf[1] = 'u';
669 for (i = 0; i < 4; ++i)
670 obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);
671 obuf[6] = '\0';
672 o = obuf;
673 } else {
674 json_write_char(json, c);
675 continue;
676 }
677 break;
678 }
679
680 json_write_str(json, o);
681 }
682
683 json_write_char(json, '"');
684 }
685
686 static void
json_write_qstring(OSSL_JSON_ENC * json,const char * str)687 json_write_qstring(OSSL_JSON_ENC *json, const char *str)
688 {
689 json_write_qstring_inner(json, str, 0, 1);
690 }
691
692 static void
json_write_qstring_len(OSSL_JSON_ENC * json,const char * str,size_t str_len)693 json_write_qstring_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
694 {
695 json_write_qstring_inner(json, str, str_len, 0);
696 }
697
ossl_json_str(OSSL_JSON_ENC * json,const char * str)698 void ossl_json_str(OSSL_JSON_ENC *json, const char *str)
699 {
700 if (!json_pre_item(json))
701 return;
702
703 json_write_qstring(json, str);
704 json_post_item(json);
705 }
706
ossl_json_str_len(OSSL_JSON_ENC * json,const char * str,size_t str_len)707 void ossl_json_str_len(OSSL_JSON_ENC *json, const char *str, size_t str_len)
708 {
709 if (!json_pre_item(json))
710 return;
711
712 json_write_qstring_len(json, str, str_len);
713 json_post_item(json);
714 }
715
716 /*
717 * Encode binary data as a lowercase hex string. data_len is the data length in
718 * bytes.
719 */
ossl_json_str_hex(OSSL_JSON_ENC * json,const void * data,size_t data_len)720 void ossl_json_str_hex(OSSL_JSON_ENC *json, const void *data, size_t data_len)
721 {
722 const unsigned char *b = data, *end = b + data_len;
723 unsigned char c;
724
725 if (!json_pre_item(json))
726 return;
727
728 json_write_char(json, '"');
729
730 for (; b < end; ++b) {
731 c = *b;
732 json_write_char(json, hex_digit(c >> 4));
733 json_write_char(json, hex_digit(c & 0x0F));
734 }
735
736 json_write_char(json, '"');
737 json_post_item(json);
738 }
739