Coverage Report

Created: 2025-08-28 07:07

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