Merge pull request #8182 from daverodgman/asn1write-size

Reduce code size in mbedtls_asn1_write_len
diff --git a/library/asn1write.c b/library/asn1write.c
index 4123ac3..2e9b98a 100644
--- a/library/asn1write.c
+++ b/library/asn1write.c
@@ -28,68 +28,40 @@
 
 #include "mbedtls/platform.h"
 
+#if defined(MBEDTLS_ASN1_PARSE_C)
+#include "mbedtls/asn1.h"
+#endif
+
 int mbedtls_asn1_write_len(unsigned char **p, const unsigned char *start, size_t len)
 {
-    if (len < 0x80) {
-        if (*p - start < 1) {
-            return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
-        }
-
-        *--(*p) = (unsigned char) len;
-        return 1;
-    }
-
-    if (len <= 0xFF) {
-        if (*p - start < 2) {
-            return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
-        }
-
-        *--(*p) = (unsigned char) len;
-        *--(*p) = 0x81;
-        return 2;
-    }
-
-    if (len <= 0xFFFF) {
-        if (*p - start < 3) {
-            return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
-        }
-
-        *--(*p) = MBEDTLS_BYTE_0(len);
-        *--(*p) = MBEDTLS_BYTE_1(len);
-        *--(*p) = 0x82;
-        return 3;
-    }
-
-    if (len <= 0xFFFFFF) {
-        if (*p - start < 4) {
-            return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
-        }
-
-        *--(*p) = MBEDTLS_BYTE_0(len);
-        *--(*p) = MBEDTLS_BYTE_1(len);
-        *--(*p) = MBEDTLS_BYTE_2(len);
-        *--(*p) = 0x83;
-        return 4;
-    }
-
-    int len_is_valid = 1;
 #if SIZE_MAX > 0xFFFFFFFF
-    len_is_valid = (len <= 0xFFFFFFFF);
+    if (len > 0xFFFFFFFF) {
+        return MBEDTLS_ERR_ASN1_INVALID_LENGTH;
+    }
 #endif
-    if (len_is_valid) {
-        if (*p - start < 5) {
-            return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
-        }
 
-        *--(*p) = MBEDTLS_BYTE_0(len);
-        *--(*p) = MBEDTLS_BYTE_1(len);
-        *--(*p) = MBEDTLS_BYTE_2(len);
-        *--(*p) = MBEDTLS_BYTE_3(len);
-        *--(*p) = 0x84;
-        return 5;
+    int required = 1;
+
+    if (len >= 0x80) {
+        for (size_t l = len; l != 0; l >>= 8) {
+            required++;
+        }
     }
 
-    return MBEDTLS_ERR_ASN1_INVALID_LENGTH;
+    if (required > (*p - start)) {
+        return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
+    }
+
+    do {
+        *--(*p) = MBEDTLS_BYTE_0(len);
+        len >>= 8;
+    } while (len);
+
+    if (required > 1) {
+        *--(*p) = (unsigned char) (0x80 + required - 1);
+    }
+
+    return required;
 }
 
 int mbedtls_asn1_write_tag(unsigned char **p, const unsigned char *start, unsigned char tag)
@@ -105,6 +77,19 @@
 #endif /* MBEDTLS_ASN1_WRITE_C || MBEDTLS_X509_USE_C */
 
 #if defined(MBEDTLS_ASN1_WRITE_C)
+static int mbedtls_asn1_write_len_and_tag(unsigned char **p,
+                                          const unsigned char *start,
+                                          size_t len,
+                                          unsigned char tag)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
+    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, tag));
+
+    return (int) len;
+}
+
 int mbedtls_asn1_write_raw_buffer(unsigned char **p, const unsigned char *start,
                                   const unsigned char *buf, size_t size)
 {
@@ -156,10 +141,7 @@
         len += 1;
     }
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_INTEGER));
-
-    ret = (int) len;
+    ret = mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_INTEGER);
 
 cleanup:
     return ret;
@@ -168,15 +150,9 @@
 
 int mbedtls_asn1_write_null(unsigned char **p, const unsigned char *start)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t len = 0;
-
     // Write NULL
     //
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, 0));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_NULL));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, 0, MBEDTLS_ASN1_NULL);
 }
 
 int mbedtls_asn1_write_oid(unsigned char **p, const unsigned char *start,
@@ -187,10 +163,7 @@
 
     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
                                                             (const unsigned char *) oid, oid_len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OID));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_OID);
 }
 
 int mbedtls_asn1_write_algorithm_identifier(unsigned char **p, const unsigned char *start,
@@ -217,17 +190,12 @@
 
     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start,
-                                                     MBEDTLS_ASN1_CONSTRUCTED |
-                                                     MBEDTLS_ASN1_SEQUENCE));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len,
+                                          MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
 }
 
 int mbedtls_asn1_write_bool(unsigned char **p, const unsigned char *start, int boolean)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t len = 0;
 
     if (*p - start < 1) {
@@ -237,15 +205,11 @@
     *--(*p) = (boolean) ? 255 : 0;
     len++;
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_BOOLEAN));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_BOOLEAN);
 }
 
 static int asn1_write_tagged_int(unsigned char **p, const unsigned char *start, int val, int tag)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t len = 0;
 
     do {
@@ -265,10 +229,7 @@
         len += 1;
     }
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, tag));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len, tag);
 }
 
 int mbedtls_asn1_write_int(unsigned char **p, const unsigned char *start, int val)
@@ -291,10 +252,7 @@
                                                             (const unsigned char *) text,
                                                             text_len));
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, tag));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len, tag);
 }
 
 int mbedtls_asn1_write_utf8_string(unsigned char **p, const unsigned char *start,
@@ -363,7 +321,6 @@
 int mbedtls_asn1_write_bitstring(unsigned char **p, const unsigned char *start,
                                  const unsigned char *buf, size_t bits)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t len = 0;
     size_t unused_bits, byte_len;
 
@@ -387,10 +344,7 @@
     /* Write unused bits */
     *--(*p) = (unsigned char) unused_bits;
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_BIT_STRING));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_BIT_STRING);
 }
 
 int mbedtls_asn1_write_octet_string(unsigned char **p, const unsigned char *start,
@@ -401,13 +355,11 @@
 
     MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start, buf, size));
 
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OCTET_STRING));
-
-    return (int) len;
+    return mbedtls_asn1_write_len_and_tag(p, start, len, MBEDTLS_ASN1_OCTET_STRING);
 }
 
 
+#if !defined(MBEDTLS_ASN1_PARSE_C)
 /* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(),
  * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */
 static mbedtls_asn1_named_data *asn1_find_named_data(
@@ -425,6 +377,10 @@
 
     return list;
 }
+#else
+#define asn1_find_named_data(list, oid, len) \
+    ((mbedtls_asn1_named_data *) mbedtls_asn1_find_named_data(list, oid, len))
+#endif
 
 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(
     mbedtls_asn1_named_data **head,