Merge pull request #5991 from gilles-peskine-arm/asn1write-0-fix-2.28

Backport 2.28: Improve ASN.1 write tests
diff --git a/ChangeLog.d/fix-csr_subject_commas.txt b/ChangeLog.d/fix-csr_subject_commas.txt
new file mode 100644
index 0000000..e01c9a8
--- /dev/null
+++ b/ChangeLog.d/fix-csr_subject_commas.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix string representation of DNs when outputting values containing commas
+     and other special characters, conforming to RFC 1779. Fixes #769.
diff --git a/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt b/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt
index 6878645..a6540a1 100644
--- a/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt
+++ b/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt
@@ -1,3 +1,3 @@
 Bugfix
-   * Fix compilation on Windows when building shared library, by setting
-     library search path to CMAKE_CURRENT_BINARY_DIR.
+   * Fix the library search path when building a shared library with CMake
+     on Windows.
diff --git a/ChangeLog.d/fix-x25519-program.txt b/ChangeLog.d/fix-x25519-program.txt
index af60465..bf5d6ac 100644
--- a/ChangeLog.d/fix-x25519-program.txt
+++ b/ChangeLog.d/fix-x25519-program.txt
@@ -1,4 +1,4 @@
 Bugfix
-   * Fix a bug in x25519 example program where the removal of
+   * Fix a bug in the x25519 example program where the removal of
      MBEDTLS_ECDH_LEGACY_CONTEXT caused the program not to run. Fixes #4901 and
      #3191.
diff --git a/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt b/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt
index d55c016..043b273 100644
--- a/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt
+++ b/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt
@@ -1,2 +1,2 @@
 Bugfix
-   * Fix memory leak if mbedtls_ssl_config_defaults() call is repeated
+   * Fix a memory leak if mbedtls_ssl_config_defaults() is called twice.
diff --git a/ChangeLog.d/raw-agreement-destroy-missing.txt b/ChangeLog.d/raw-agreement-destroy-missing.txt
deleted file mode 100644
index 7342b8c..0000000
--- a/ChangeLog.d/raw-agreement-destroy-missing.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Add missing key slot destruction calls when a raw key agreement or
-     a public key export fails in ssl_write_client_key_exchange.
diff --git a/ChangeLog.d/selftest-gcc12.txt b/ChangeLog.d/selftest-gcc12.txt
new file mode 100644
index 0000000..aafa256
--- /dev/null
+++ b/ChangeLog.d/selftest-gcc12.txt
@@ -0,0 +1,2 @@
+Bugfix
+   * Silence a warning from GCC 12 in the selftest program. Fixes #5974.
diff --git a/ChangeLog.d/use-psa-ecdhe-curve.txt b/ChangeLog.d/use-psa-ecdhe-curve.txt
index cc432bd..658f88f 100644
--- a/ChangeLog.d/use-psa-ecdhe-curve.txt
+++ b/ChangeLog.d/use-psa-ecdhe-curve.txt
@@ -4,4 +4,4 @@
      client would fail to check that the curve selected by the server for
      ECDHE was indeed one that was offered. As a result, the client would
      accept any curve that it supported, even if that curve was not allowed
-     according to its configuration.
+     according to its configuration. Fixes #5291.
diff --git a/library/x509.c b/library/x509.c
index f21e9e6..3997ebd 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -741,7 +741,7 @@
 int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t i, n;
+    size_t i, j, n;
     unsigned char c, merge = 0;
     const mbedtls_x509_name *name;
     const char *short_name = NULL;
@@ -775,17 +775,24 @@
             ret = mbedtls_snprintf( p, n, "\?\?=" );
         MBEDTLS_X509_SAFE_SNPRINTF;
 
