]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - ssl/quic/json_enc.c
Copyright year updates
[thirdparty/openssl.git] / ssl / quic / json_enc.c
index da698c2222bcf514c040bf241babf14f78f99607..3e9f715dfaca7d820b8a733655e8c5ff1506cb31 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -9,6 +9,7 @@
 
 #include "internal/json_enc.h"
 #include "internal/nelem.h"
+#include "internal/numbers.h"
 #include <string.h>
 #include <math.h>
 
@@ -16,7 +17,7 @@
  * wbuf
  * ====
  */
-static int wbuf_flush(struct json_write_buf *wbuf);
+static int wbuf_flush(struct json_write_buf *wbuf, int full);
 
 static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)
 {
@@ -58,7 +59,7 @@ static ossl_inline size_t wbuf_avail(struct json_write_buf *wbuf)
 static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)
 {
     if (wbuf_avail(wbuf) == 0) {
-        if (!wbuf_flush(wbuf))
+        if (!wbuf_flush(wbuf, /*full=*/0))
             return 0;
     }
 
@@ -81,7 +82,7 @@ static int wbuf_write_str(struct json_write_buf *wbuf, const char *s)
 }
 
 /* Flush write buffer, returning 0 on I/O failure. */
-static int wbuf_flush(struct json_write_buf *wbuf)
+static int wbuf_flush(struct json_write_buf *wbuf, int full)
 {
     size_t written = 0, total_written = 0;
 
@@ -101,6 +102,10 @@ static int wbuf_flush(struct json_write_buf *wbuf)
     }
 
     wbuf->cur = 0;
+
+    if (full)
+        (void)BIO_flush(wbuf->bio); /* best effort */
+
     return 1;
 }
 
@@ -270,7 +275,7 @@ int ossl_json_reset(OSSL_JSON_ENC *json)
 
 int ossl_json_flush(OSSL_JSON_ENC *json)
 {
-    return wbuf_flush(&json->wbuf);
+    return wbuf_flush(&json->wbuf, /*full=*/1);
 }
 
 int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)
@@ -598,10 +603,19 @@ void ossl_json_f64(OSSL_JSON_ENC *json, double value)
     if (!json_pre_item(json))
         return;
 
-    if (isnan(value) || isinf(value)) {
-        json_raise_error(json);
-        return;
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    {
+        int checks = isnan(value);
+# if !defined(OPENSSL_SYS_VMS)
+        checks |= isinf(value);
+# endif
+
+        if (checks) {
+            json_raise_error(json);
+            return;
+        }
     }
+#endif
 
     BIO_snprintf(buf, sizeof(buf), "%1.17g", value);
     json_write_str(json, buf);
@@ -622,6 +636,7 @@ json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
                          int nul_term)
 {
     char c, *o, obuf[7];
+    unsigned char *u_str;
     int i;
     size_t j;
 
@@ -630,9 +645,9 @@ json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
 
     json_write_char(json, '"');
 
-    for (j = 0; (nul_term && *str != '\0')
-                || (!nul_term && j < str_len); ++str, ++j) {
+    for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {
         c = *str;
+        u_str = (unsigned char*)str;
         switch (c) {
         case '\n': o = "\\n"; break;
         case '\r': o = "\\r"; break;
@@ -642,15 +657,45 @@ json_write_qstring_inner(OSSL_JSON_ENC *json, const char *str, size_t str_len,
         case '"': o = "\\\""; break;
         case '\\': o = "\\\\"; break;
         default:
-            if ((unsigned char)c >= 0x80) {
-                json_raise_error(json);
-                return;
+            /* valid UTF-8 sequences according to RFC-3629 */
+            if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2
+                    && u_str[1] >= 0x80 && u_str[1] <= 0xbf) {
+                memcpy(obuf, str, 2);
+                obuf[2] = '\0';
+                str++, j--;
+                o = obuf;
+                break;
+            }
+            if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3
+                    && u_str[1] >= 0x80 && u_str[1] <= 0xbf
+                    && u_str[2] >= 0x80 && u_str[2] <= 0xbf
+                    && !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)
+                    && !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {
+                memcpy(obuf, str, 3);
+                obuf[3] = '\0';
+                str += 2;
+                j -= 2;
+                o = obuf;
+                break;
+            }
+            if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4
+                    && u_str[1] >= 0x80 && u_str[1] <= 0xbf
+                    && u_str[2] >= 0x80 && u_str[2] <= 0xbf
+                    && u_str[3] >= 0x80 && u_str[3] <= 0xbf
+                    && !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)
+                    && !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {
+                memcpy(obuf, str, 4);
+                obuf[4] = '\0';
+                str += 3;
+                j -= 3;
+                o = obuf;
+                break;
             }
-            if ((unsigned char)c < 0x20 || (unsigned char)c >= 0x7f) {
+            if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {
                 obuf[0] = '\\';
                 obuf[1] = 'u';
                 for (i = 0; i < 4; ++i)
-                    obuf[2 + i] = hex_digit((c >> ((3 - i) * 4)) & 0x0F);
+                    obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);
                 obuf[6] = '\0';
                 o = obuf;
             } else {