Escape hexpairs characters RFC 4514

Converts none ascii to escaped hexpairs in mbedtls_x509_dn_gets and
interprets hexpairs in mbedtls_x509_string_to_names.

Signed-off-by: Agathiyan Bragadeesh <agathiyan.bragadeesh2@arm.com>
diff --git a/library/x509.c b/library/x509.c
index 2764ba6..5025d77 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -810,6 +810,12 @@
     return 0;
 }
 
+/* Converts only the 4 least significant bits */
+static char x509_int_to_hexdigit(int i)
+{
+    return (i < 10) ? (i | 0x30) : ((i - 9) | 0x40);
+}
+
 /*
  * Store the name in printable form into buf; no more
  * than size characters will be written
@@ -857,9 +863,9 @@
             c = name->val.p[i];
             // Special characters requiring escaping, RFC 4514 Section 2.4
             if (c) {
-                if (strchr(",=+<>;\"\\+", c) || 
-                ((i == 0) && strchr("# ", c)) ||
-                ((i == name->val.len-1 ) && (c == ' '))) {
+                if (strchr(",=+<>;\"\\+", c) ||
+                    ((i == 0) && strchr("# ", c)) ||
+                    ((i == name->val.len-1) && (c == ' '))) {
                     if (j + 1 >= sizeof(s) - 1) {
                         return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
                     }
@@ -867,7 +873,14 @@
                 }
             }
             if (c < 32 || c >= 127) {
-                s[j] = '?';
+                if (j + 3 >= sizeof(s) - 1) {
+                    return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
+                }
+                s[j++] = '\\';
+                char lowbits = (c & 0x0F);
+                char highbits = c>>4;
+                s[j++] = x509_int_to_hexdigit(highbits);
+                s[j] = x509_int_to_hexdigit(lowbits);
             } else {
                 s[j] = c;
             }
diff --git a/library/x509_create.c b/library/x509_create.c
index 170a6bc..9652a20 100644
--- a/library/x509_create.c
+++ b/library/x509_create.c
@@ -123,6 +123,16 @@
     return cur;
 }
 
+static int x509_is_char_hex(char c)
+{
+    return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
+static int x509_hex_to_int(char c)
+{
+    return ((c & 0x40) ? (c + 9) : c) & 0x0F;
+}
+
 int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name)
 {
     int ret = MBEDTLS_ERR_X509_INVALID_NAME;
@@ -131,6 +141,7 @@
     const char *oid = NULL;
     const x509_attr_descriptor_t *attr_descr = NULL;
     int in_tag = 1;
+    int hexpair = 0;
     char data[MBEDTLS_X509_MAX_DN_NAME_SIZE];
     char *d = data;
 
@@ -154,7 +165,11 @@
             c++;
 
             /* Check for valid escaped characters in RFC 4514 in Section 3*/
-            if (c == end || !strchr(" ,=+<>#;\"\\+", *c)) {
+            if (c + 1 < end && x509_is_char_hex(*c) && x509_is_char_hex(*(c+1))) {
+                hexpair = 1;
+                *(d++) = (x509_hex_to_int(*c) << 4) + x509_hex_to_int(*(c+1));
+                c++;
+            } else if (c == end || !strchr(" ,=+<>#;\"\\+", *c)) {
                 ret = MBEDTLS_ERR_X509_INVALID_NAME;
                 goto exit;
             }
@@ -182,7 +197,7 @@
             ret = 0;
         }
 
-        if (!in_tag && s != c + 1) {
+        if (!hexpair && !in_tag && s != c + 1) {
             *(d++) = *c;
 
             if (d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE) {
@@ -191,6 +206,7 @@
             }
         }
 
+        hexpair = 0;
         c++;
     }