-        for( i = 0; i < name->val.len; i++ )
+        for( i = 0, j = 0; i < name->val.len; i++, j++ )
         {
-            if( i >= sizeof( s ) - 1 )
-                break;
+            if( j >= sizeof( s ) - 1 )
+                return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
 
             c = name->val.p[i];
+            // Special characters requiring escaping, RFC 1779
+            if( c && strchr( ",=+<>#;\"\\", c ) )
+            {
+                if( j + 1 >= sizeof( s ) - 1 )
+                    return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
+                s[j++] = '\\';
+            }
             if( c < 32 || c >= 127 )
-                 s[i] = '?';
-            else s[i] = c;
+                 s[j] = '?';
+            else s[j] = c;
         }
-        s[i] = '\0';
+        s[j] = '\0';
         ret = mbedtls_snprintf( p, n, "%s", s );
         MBEDTLS_X509_SAFE_SNPRINTF;
 
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index 41d7040..393d737 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -89,7 +89,6 @@
     void *empty2 = mbedtls_calloc( 0, 1 );
     void *buffer1 = mbedtls_calloc( 1, 1 );
     void *buffer2 = mbedtls_calloc( 1, 1 );
-    uintptr_t old_buffer1;
 
     if( empty1 == NULL && empty2 == NULL )
     {
@@ -131,7 +130,6 @@
             mbedtls_printf( "  CALLOC(1): passed\n" );
     }
 
-    old_buffer1 = (uintptr_t) buffer1;
     mbedtls_free( buffer1 );
     buffer1 = mbedtls_calloc( 1, 1 );
     if( buffer1 == NULL )
@@ -143,9 +141,7 @@
     else
     {
         if( verbose )
-            mbedtls_printf( "  CALLOC(1 again): passed (%s address)\n",
-                            (uintptr_t) old_buffer1 == (uintptr_t) buffer1 ?
-                            "same" : "different" );
+            mbedtls_printf( "  CALLOC(1 again): passed\n" );
     }
 
     if( verbose )
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index f3cba5a..49db4ca 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -937,6 +937,10 @@
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA1 force_ns_cert_type=1
 all_final += server1.req.cert_type_empty
 
+server1.req.commas.sha256: server1.key
+	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL\, Commas,CN=PolarSSL Server 1" md=SHA256
+all_final += server1.req.commas.sha256
+
 # server2*
 
 server2_pwd_ec = PolarSSLTest
@@ -994,7 +998,9 @@
 	$(MBEDTLS_CERT_WRITE) request_file=server1.req.sha256 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20190210144406 not_after=20290210144406 md=SHA1 authority_identifier=0 version=3 output_file=$@
 server1.der: server1.crt
 	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
-all_final += server1.crt server1.noauthid.crt server1.crt.der
+server1.commas.crt: server1.key server1.req.commas.sha256 $(test_ca_crt) $(test_ca_key_file_rsa)
+	$(MBEDTLS_CERT_WRITE) request_file=server1.req.commas.sha256 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) version=1 not_before=20190210144406 not_after=20290210144406 md=SHA1 version=3 output_file=$@
+all_final += server1.crt server1.noauthid.crt server1.crt.der server1.commas.crt
 
 server1.key_usage.crt: server1.key server1.req.sha256 $(test_ca_crt) $(test_ca_key_file_rsa)
 	$(MBEDTLS_CERT_WRITE) request_file=server1.req.sha256 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) version=1 not_before=20190210144406 not_after=20290210144406 md=SHA1 key_usage=digital_signature,non_repudiation,key_encipherment version=3 output_file=$@
