x509: fix endianness and input data format for x509write_crt_set_serial_new

Signed-off-by: Valerio Setti <vsetti@baylibre.com>
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 25d4a7b..6817850 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -1022,17 +1022,17 @@
  * \brief           Set the serial number for a Certificate.
  *
  * \param ctx               CRT context to use
- * \param serial_buff       Input buffer containing the serial number in big
- *                          endian format
+ * \param serial_buff       A raw array of bytes containing the serial number
+ *                          in big endian format
  * \param serial_buff_len   Length of the previous input buffer buffer
  *
  * \return          0 if successful, or
- *                  MBEDTLS_ERR_X509_BAD_INPUT_DATA if the provided input buffer:
- *                  - is too big (longer than MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN)
- *                  - contains invalid chars
+ *                  MBEDTLS_ERR_X509_BAD_INPUT_DATA if the provided input buffer
+ *                  is too big (longer than MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN)
  */
 int mbedtls_x509write_crt_set_serial_new( mbedtls_x509write_cert *ctx,
-                                char* serial_buff, size_t serial_buff_len );
+                                        unsigned char* serial_buff,
+                                        size_t serial_buff_len );
 
 /**
  * \brief           Set the validity period for a Certificate
diff --git a/library/x509write_crt.c b/library/x509write_crt.c
index 04226b8..55f22d7 100644
--- a/library/x509write_crt.c
+++ b/library/x509write_crt.c
@@ -120,40 +120,23 @@
     if( ret < 0 )
         return ret;
     
-    /* Reverse the string since "tmp" is in big endian format */
-    for( int i=0; i<MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN; i++ )
-        ctx->serial[i] = tmp[MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN - 1 - i];
+    /* Copy data to the internal structure skipping leading zeros */
+    memcpy(ctx->serial, &tmp[MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN - tmp_len],
+            tmp_len);
 
     return( 0 );
 }
 #endif // MBEDTLS_BIGNUM_C && !MBEDTLS_DEPRECATED_REMOVED
 
 int mbedtls_x509write_crt_set_serial_new( mbedtls_x509write_cert *ctx,
-                                char* serial_buff, size_t serial_buff_len)
+                                        unsigned char* serial_buff,
+                                        size_t serial_buff_len)
 {
-    int i, j;
-    char c;
-    unsigned char val;
-
     if( serial_buff_len > MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN )
         return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
 
-    /* Store data in little endian format */
-    for( i = 0, j = serial_buff_len - 1; j == 0; i++, j-- )
-    {
-        c = serial_buff[j];
-        if( c >= 0x30 && c <= 0x39 )
-            val = c - 0x30;
-        else if( c >= 0x41 && c <= 0x46 )
-            val = c - 0x37;
-        else if( c >= 0x61 && c <= 0x66 )
-            val = c - 0x57;
-        else
-            return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
-
-        ctx->serial[i] = val;
-    }
-    ctx->serial_len = i;
+    ctx->serial_len = serial_buff_len;
+    memcpy(ctx->serial, serial_buff, serial_buff_len);
 
     return 0;
 }
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index f9d5102..c9bd34b 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -235,6 +235,41 @@
     return( 0 );
 }
 
+/*
+ * Convert the input "in_buff" string to a raw byte array "out_buff". The amount
+ * of converted data is returned on "written_data".
+ */
+static int parse_serial( const char* in_buff, size_t in_buff_len,
+                    unsigned char* out_buff, size_t out_buff_len,
+                    size_t *written_data )
+{
+    char c;
+    unsigned char val;
+    int i;
+
+    if( out_buff_len < in_buff_len )
+        return( -1 );
+
+    *written_data = 0;
+
+    for( i = 0; i < (int) in_buff_len; i++, (*written_data)++ )
+    {
+        c = in_buff[i];
+        if( c >= 0x30 && c <= 0x39 )
+            val = c - 0x30;
+        else if( c >= 0x41 && c <= 0x46 )
+            val = c - 0x37;
+        else if( c >= 0x61 && c <= 0x66 )
+            val = c - 0x57;
+        else
+            return( -1 );
+
+        out_buff[i] = val;
+    }
+
+    return( 0 );
+}
+
 int main( int argc, char *argv[] )
 {
     int ret = 1;
@@ -252,7 +287,8 @@
     mbedtls_x509_csr csr;
 #endif
     mbedtls_x509write_cert crt;
-    mbedtls_mpi serial;
+    unsigned char serial[MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN];
+    size_t serial_len;
     mbedtls_asn1_sequence *ext_key_usage;
     mbedtls_entropy_context entropy;
     mbedtls_ctr_drbg_context ctr_drbg;
@@ -264,7 +300,6 @@
     mbedtls_x509write_crt_init( &crt );
     mbedtls_pk_init( &loaded_issuer_key );
     mbedtls_pk_init( &loaded_subject_key );
-    mbedtls_mpi_init( &serial );
     mbedtls_ctr_drbg_init( &ctr_drbg );
     mbedtls_entropy_init( &entropy );
 #if defined(MBEDTLS_X509_CSR_PARSE_C)
@@ -559,16 +594,6 @@
     mbedtls_printf( "  . Reading serial number..." );
     fflush( stdout );
 
-#if defined(MBEDTLS_BIGNUM_C)
-    if( ( ret = mbedtls_mpi_read_string( &serial, 10, opt.serial ) ) != 0 )
-    {
-        mbedtls_strerror( ret, buf, sizeof(buf) );
-        mbedtls_printf( " failed\n  !  mbedtls_mpi_read_string "
-                        "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
-        goto exit;
-    }
-#endif
-
     mbedtls_printf( " ok\n" );
 
     // Parse issuer certificate if present
@@ -723,18 +748,13 @@
     mbedtls_x509write_crt_set_version( &crt, opt.version );
     mbedtls_x509write_crt_set_md_alg( &crt, opt.md );
 
-#if defined(MBEDTLS_BIGNUM_C) && !defined(MBEDTLS_DEPRECATED_REMOVED)
-    ret = mbedtls_x509write_crt_set_serial( &crt, &serial );
-    if( ret != 0 )
+    if( parse_serial( opt.serial, strlen( opt.serial ),
+                    serial, sizeof( serial ), &serial_len ) < 0 )
     {
-        mbedtls_strerror( ret, buf, sizeof(buf) );
-        mbedtls_printf( " failed\n  !  mbedtls_x509write_crt_set_serial "
-                        "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+        mbedtls_printf( " failed\n  !  Unable to parse serial\n\n" );
         goto exit;
     }
-#else
-    ret = mbedtls_x509write_crt_set_serial_new( &crt, opt.serial,
-                                                strlen( opt.serial ) );
+    ret = mbedtls_x509write_crt_set_serial_new( &crt, serial, serial_len );
     if( ret != 0 )
     {
         mbedtls_strerror( ret, buf, sizeof(buf) );
@@ -742,7 +762,6 @@
                         "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
         goto exit;
     }
-#endif
 
     ret = mbedtls_x509write_crt_set_validity( &crt, opt.not_before, opt.not_after );
     if( ret != 0 )
@@ -893,7 +912,6 @@
     mbedtls_x509write_crt_free( &crt );
     mbedtls_pk_free( &loaded_subject_key );
     mbedtls_pk_free( &loaded_issuer_key );
-    mbedtls_mpi_free( &serial );
     mbedtls_ctr_drbg_free( &ctr_drbg );
     mbedtls_entropy_free( &entropy );