Merge pull request #6579 from gilles-peskine-arm/negative-zero-from-add-2.28

Backport 2.28: Fix negative zero from bignum add/subtract
diff --git a/ChangeLog.d/fix_dh_genprime_error_reporting.txt b/ChangeLog.d/fix_dh_genprime_error_reporting.txt
new file mode 100644
index 0000000..1c98947
--- /dev/null
+++ b/ChangeLog.d/fix_dh_genprime_error_reporting.txt
@@ -0,0 +1,4 @@
+Bugfix
+   * Fix bug in error reporting in dh_genprime.c where upon failure,
+     the error code returned by mbedtls_mpi_write_file() is overwritten
+     and therefore not printed.
diff --git a/library/ecp.c b/library/ecp.c
index 402d5de..80adc55 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -2051,7 +2051,7 @@
 
         int have_rng = 1;
 #if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
-        if( f_rng == 0 )
+        if( f_rng == NULL )
             have_rng = 0;
 #endif
         if( have_rng )
@@ -2190,7 +2190,7 @@
      */
     int have_rng = 1;
 #if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
-    if( f_rng == 0 )
+    if( f_rng == NULL )
         have_rng = 0;
 #endif
     if( have_rng )
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 5df2758..3475aa4 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1089,11 +1089,6 @@
      * RFC 5077 section 3.4: "When presenting a ticket, the client MAY
      * generate and include a Session ID in the TLS ClientHello."
      */
-    renegotiating = 0;
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-    if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE )
-        renegotiating = 1;
-#endif
     if( !renegotiating )
     {
         if( ssl->session_negotiate->ticket != NULL &&
@@ -1209,11 +1204,6 @@
     /*
      * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV
      */
-    renegotiating = 0;
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-    if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE )
-        renegotiating = 1;
-#endif
     if( !renegotiating )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding EMPTY_RENEGOTIATION_INFO_SCSV" ) );
@@ -2065,6 +2055,30 @@
 }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+static int is_compression_bad( mbedtls_ssl_context *ssl, unsigned char comp )
+{
+    int bad_comp = 0;
+
+    /* Suppress warnings in some configurations */
+    (void) ssl;
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+    /* See comments in ssl_write_client_hello() */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+        comp != MBEDTLS_SSL_COMPRESS_NULL )
+        bad_comp = 1;
+#endif
+
+    if( comp != MBEDTLS_SSL_COMPRESS_NULL &&
+        comp != MBEDTLS_SSL_COMPRESS_DEFLATE )
+        bad_comp = 1;
+#else /* MBEDTLS_ZLIB_SUPPORT */
+    if( comp != MBEDTLS_SSL_COMPRESS_NULL )
+        bad_comp = 1;
+#endif/* MBEDTLS_ZLIB_SUPPORT */
+    return bad_comp;
+}
+
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
 {
@@ -2073,9 +2087,6 @@
     size_t ext_len;
     unsigned char *buf, *ext;
     unsigned char comp;
-#if defined(MBEDTLS_ZLIB_SUPPORT)
-    int accept_comp;
-#endif
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
     int renegotiation_info_seen = 0;
 #endif
@@ -2244,23 +2255,7 @@
      */
     comp = buf[37 + n];
 
-    int bad_comp = 0;
-#if defined(MBEDTLS_ZLIB_SUPPORT)
-    /* See comments in ssl_write_client_hello() */
-    accept_comp = 1;
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
-        accept_comp = 0;
-#endif
-
-    if( comp != MBEDTLS_SSL_COMPRESS_NULL &&
-        ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) )
-        bad_comp = 1;
-#else /* MBEDTLS_ZLIB_SUPPORT */
-    if( comp != MBEDTLS_SSL_COMPRESS_NULL )
-        bad_comp = 1;
-#endif/* MBEDTLS_ZLIB_SUPPORT */
-    if( bad_comp )
+    if( is_compression_bad( ssl, comp ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1,
             ( "server hello, bad compression: %d", comp ) );
@@ -2693,7 +2688,7 @@
     grp_id = ssl->handshake->ecdh_ctx.grp.id;
 #else
     grp_id = ssl->handshake->ecdh_ctx.grp_id;
-#endif
+#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */
 
     curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id );
     if( curve_info == NULL )
