From ba3e969b3697ee63e3d71a45fac27e2c3a9b4797 Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Tue, 1 Aug 2023 15:39:05 +0100 Subject: [PATCH 1/7] Implement utf-8 validation function Signed-off-by: Agathiyan Bragadeesh --- library/x509_create.c | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/library/x509_create.c b/library/x509_create.c index 1c489a3ca5..956dbe70fb 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -232,6 +232,81 @@ static int parse_attribute_value_der_encoded(const char *s, return 0; } +static int validate_utf_8(unsigned char *data, size_t len) { + unsigned char *end = data + len; + int i, n; + int utf_tails; + unsigned char *d; + + for(d = data; d < end; d++) { + if ((0x00 <= *d) && (*d <= 0x7F)) { + utf_tails = 0; + } + else if ((0xC2 <= *d) && (*d <= 0xDF)) { + utf_tails = 1; + } + else if (((0xE1 <= *d) && (*d <= 0xEC)) || ((0xEE <= *d) && (*d <= 0xEF))) { + utf_tails = 2; + } + else if (0xE0 == *d) { + if(d + 1 >= end) { + return -1; + } + d++; + if(!((0xA0 <= *d) && (*d <= 0xBF))) { + return -1; + } + utf_tails = 1; + } + else if (0xED == *d) { + if(d + 1 >= end) { + return -1; + } + d++; + if(!((0x80 <= *d) && (*d <= 0x9F))) { + return -1; + } + utf_tails = 1; + } + else if ((0xF1 <= *d) && (*d <= 0xF3)) { + utf_tails = 3; + } + else if (0xF0 == *d) { + if(d + 1 >= end) { + return -1; + } + d++; + if(!((0x90 <= *d) && (*d <= 0xBF))) { + return -1; + } + utf_tails = 2; + } + else if (0xF4 == *d) { + if(d + 1 >= end) { + return -1; + } + d++; + if(!((0x80 <= *d) && (*d <= 0x8F))) { + return -1; + } + utf_tails = 2; + } + else { + return -1; + } + + for(i = 0; i < utf_tails; i++) { + if(d + 1 >= end) { + return -1; + } + d++; + if(!((0x80 <= *d) && (*d <= 0xBF))) { + return -1; + } + } + } +} + int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name) { int ret = MBEDTLS_ERR_X509_INVALID_NAME; From dc7ac9db499262b5ec5f0fb4c8e5c8db0e476709 Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Mon, 7 Aug 2023 12:17:07 +0100 Subject: [PATCH 2/7] Add alternative utf8 validator function This works by parsing out the code point represented by the utf sequence and then checking bounds, rather than using the ABNF. Signed-off-by: Agathiyan Bragadeesh --- library/x509_create.c | 106 ++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/library/x509_create.c b/library/x509_create.c index 956dbe70fb..f658521015 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -232,81 +232,127 @@ static int parse_attribute_value_der_encoded(const char *s, return 0; } -static int validate_utf_8(unsigned char *data, size_t len) { +static int validate_utf_8(unsigned char *data, size_t len) +{ unsigned char *end = data + len; int i, n; int utf_tails; unsigned char *d; - for(d = data; d < end; d++) { + for (d = data; d < end; d++) { if ((0x00 <= *d) && (*d <= 0x7F)) { utf_tails = 0; - } - else if ((0xC2 <= *d) && (*d <= 0xDF)) { + } else if ((0xC2 <= *d) && (*d <= 0xDF)) { utf_tails = 1; - } - else if (((0xE1 <= *d) && (*d <= 0xEC)) || ((0xEE <= *d) && (*d <= 0xEF))) { + } else if (((0xE1 <= *d) && (*d <= 0xEC)) || ((0xEE <= *d) && (*d <= 0xEF))) { utf_tails = 2; - } - else if (0xE0 == *d) { - if(d + 1 >= end) { + } else if (0xE0 == *d) { + if (d + 1 >= end) { return -1; } d++; - if(!((0xA0 <= *d) && (*d <= 0xBF))) { + if (!((0xA0 <= *d) && (*d <= 0xBF))) { return -1; } utf_tails = 1; - } - else if (0xED == *d) { - if(d + 1 >= end) { + } else if (0xED == *d) { + if (d + 1 >= end) { return -1; } d++; - if(!((0x80 <= *d) && (*d <= 0x9F))) { + if (!((0x80 <= *d) && (*d <= 0x9F))) { return -1; } utf_tails = 1; - } - else if ((0xF1 <= *d) && (*d <= 0xF3)) { + } else if ((0xF1 <= *d) && (*d <= 0xF3)) { utf_tails = 3; - } - else if (0xF0 == *d) { - if(d + 1 >= end) { + } else if (0xF0 == *d) { + if (d + 1 >= end) { return -1; } d++; - if(!((0x90 <= *d) && (*d <= 0xBF))) { + if (!((0x90 <= *d) && (*d <= 0xBF))) { return -1; } utf_tails = 2; - } - else if (0xF4 == *d) { - if(d + 1 >= end) { + } else if (0xF4 == *d) { + if (d + 1 >= end) { return -1; } d++; - if(!((0x80 <= *d) && (*d <= 0x8F))) { + if (!((0x80 <= *d) && (*d <= 0x8F))) { return -1; } utf_tails = 2; - } - else { + } else { return -1; } - - for(i = 0; i < utf_tails; i++) { - if(d + 1 >= end) { + + for (i = 0; i < utf_tails; i++) { + if (d + 1 >= end) { return -1; } d++; - if(!((0x80 <= *d) && (*d <= 0xBF))) { + if (!((0x80 <= *d) && (*d <= 0xBF))) { return -1; } } } } +static int validate_utf_8_2(unsigned char *data, size_t len) +{ + uint32_t code_point; + unsigned char *d; + unsigned char *end = data + len; + int utf_bytes, i; + + for (d = data; d < end; d++) { + code_point = 0; + if (*d & 0x80 == 0x00) { + utf_bytes = 1; + code_point = code_point | (*d & 0x3F); + } else if (*d & 0xE0 == 0xC0) { + utf_bytes = 2; + code_point = code_point | (uint32_t) (*d & 0x1F) << 6; + } else if (*d & 0xF0 == 0xE0) { + utf_bytes = 3; + code_point = code_point | (uint32_t) (*d & 0x0F) << 12; + } else if (*d & 0xF8 == 0xF0) { + utf_bytes = 4; + code_point = code_point | (uint32_t) (*d & 0x07) << 18; + } else { + return MBEDTLS_ERROR_C; + } + for (i = utf_bytes-1; i > 0; i--) { + if (d + 1 >= end) { + return -1; + } + d++; + code_point = code_point | (uint32_t) (*d & 0x3F) << (6 * (i-1)); + } + switch (utf_bytes) { + case 2: + if (!(0x80 < code_point && code_point < 0x7FF)) { + return MBEDTLS_ERROR_C; //bad encoding + } + break; + case 3: + if (!(0x800 < code_point && code_point < 0xD7FF) && + !(0xE000 < utf_bytes && utf_bytes < 0xFFFF)) { + return MBEDTLS_ERROR_C; //bad encoding + } + break; + case 4: + if (!(0x10000 < code_point && code_point < 0x10FFFF)) { + return MBEDTLS_ERROR_C; //bad encoding + } + break; + } + } + return 0; +} + int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name) { int ret = MBEDTLS_ERR_X509_INVALID_NAME; From 994085d06648271451aa06f1a14cca22e979716b Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Mon, 7 Aug 2023 16:34:43 +0100 Subject: [PATCH 3/7] Validate utf strings x509 Signed-off-by: Agathiyan Bragadeesh --- library/x509_create.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/x509_create.c b/library/x509_create.c index f658521015..b5e024545f 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -414,6 +414,11 @@ int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *nam tag = attr_descr->default_tag; } } + if (tag == MBEDTLS_ASN1_UTF8_STRING) { + if (validate_utf_8_2(data, data_len) != 0) { + return MBEDTLS_ERR_X509_INVALID_NAME; + } + } mbedtls_asn1_named_data *cur = mbedtls_asn1_store_named_data(head, (char *) oid.p, oid.len, From 9718084a11c011193bbc1231756642056ae9abc2 Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Wed, 23 Aug 2023 15:20:31 +0100 Subject: [PATCH 4/7] Remove duplicate utf validator Signed-off-by: Agathiyan Bragadeesh --- library/x509_create.c | 72 ++----------------------------------------- 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/library/x509_create.c b/library/x509_create.c index b5e024545f..c6d83b25b2 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -232,75 +232,7 @@ static int parse_attribute_value_der_encoded(const char *s, return 0; } -static int validate_utf_8(unsigned char *data, size_t len) -{ - unsigned char *end = data + len; - int i, n; - int utf_tails; - unsigned char *d; - - for (d = data; d < end; d++) { - if ((0x00 <= *d) && (*d <= 0x7F)) { - utf_tails = 0; - } else if ((0xC2 <= *d) && (*d <= 0xDF)) { - utf_tails = 1; - } else if (((0xE1 <= *d) && (*d <= 0xEC)) || ((0xEE <= *d) && (*d <= 0xEF))) { - utf_tails = 2; - } else if (0xE0 == *d) { - if (d + 1 >= end) { - return -1; - } - d++; - if (!((0xA0 <= *d) && (*d <= 0xBF))) { - return -1; - } - utf_tails = 1; - } else if (0xED == *d) { - if (d + 1 >= end) { - return -1; - } - d++; - if (!((0x80 <= *d) && (*d <= 0x9F))) { - return -1; - } - utf_tails = 1; - } else if ((0xF1 <= *d) && (*d <= 0xF3)) { - utf_tails = 3; - } else if (0xF0 == *d) { - if (d + 1 >= end) { - return -1; - } - d++; - if (!((0x90 <= *d) && (*d <= 0xBF))) { - return -1; - } - utf_tails = 2; - } else if (0xF4 == *d) { - if (d + 1 >= end) { - return -1; - } - d++; - if (!((0x80 <= *d) && (*d <= 0x8F))) { - return -1; - } - utf_tails = 2; - } else { - return -1; - } - - for (i = 0; i < utf_tails; i++) { - if (d + 1 >= end) { - return -1; - } - d++; - if (!((0x80 <= *d) && (*d <= 0xBF))) { - return -1; - } - } - } -} - -static int validate_utf_8_2(unsigned char *data, size_t len) +static int validate_utf8(unsigned char *data, size_t len) { uint32_t code_point; unsigned char *d; @@ -415,7 +347,7 @@ int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *nam } } if (tag == MBEDTLS_ASN1_UTF8_STRING) { - if (validate_utf_8_2(data, data_len) != 0) { + if (validate_utf8(data, data_len) != 0) { return MBEDTLS_ERR_X509_INVALID_NAME; } } From 12376e0bbbb03f7065431077d0e3146130ff866d Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Wed, 23 Aug 2023 15:54:59 +0100 Subject: [PATCH 5/7] Add changelog entry for UTF8 validation Signed-off-by: Agathiyan Bragadeesh --- ChangeLog.d/validate-utf8-in-fnd.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 ChangeLog.d/validate-utf8-in-fnd.txt diff --git a/ChangeLog.d/validate-utf8-in-fnd.txt b/ChangeLog.d/validate-utf8-in-fnd.txt new file mode 100644 index 0000000000..b226101acd --- /dev/null +++ b/ChangeLog.d/validate-utf8-in-fnd.txt @@ -0,0 +1,2 @@ +Features + * Validate UTF-8 strings in certificate Distinguished Names. \ No newline at end of file From e9c72fbc2e1d26c32f4c02f3761300743b330174 Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Thu, 24 Aug 2023 14:55:30 +0100 Subject: [PATCH 6/7] Add parantheses expressions in utf validator Signed-off-by: Agathiyan Bragadeesh --- library/x509_create.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/x509_create.c b/library/x509_create.c index c6d83b25b2..d02b526802 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -241,16 +241,16 @@ static int validate_utf8(unsigned char *data, size_t len) for (d = data; d < end; d++) { code_point = 0; - if (*d & 0x80 == 0x00) { + if ((*d & 0x80) == 0x00) { utf_bytes = 1; code_point = code_point | (*d & 0x3F); - } else if (*d & 0xE0 == 0xC0) { + } else if ((*d & 0xE0) == 0xC0) { utf_bytes = 2; code_point = code_point | (uint32_t) (*d & 0x1F) << 6; - } else if (*d & 0xF0 == 0xE0) { + } else if ((*d & 0xF0) == 0xE0) { utf_bytes = 3; code_point = code_point | (uint32_t) (*d & 0x0F) << 12; - } else if (*d & 0xF8 == 0xF0) { + } else if ((*d & 0xF8) == 0xF0) { utf_bytes = 4; code_point = code_point | (uint32_t) (*d & 0x07) << 18; } else { From f59f10f1d1d6954dfcd87f5ba76125620424c380 Mon Sep 17 00:00:00 2001 From: Agathiyan Bragadeesh Date: Tue, 12 Sep 2023 15:56:27 +0100 Subject: [PATCH 7/7] Add error returns in utf validator Signed-off-by: Agathiyan Bragadeesh --- library/x509_create.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/x509_create.c b/library/x509_create.c index d02b526802..a0d04a76ab 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -254,7 +254,7 @@ static int validate_utf8(unsigned char *data, size_t len) utf_bytes = 4; code_point = code_point | (uint32_t) (*d & 0x07) << 18; } else { - return MBEDTLS_ERROR_C; + return MBEDTLS_ERR_X509_INVALID_NAME; } for (i = utf_bytes-1; i > 0; i--) { if (d + 1 >= end) { @@ -266,18 +266,18 @@ static int validate_utf8(unsigned char *data, size_t len) switch (utf_bytes) { case 2: if (!(0x80 < code_point && code_point < 0x7FF)) { - return MBEDTLS_ERROR_C; //bad encoding + return MBEDTLS_ERR_X509_INVALID_NAME; //bad encoding } break; case 3: if (!(0x800 < code_point && code_point < 0xD7FF) && !(0xE000 < utf_bytes && utf_bytes < 0xFFFF)) { - return MBEDTLS_ERROR_C; //bad encoding + return MBEDTLS_ERR_X509_INVALID_NAME; //bad encoding } break; case 4: if (!(0x10000 < code_point && code_point < 0x10FFFF)) { - return MBEDTLS_ERROR_C; //bad encoding + return MBEDTLS_ERR_X509_INVALID_NAME; //bad encoding } break; }