Browse Source

Try to fix intermittent CI failures in quic_multistream test

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23807)
Bernd Edlinger 1 month ago
parent
commit
bc3eb7b527
2 changed files with 58 additions and 9 deletions
  1. 38 7
      ssl/quic/json_enc.c
  2. 20 2
      test/json_test.c

+ 38 - 7
ssl/quic/json_enc.c

@@ -626,6 +626,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;
 
@@ -634,9 +635,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;
@@ -646,15 +647,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 {

+ 20 - 2
test/json_test.c

@@ -427,8 +427,23 @@ END_SCRIPT_EXPECTING_S("{\"x\":")
 
 BEGIN_SCRIPT(err_utf8, "error test: only basic ASCII supported", 0)
     OPJ_STR("\x80")
-    OP_ASSERT_ERROR(1)
-END_SCRIPT_EXPECTING_S("\"")
+    OP_ASSERT_ERROR(0)
+END_SCRIPT_EXPECTING_S("\"\\u0080\"")
+
+BEGIN_SCRIPT(utf8_2, "test: valid UTF-8 2byte supported", 0)
+    OPJ_STR("low=\xc2\x80, high=\xdf\xbf")
+    OP_ASSERT_ERROR(0)
+END_SCRIPT_EXPECTING_S("\"low=\xc2\x80, high=\xdf\xbf\"")
+
+BEGIN_SCRIPT(utf8_3, "test: valid UTF-8 3byte supported", 0)
+    OPJ_STR("low=\xe0\xa0\x80, high=\xef\xbf\xbf")
+    OP_ASSERT_ERROR(0)
+END_SCRIPT_EXPECTING_S("\"low=\xe0\xa0\x80, high=\xef\xbf\xbf\"")
+
+BEGIN_SCRIPT(utf8_4, "test: valid UTF-8 4byte supported", 0)
+    OPJ_STR("low=\xf0\x90\xbf\xbf, high=\xf4\x8f\xbf\xbf")
+    OP_ASSERT_ERROR(0)
+END_SCRIPT_EXPECTING_S("\"low=\xf0\x90\xbf\xbf, high=\xf4\x8f\xbf\xbf\"")
 
 BEGIN_SCRIPT(ijson_int, "I-JSON: large integer", OSSL_JSON_FLAG_IJSON)
     OPJ_BEGIN_A()
@@ -508,6 +523,9 @@ static const info_func scripts[] = {
     SCRIPT(err_obj_multi_key)
     SCRIPT(err_obj_no_value)
     SCRIPT(err_utf8)
+    SCRIPT(utf8_2)
+    SCRIPT(utf8_3)
+    SCRIPT(utf8_4)
     SCRIPT(ijson_int)
     SCRIPT(multi_item)
     SCRIPT(seq)