@@ -2704,17 +2699,14 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) );
 
-    int bad_params = 0;
 #if defined(MBEDTLS_ECP_C)
     if( mbedtls_ssl_check_curve( ssl, grp_id ) != 0 )
-        bad_params = 1;
+        return( -1 );
 #else
     if( ssl->handshake->ecdh_ctx.grp.nbits < 163 ||
         ssl->handshake->ecdh_ctx.grp.nbits > 521 )
-        bad_params = 1;
-#endif
-    if( bad_params )
         return( -1 );
+#endif /* MBEDTLS_ECP_C */
 
     MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx,
                             MBEDTLS_DEBUG_ECDH_QP );
@@ -3462,25 +3454,23 @@
 #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
         if( ssl->handshake->ecrs_enabled )
             rs_ctx = &ssl->handshake->ecrs_ctx.pk;
-#endif
+#endif /* MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED */
 
         if( ( ret = mbedtls_pk_verify_restartable( peer_pk,
                         md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
         {
-            int send_alert_msg = 1;
-#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
-            send_alert_msg = ( ret != MBEDTLS_ERR_ECP_IN_PROGRESS );
-#endif
-            if( send_alert_msg )
-                mbedtls_ssl_send_alert_message(
-                    ssl,
-                    MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                    MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
-            MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
 #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED)
             if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
-                ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
-#endif
+            {
+                MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
+                return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
+            }
+#endif /* MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED */
+            mbedtls_ssl_send_alert_message(
+                ssl,
+                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+            MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
             return( ret );
         }
 
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index e6abe85..8a57789 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -148,16 +148,22 @@
 
     int do_mbedtls_cipher_setup = 1;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    do_mbedtls_cipher_setup = 0;
-
     ret = mbedtls_cipher_setup_psa( &ctx->keys[0].ctx,
                                     cipher_info, TICKET_AUTH_TAG_BYTES );
-    if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
-        return( ret );
-    /* We don't yet expect to support all ciphers through PSA,
-     * so allow fallback to ordinary mbedtls_cipher_setup(). */
-    if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE )
-        do_mbedtls_cipher_setup = 1;
+
+    switch( ret )
+    {
+        case 0:
+            do_mbedtls_cipher_setup = 0;
+            break;
+        case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE:
+            /* We don't yet expect to support all ciphers through PSA,
+             * so allow fallback to ordinary mbedtls_cipher_setup(). */
+            do_mbedtls_cipher_setup = 1;
+            break;
+        default:
+            return( ret );
+    }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
     if( do_mbedtls_cipher_setup )
         if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) )
diff --git a/programs/pkey/dh_genprime.c b/programs/pkey/dh_genprime.c
index 51f6971..84f498e 100644
--- a/programs/pkey/dh_genprime.c
+++ b/programs/pkey/dh_genprime.c
@@ -161,8 +161,8 @@
         goto exit;
     }
 
-    if( ( ret = mbedtls_mpi_write_file( "P = ", &P, 16, fout ) != 0 ) ||
-        ( ret = mbedtls_mpi_write_file( "G = ", &G, 16, fout ) != 0 ) )
+    if( ( ( ret = mbedtls_mpi_write_file( "P = ", &P, 16, fout ) ) != 0 ) ||
+        ( ( ret = mbedtls_mpi_write_file( "G = ", &G, 16, fout ) ) != 0 ) )
     {
         mbedtls_printf( " failed\n  ! mbedtls_mpi_write_file returned %d\n\n", ret );
         fclose( fout );
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 94995ba..f249fb5 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -912,6 +912,11 @@
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA256
 all_final += server1.req.sha256
 
+server1.req.sha256.ext: server1.key
+	# Generating this with OpenSSL as a comparison point to test we're getting the same result
+	openssl req -new -out $@ -key $< -subj '/C=NL/O=PolarSSL/CN=PolarSSL Server 1' -sha256 -addext "extendedKeyUsage=serverAuth"
+all_final += server1.req.sha256.ext
+
 server1.req.sha384: server1.key
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA384
 all_final += server1.req.sha384
diff --git a/tests/data_files/server1.req.sha256.ext b/tests/data_files/server1.req.sha256.ext
new file mode 100644
index 0000000..3f26f09
--- /dev/null
+++ b/tests/data_files/server1.req.sha256.ext
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICpzCCAY8CAQAwPDELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRow
+GAYDVQQDDBFQb2xhclNTTCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKkCHz1AatVVU4v9Nu6CZS4VYV6Jv7joRZDb7ogWUtPxQ1BHlhJZ
+ZIdr/SvgRvlzvt3PkuGRW+1moG+JKXlFgNCDatVBQ3dfOXwJBEeCsFc5cO2j7BUZ
+HqgzCEfBBUKp/UzDtN/dBh9NEFFAZ3MTD0D4bYElXwqxU8YwfhU5rPla7n+SnqYF
+W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
+FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
+DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAmMCQGCSqGSIb3DQEJDjEX
+MBUwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAHi0yEGu
+Fh5tuLiLuT95UrRnly55+lTY9xchFiKtlcoEdSheybYxqk3JHuSSqojOFKZBlRdk
+oG6Azg56/aMHPWyvtCMSRQX4b+FgjeQsm9IfhYNMquQOxyPxm62vjuU3MfZIofXH
+hKdI6Ci2CDF4Fyvw50KBWniV38eE9+kjsvDLdXD3ESZJGhjjuFl8ReUiA2wdBTcP
+XEZaXUIc6B4tUnlPeqn/2zp4GBqqWzNZx6TXBpApASGG3BEJnM52FVPC7E9p+8YZ
+qIGuiF5Cz/rYZkpwffBWIfS2zZakHLm5TB8FgZkWlyReJU9Ihk2Tl/sZ1kllFdYa
+xLPnLCL82KFL1Co=
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function
index 83c8011..f159967 100644
--- a/tests/suites/test_suite_bignum.function
+++ b/tests/suites/test_suite_bignum.function
@@ -1183,24 +1183,57 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mbedtls_mpi_mod_int( char * input_X, int input_Y,
-                          int input_A, int div_result )
+void mbedtls_mpi_mod_int( char * input_X, char * input_Y,
+                          char * input_A, int mod_result )
 {
     mbedtls_mpi X;
+    mbedtls_mpi Y;
+    mbedtls_mpi A;
     int res;
     mbedtls_mpi_uint r;
-    mbedtls_mpi_init( &X );
 
-    TEST_ASSERT( mbedtls_test_read_mpi( &X, input_X ) == 0 );
-    res = mbedtls_mpi_mod_int( &r, &X, input_Y );
-    TEST_ASSERT( res == div_result );
+    mbedtls_mpi_init( &X );
+    mbedtls_mpi_init( &Y );
+    mbedtls_mpi_init( &A );
+
+    /* We use MPIs to read Y and A since the test framework limits us to
+     * ints, so we can't have 64-bit values */
+    TEST_EQUAL( mbedtls_test_read_mpi( &X, input_X ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi( &Y, input_Y ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi( &A, input_A ), 0 );
+
+    TEST_EQUAL( Y.n, 1 );
+    TEST_EQUAL( A.n, 1 );
+
+    /* Convert the MPIs for Y and A to (signed) mbedtls_mpi_sints */
+
+    /* Since we're converting sign+magnitude to two's complement, we lose one
+     * bit of value in the output. This means there are some values we can't
+     * represent, e.g. (hex) -A0000000 on 32-bit systems. These are technically
+     * invalid test cases, so could be considered "won't happen", but they are
+     * easy to test for, and this helps guard against human error. */
+
+    mbedtls_mpi_sint y = (mbedtls_mpi_sint) Y.p[0];
+    TEST_ASSERT( y >= 0 );      /* If y < 0 here, we can't make negative y */
+    if( Y.s == -1 )
+        y = -y;
+
+    mbedtls_mpi_sint a = (mbedtls_mpi_sint) A.p[0];
+    TEST_ASSERT( a >= 0 );      /* Same goes for a */
+    if( A.s == -1 )
+        a = -a;
+
+    res = mbedtls_mpi_mod_int( &r, &X, y );
+    TEST_EQUAL( res, mod_result );
     if( res == 0 )
     {
-        TEST_ASSERT( r == (mbedtls_mpi_uint) input_A );
+        TEST_EQUAL( r, a );
     }
 
 exit:
     mbedtls_mpi_free( &X );
+    mbedtls_mpi_free( &Y );
+    mbedtls_mpi_free( &A );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_bignum.misc.data b/tests/suites/test_suite_bignum.misc.data
index a9b05d7..937e290 100644
--- a/tests/suites/test_suite_bignum.misc.data
+++ b/tests/suites/test_suite_bignum.misc.data
@@ -1226,40 +1226,72 @@
 mbedtls_mpi_mod_mpi:"-":"-2a":"":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Base test mbedtls_mpi_mod_int #1
-mbedtls_mpi_mod_int:"3e8":13:12:0
+mbedtls_mpi_mod_int:"3e8":"d":"c":0
 
 Base test mbedtls_mpi_mod_int #2 (Divide by zero)
-mbedtls_mpi_mod_int:"3e8":0:0:MBEDTLS_ERR_MPI_DIVISION_BY_ZERO
+mbedtls_mpi_mod_int:"3e8":"0":"0":MBEDTLS_ERR_MPI_DIVISION_BY_ZERO
 
 Base test mbedtls_mpi_mod_int #3
-mbedtls_mpi_mod_int:"-3e8":13:1:0
+mbedtls_mpi_mod_int:"-3e8":"d":"1":0
 
 Base test mbedtls_mpi_mod_int #4 (Negative modulo)
-mbedtls_mpi_mod_int:"3e8":-13:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mbedtls_mpi_mod_int:"3e8":"-d":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Base test mbedtls_mpi_mod_int #5 (Negative modulo)
-mbedtls_mpi_mod_int:"-3e8":-13:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mbedtls_mpi_mod_int:"-3e8":"-d":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Base test mbedtls_mpi_mod_int #6 (By 1)
-mbedtls_mpi_mod_int:"3e8":1:0:0
+mbedtls_mpi_mod_int:"3e8":"1":"0":0
 
 Base test mbedtls_mpi_mod_int #7 (By 2)
-mbedtls_mpi_mod_int:"3e9":2:1:0
+mbedtls_mpi_mod_int:"3e9":"2":"1":0
 
 Base test mbedtls_mpi_mod_int #8 (By 2)
-mbedtls_mpi_mod_int:"3e8":2:0:0
+mbedtls_mpi_mod_int:"3e8":"2":"0":0
 
 Test mbedtls_mpi_mod_int: 0 (null) % 1
-mbedtls_mpi_mod_int:"":1:0:0
+mbedtls_mpi_mod_int:"":"1":"0":0
 
 Test mbedtls_mpi_mod_int: 0 (null) % 2
-mbedtls_mpi_mod_int:"":2:0:0
+mbedtls_mpi_mod_int:"":"2":"0":0
 
 Test mbedtls_mpi_mod_int: 0 (null) % -1
-mbedtls_mpi_mod_int:"":-1:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mbedtls_mpi_mod_int:"":"-1":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Test mbedtls_mpi_mod_int: 0 (null) % -2
-mbedtls_mpi_mod_int:"":-2:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mbedtls_mpi_mod_int:"":"-2":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
+# CURRENTLY FAILS - SEE GITHUB ISSUE #6540
+#Test mbedtls_mpi_mod_int: 230772460340063000000100500000300000010 % 5178236083361335880 -> 3386266129388798810
+#depends_on:MBEDTLS_HAVE_INT64
+#mbedtls_mpi_mod_int:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA4847DCCA48":"2EFE6F1A7D28035A":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340063000000100500000300000010 % 5178236083361335880 -> 3386266129388798810
+mbedtls_mpi_mod_mpi:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA4847DCCA48":"2EFE6F1A7D28035A":0
+
+# CURRENTLY FAILS - SEE GITHUB ISSUE #6540
+#Test mbedtls_mpi_mod_int: 230772460340062999996714233870911201200 % 5178236083361335880 -> 0
+#depends_on:MBEDTLS_HAVE_INT64
+#mbedtls_mpi_mod_int:"AD9D28BF6C4E98FDC2584FEF03A6DFB0":"47DCCA4847DCCA48":"0":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340062999996714233870911201200 % 5178236083361335880 -> 0
+mbedtls_mpi_mod_mpi:"AD9D28BF6C4E98FDC2584FEF03A6DFB0":"47DCCA4847DCCA48":"0":0
+
+# CURRENTLY FAILS WHEN MPIS ARE 32-BIT (ISSUE #6450): WHEN FIXED, REMOVE "depends_on" LINE
+Test mbedtls_mpi_mod_int: 230772460340063000000100500000300000010 % 1205652040 -> 3644370
+depends_on:MBEDTLS_HAVE_INT64
+mbedtls_mpi_mod_int:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA48":"379BD2":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340063000000100500000300000010 % 1205652040 -> 3644370
+mbedtls_mpi_mod_mpi:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA48":"379BD2":0
+
+# CURRENTLY FAILS WHEN MPIS ARE 32-BIT (ISSUE #6450): WHEN FIXED, REMOVE "depends_on" LINE
+Test mbedtls_mpi_mod_int: 230772460340063000000100500000296355640 % 1205652040 -> 0
+depends_on:MBEDTLS_HAVE_INT64
+mbedtls_mpi_mod_int:"AD9D28BF6C4E98FDF156BF0980974738":"47DCCA48":"0":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340063000000100500000296355640 % 1205652040 -> 0
+mbedtls_mpi_mod_mpi:"AD9D28BF6C4E98FDF156BF0980974738":"47DCCA48":"0":0
 
 Base test mbedtls_mpi_exp_mod #1
 mbedtls_mpi_exp_mod:"17":"d":"1d":"18":0
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index 1c1cf30..aa8b3cd 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -1,54 +1,58 @@
 Certificate Request check Server1 SHA1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha1":MBEDTLS_MD_SHA1:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha1":MBEDTLS_MD_SHA1:0:0:0:0:0
 
 Certificate Request check Server1 SHA224
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha224":MBEDTLS_MD_SHA224:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha224":MBEDTLS_MD_SHA224:0:0:0:0:0
 
 Certificate Request check Server1 SHA256
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256":MBEDTLS_MD_SHA256:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256":MBEDTLS_MD_SHA256:0:0:0:0:0
 
 Certificate Request check Server1 SHA384
 depends_on:MBEDTLS_SHA512_C:!MBEDTLS_SHA512_NO_SHA384:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha384":MBEDTLS_MD_SHA384:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha384":MBEDTLS_MD_SHA384:0:0:0:0:0
 
 Certificate Request check Server1 SHA512
 depends_on:MBEDTLS_SHA512_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha512":MBEDTLS_MD_SHA512:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha512":MBEDTLS_MD_SHA512:0:0:0:0:0
 
 Certificate Request check Server1 MD4
 depends_on:MBEDTLS_MD4_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.md4":MBEDTLS_MD_MD4:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.md4":MBEDTLS_MD_MD4:0:0:0:0:0
 
 Certificate Request check Server1 MD5
 depends_on:MBEDTLS_MD5_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.md5":MBEDTLS_MD_MD5:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.md5":MBEDTLS_MD_MD5:0:0:0:0:0
 
 Certificate Request check Server1 key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:0
 
 Certificate Request check Server1 key_usage empty
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage_empty":MBEDTLS_MD_SHA1:0:1:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage_empty":MBEDTLS_MD_SHA1:0:1:0:0:0
 
 Certificate Request check Server1 ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0
 
 Certificate Request check Server1 ns_cert_type empty
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type_empty":MBEDTLS_MD_SHA1:0:0:0:1
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type_empty":MBEDTLS_MD_SHA1:0:0:0:1:0
 
 Certificate Request check Server1 key_usage + ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.ku-ct":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.ku-ct":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0
 
 Certificate Request check Server5 ECDSA, key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_ECP_DP_SECP256R1_ENABLED
-x509_csr_check:"data_files/server5.key":"data_files/server5.req.ku.sha1":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION:1:0:0
+x509_csr_check:"data_files/server5.key":"data_files/server5.req.ku.sha1":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION:1:0:0:0
+
+Certificate Request check Server1, set_extension
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256.ext":MBEDTLS_MD_SHA256:0:0:0:0:1
 
 Certificate Request check opaque Server5 ECDSA, key_usage
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 12c8f39..b27a252 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -5,6 +5,7 @@
 #include "mbedtls/pem.h"
 #include "mbedtls/oid.h"
 #include "mbedtls/rsa.h"
+#include "mbedtls/asn1write.h"
 
 #if defined(MBEDTLS_RSA_C)
 int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen,
@@ -68,6 +69,56 @@
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_PEM_WRITE_C && MBEDTLS_X509_CSR_WRITE_C */
 
+#if defined(MBEDTLS_X509_CSR_WRITE_C)
+
+/*
+ * The size of this temporary buffer is given by the sequence of functions
+ * called hereinafter:
+ * - mbedtls_asn1_write_oid()
+ *     - 8 bytes for MBEDTLS_OID_EXTENDED_KEY_USAGE raw value
+ *     - 1 byte for MBEDTLS_OID_EXTENDED_KEY_USAGE length
+ *     - 1 byte for MBEDTLS_ASN1_OID tag
+ * - mbedtls_asn1_write_len()
+ *     - 1 byte since we're dealing with sizes which are less than 0x80
+ * - mbedtls_asn1_write_tag()
+ *     - 1 byte
+ *
+ * This length is fine as long as this function is called using the
+ * MBEDTLS_OID_SERVER_AUTH OID. If this is changed in the future, then this
+ * buffer's length should be adjusted accordingly.
+ * Unfortunately there's no predefined max size for OIDs which can be used
+ * to set an overall upper boundary which is always guaranteed.
+ */
+#define EXT_KEY_USAGE_TMP_BUF_MAX_LENGTH    12
+
+static int csr_set_extended_key_usage( mbedtls_x509write_csr *ctx,
+                        const char *oid, size_t oid_len )
+{
+    unsigned char buf[EXT_KEY_USAGE_TMP_BUF_MAX_LENGTH] = { 0 };
+    unsigned char *p = buf + sizeof( buf );
+    int ret;
+    size_t len = 0;
+
+    /*
+     * Following functions fail anyway if the temporary buffer is not large,
+     * but we set an extra check here to emphasize a possible source of errors
+     */
+    if ( oid_len > EXT_KEY_USAGE_TMP_BUF_MAX_LENGTH )
+    {
+        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
+    }
+
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( &p, buf, oid, oid_len ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, ret ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf,
+                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
+
+    ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_EXTENDED_KEY_USAGE,
+              MBEDTLS_OID_SIZE( MBEDTLS_OID_EXTENDED_KEY_USAGE ), p, len );
+
+    return ret;
+}
+#endif  /* MBEDTLS_X509_CSR_WRITE_C */
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -78,7 +129,7 @@
 /* BEGIN_CASE depends_on:MBEDTLS_PEM_WRITE_C:MBEDTLS_X509_CSR_WRITE_C */
 void x509_csr_check( char * key_file, char * cert_req_check_file, int md_type,
                      int key_usage, int set_key_usage, int cert_type,
-                     int set_cert_type )
+                     int set_cert_type, int set_extension )
 {
     mbedtls_pk_context key;
     mbedtls_x509write_csr req;
@@ -105,6 +156,9 @@
         TEST_ASSERT( mbedtls_x509write_csr_set_key_usage( &req, key_usage ) == 0 );
     if( set_cert_type != 0 )
         TEST_ASSERT( mbedtls_x509write_csr_set_ns_cert_type( &req, cert_type ) == 0 );
+    if ( set_extension != 0 )
+        TEST_ASSERT( csr_set_extended_key_usage( &req, MBEDTLS_OID_SERVER_AUTH,
+                            MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ) ) == 0 );
 
     ret = mbedtls_x509write_csr_pem( &req, buf, sizeof( buf ),
                                      mbedtls_test_rnd_pseudo_rand, &rnd_info );