diff --git a/tests/data_files/server1.commas.crt b/tests/data_files/server1.commas.crt
new file mode 100644
index 0000000..5acd255
--- /dev/null
+++ b/tests/data_files/server1.commas.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDRzCCAi+gAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjBEMQswCQYDVQQGEwJOTDEZMBcG
+A1UECgwQUG9sYXJTU0wsIENvbW1hczEaMBgGA1UEAwwRUG9sYXJTU0wgU2VydmVy
+IDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpAh89QGrVVVOL/Tbu
+gmUuFWFeib+46EWQ2+6IFlLT8UNQR5YSWWSHa/0r4Eb5c77dz5LhkVvtZqBviSl5
+RYDQg2rVQUN3Xzl8CQRHgrBXOXDto+wVGR6oMwhHwQVCqf1Mw7Tf3QYfTRBRQGdz
+Ew9A+G2BJV8KsVPGMH4VOaz5Wu5/kp6mBVvnE5eFtSOS2dQkBtUJJYl1B92mGo8/
+CRm+rWUsZOuVm9z+QV4XptpsW2nMAroULBYknErczdD3Umdz8S2gI/1+9DHKLXDK
+iQsE2y6mT3Buns69WIniU1meblqSZeKIPwyUGaPd5eidlRPtKdurcBLcWsprF6tS
+glSxAgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFB901j8pwXR0RTsFEiw9
+qL1DWQKmMB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MA0GCSqGSIb3
+DQEBBQUAA4IBAQA1Ecg+VVJRmgFF9cnlztnXj4y9QKj8MCf2uZA3nTNe1Deh9l17
+ZNNWdPkXzVzf0IeR3LQRKT+daTzxuOOCSV9OxOcN0dIODBwa97BtNQfuWw2eWC9I
+3UOVXbx8Ga+bXnD8ouatpyEG0FfhLO5YgEP0K9TyyN/nFa9kkB2Kvpy8yWm3w9WG
+WgsOr2fpIExfC2ZFaiu3NVGTpT9fLv8RTatSC1XLA5Sr8NNHia3zCvEJEAlTuFHs
+wm8apIAHlb44bbgW+7UwBIH9r2A21gQFy3v4cTLtlbnaUBbHUJvarK4ru70J+gew
+OO3NZ1ocvnV+qGIcc7LgyNA8pZW5Jbewb/gN
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server1.req.commas.sha256 b/tests/data_files/server1.req.commas.sha256
new file mode 100644
index 0000000..0287a31
--- /dev/null
+++ b/tests/data_files/server1.req.commas.sha256
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICiTCCAXECAQAwRDELMAkGA1UEBhMCTkwxGTAXBgNVBAoMEFBvbGFyU1NMLCBD
+b21tYXMxGjAYBgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/uOhFkNvuiBZS
+0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFDd185fAkER4Kw
+Vzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVfCrFTxjB+FTms
++Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTrlZvc/kFeF6ba
+bFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9wbp7OvViJ4lNZ
+nm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQABoAAwDQYJKoZI
+hvcNAQELBQADggEBAI7ZtRJYX6cMuwVhwXOizPV+WD17wby+273V4R8e9/6QA4nY
+RrSciAse+nWZz9Y6toBzLWr0K/9SCzwBX4OzMvLqu4A1G/wApODCDnbGaUPNUxRt
+6qbg8y7faBWvDGjk4+OpQ0suR/pdbM/L7pImqWRNwYdSPbJumNqIdB/Ewtso0TlA
+QVZ992RPe1LovXpDCfPP2p123L7/UHezNCtu5QmzLsDfQmN/rLhCJ2NZzTsnIdnP
+jp6XYU4kRV2BPDL65k38k8CSVWb6fw9XwPNUiyO3q1Zs6jpGJRYMLj9qTEoRN1np
+RME09CN2siMcgkv8UqDeDJ4Oa9qyXS6VXsDmSNI=
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 7ac91f6..066d6e4 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -318,6 +318,10 @@
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_SHA512_C:MBEDTLS_RSA_C
 mbedtls_x509_csr_info:"data_files/server1.req.sha512":"CSR version   \: 1\nsubject name  \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nsigned using  \: RSA with SHA-512\nRSA key size  \: 2048 bits\n"
 
+X509 CSR Information RSA with SHA-256, containing commas
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_SHA256_C:MBEDTLS_RSA_C:MBEDTS_X509_INFO
+mbedtls_x509_csr_info:"data_files/server1.req.commas.sha256":"CSR version   \: 1\nsubject name  \: C=NL, O=PolarSSL\, Commas, CN=PolarSSL Server 1\nsigned using  \: RSA with SHA-256\nRSA key size  \: 2048 bits\n"
+
 X509 CSR Information EC with SHA1
 depends_on:MBEDTLS_ECDSA_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA1_C
 mbedtls_x509_csr_info:"data_files/server5.req.sha1":"CSR version   \: 1\nsubject name  \: C=NL, O=PolarSSL, CN=localhost\nsigned using  \: ECDSA with SHA1\nEC key size   \: 256 bits\n"
