Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/ssl/quic/json_enc.c
48266 views
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
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
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
40
static void wbuf_set0_bio(struct json_write_buf *wbuf, BIO *bio)
41
{
42
wbuf->bio = bio;
43
}
44
45
/* Empty write buffer. */
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. */
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. */
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
*/
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. */
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
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. */
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
*/
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
*/
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
221
static ossl_inline int in_ijson(const OSSL_JSON_ENC *json)
222
{
223
return (json->flags & OSSL_JSON_FLAG_IJSON) != 0;
224
}
225
226
static ossl_inline int in_seq(const OSSL_JSON_ENC *json)
227
{
228
return (json->flags & OSSL_JSON_FLAG_SEQ) != 0;
229
}
230
231
static ossl_inline int in_pretty(const OSSL_JSON_ENC *json)
232
{
233
return (json->flags & OSSL_JSON_FLAG_PRETTY) != 0;
234
}
235
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
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
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
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
275
int ossl_json_flush(OSSL_JSON_ENC *json)
276
{
277
return wbuf_flush(&json->wbuf, /*full=*/1);
278
}
279
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
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
299
static void json_raise_error(OSSL_JSON_ENC *json)
300
{
301
json->error = 1;
302
}
303
304
static void json_undefer(OSSL_JSON_ENC *json)
305
{
306
if (!json->defer_indent)
307
return;
308
309
json_indent(json);
310
}
311
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
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
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
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
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
*/
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
*/
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. */
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(). */
459
void ossl_json_object_end(OSSL_JSON_ENC *json)
460
{
461
composite_end(json, 0, '}');
462
}
463
464
/* Begin a new JSON array. */
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(). */
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
*/
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. */
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
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. */
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
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. */
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
*/
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
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
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
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
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
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
*/
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
740