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