@@ -399,6 +403,30 @@
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 mbedtls_x509_dn_gets:"data_files/server2.crt":"issuer":"C=NL, O=PolarSSL, CN=PolarSSL Test CA"
 
+X509 Get Distinguished Name #5
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+mbedtls_x509_dn_gets:"data_files/server1.commas.crt":"subject":"C=NL, O=PolarSSL\, Commas, CN=PolarSSL Server 1"
+
+X509 Get Modified DN #1
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+mbedtls_x509_dn_gets_subject_replace:"data_files/server1.crt":"Modified":"C=NL, O=Modified, CN=PolarSSL Server 1":0
+
+X509 Get Modified DN #2 Name exactly 255 bytes
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+mbedtls_x509_dn_gets_subject_replace:"data_files/server1.crt":"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345":"C=NL, O=123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345, CN=PolarSSL Server 1":0
+
+X509 Get Modified DN #3 Name exceeds 255 bytes
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+mbedtls_x509_dn_gets_subject_replace:"data_files/server1.crt":"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456":"":MBEDTLS_ERR_X509_BUFFER_TOO_SMALL
+
+X509 Get Modified DN #4 Name exactly 255 bytes, with comma requiring escaping
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+mbedtls_x509_dn_gets_subject_replace:"data_files/server1.crt":"1234567890,1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234":"":MBEDTLS_ERR_X509_BUFFER_TOO_SMALL
+
+X509 Get Modified DN #5 Name exactly 255 bytes, ending with comma requiring escaping
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+mbedtls_x509_dn_gets_subject_replace:"data_files/server1.crt":"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234,":"":MBEDTLS_ERR_X509_BUFFER_TOO_SMALL
+
 X509 Time Expired #1
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_HAVE_TIME_DATE:MBEDTLS_SHA1_C
 mbedtls_x509_time_is_past:"data_files/server1.crt":"valid_from":1
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 00b6863..77f3d23 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -768,6 +768,37 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
+void mbedtls_x509_dn_gets_subject_replace( char * crt_file, char * new_subject_ou, char * result_str, int ret )
+{
+    mbedtls_x509_crt   crt;
+    char buf[2000];
+    int res = 0;
+
+    mbedtls_x509_crt_init( &crt );
+    memset( buf, 0, 2000 );
+
+    TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
+    crt.subject.next->val.p = (unsigned char *) new_subject_ou;
+    crt.subject.next->val.len = strlen( new_subject_ou );
+
+    res =  mbedtls_x509_dn_gets( buf, 2000, &crt.subject );
+
+    if ( ret != 0 )
+    {
+        TEST_ASSERT( res == ret );
+    }
+    else
+    {
+        TEST_ASSERT( res != -1 );
+        TEST_ASSERT( res != -2 );
+        TEST_ASSERT( strcmp( buf, result_str ) == 0 );
+    }
+exit:
+    mbedtls_x509_crt_free( &crt );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */
 void mbedtls_x509_time_is_past( char * crt_file, char * entity, int result )
 {
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index 87f28a7..1c1cf30 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -112,7 +112,7 @@
 
 
 X509 String to Names #1
-mbedtls_x509_string_to_names:"C=NL,O=Offspark\, Inc., OU=PolarSSL":"C=NL, O=Offspark, Inc., OU=PolarSSL":0
+mbedtls_x509_string_to_names:"C=NL,O=Offspark\, Inc., OU=PolarSSL":"C=NL, O=Offspark\, Inc., OU=PolarSSL":0
 
 X509 String to Names #2
 mbedtls_x509_string_to_names:"C=NL, O=Offspark, Inc., OU=PolarSSL":"":MBEDTLS_ERR_X509_UNKNOWN_OID