Merge remote-tracking branch 'upstream-public/pr/1113' into mbedtls-1.3
diff --git a/ChangeLog b/ChangeLog
index 24d5703..9b6d009 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,19 @@
 mbed TLS ChangeLog (Sorted per branch, date)
 
-= mbed TLS x.x.xx branch released xxxx-xx-xx
+= mbed TLS 1.3.22 branch released 2017-xx-xx
 
 Bugfix
+   * Fix memory leak in ssl_set_hostname() when called multiple times.
+     Found by projectgus and jethrogb, #836.
+   * Fix usage help in ssl_server2 example. Found and fixed by Bei Lin.
+   * Fix Visual Studio implicit cast compilation warnings in the net.c and
+     x509.c modules and some sample applications.
+   * Parse signature algorithm extension when renegotiating. Previously,
+     renegotiated handshakes would only accept signatures using SHA-1
+     regardless of the peer's preferences, or fail if SHA-1 was disabled.
+   * Fix leap year calculation in x509_date_is_valid() to ensure that invalid
+     dates on leap years with 100 and 400 intervals are handled correctly. Found
+     by Nicholas Wilson. #694
    * Fix out-of-memory problem when parsing 4096-bit PKCS8-encrypted RSA keys.
      Found independently by Florian in the mbed TLS forum and by Mishamax.
      #878, #1019.
diff --git a/configs/README.txt b/configs/README.txt
index 4a0074c..76f0031 100644
--- a/configs/README.txt
+++ b/configs/README.txt
@@ -8,7 +8,7 @@
 them, you can pick one of the following methods:
 
 1. Replace the default file include/polarssl/config.h with the chosen one.
-   (Depending on your compiler, you may need to ajust the line with
+   (Depending on your compiler, you may need to adjust the line with
    #include "polarssl/check_config.h" then.)
 
 2. Define POLARSSL_CONFIG_FILE and adjust the include path accordingly.
diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h
index 0bfa929..5f236a5 100644
--- a/include/polarssl/asn1.h
+++ b/include/polarssl/asn1.h
@@ -60,7 +60,7 @@
 
 /**
  * \name DER constants
- * These constants comply with DER encoded the ANS1 type tags.
+ * These constants comply with the DER encoded ASN.1 type tags.
  * DER encoding uses hexadecimal representation.
  * An example DER sequence is:\n
  * - 0x02 -- tag indicating INTEGER
diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h
index 4a01bbf..9a3fb8a 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -1398,15 +1398,23 @@
 
 #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
 /**
- * \brief          Set hostname for ServerName TLS extension
- *                 (client-side only)
- *
+ * \brief          Set or reset the hostname to check against the received
+ *                 server certificate. It sets the ServerName TLS extension,
+ *                 too, if that extension is enabled. (client-side only)
  *
  * \param ssl      SSL context
- * \param hostname the server hostname
+ * \param hostname the server hostname, may be NULL to clear hostname
  *
- * \return         0 if successful or POLARSSL_ERR_SSL_MALLOC_FAILED
- */
+ * \note           Maximum hostname length SSL_MAX_HOST_NAME_LEN.
+ *
+ * \return         0 if successful, POLARSSL_ERR_SSL_MALLOC_FAILED on
+ *                 allocation failure, POLARSSL_ERR_BAD_INPUT_DATA on
+ *                 too long input hostname.
+ *
+ * \note           Hostname set to the one provided on success (cleared
+ *                 when NULL). On allocation failure hostname is cleared.
+ *                 On too long input failure, old hostname is unchanged.
+*/
 int ssl_set_hostname( ssl_context *ssl, const char *hostname );
 
 /**
diff --git a/library/net.c b/library/net.c
index c7ce258..b42b86f 100644
--- a/library/net.c
+++ b/library/net.c
@@ -55,8 +55,8 @@
 #endif
 #endif /* _MSC_VER */
 
-#define read(fd,buf,len)        recv(fd,(char*)buf,(int) len,0)
-#define write(fd,buf,len)       send(fd,(char*)buf,(int) len,0)
+#define read(fd,buf,len)        recv( fd, (char*)( buf ), (int)( len ), 0 )
+#define write(fd,buf,len)       send( fd, (char*)( buf ), (int)( len ), 0 )
 #define close(fd)               closesocket(fd)
 
 static int wsa_init_done = 0;
@@ -92,6 +92,14 @@
 
 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
 
+/* Some MS functions want int and MSVC warns if we pass size_t,
+ * but the standard functions use socklen_t, so cast only for MSVC */
+#if defined(_MSC_VER)
+#define MSVC_INT_CAST   (int)
+#else
+#define MSVC_INT_CAST
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 
@@ -202,7 +210,7 @@
             continue;
         }
 
-        if( connect( *fd, cur->ai_addr, cur->ai_addrlen ) == 0 )
+        if( connect( *fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 )
         {
             ret = 0;
             break;
@@ -299,7 +307,7 @@
             continue;
         }
 
-        if( bind( *fd, cur->ai_addr, cur->ai_addrlen ) != 0 )
+        if( bind( *fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 )
         {
             close( *fd );
             ret = POLARSSL_ERR_NET_BIND_FAILED;
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 146f283..0f0369a 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -1675,10 +1675,6 @@
         defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED)
             case TLS_EXT_SIG_ALG:
                 SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) );
-    #if defined(POLARSSL_SSL_RENEGOTIATION)
-                if( ssl->renegotiation == SSL_RENEGOTIATION )
-                    break;
-    #endif
 
                 ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size );
                 if( ret != 0 )
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index bae8433..54867da 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -4230,26 +4230,51 @@
 #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
 int ssl_set_hostname( ssl_context *ssl, const char *hostname )
 {
+    size_t hostname_len = 0;
+
+    /* Check if new hostname is valid before
+     * making any change to current one */
+
+    if( hostname != NULL )
+    {
+        hostname_len = strlen( hostname );
+
+        if( hostname_len > SSL_MAX_HOST_NAME_LEN )
+            return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    /* Now it's clear that we will overwrite the old hostname,
+     * so we can free it safely */
+
+    if( ssl->hostname != NULL )
+    {
+        polarssl_zeroize( ssl->hostname, ssl->hostname_len );
+        polarssl_free( ssl->hostname );
+    }
+
+    /* Passing NULL as hostname shall clear the old one */
+
     if( hostname == NULL )
-        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+    {
+        ssl->hostname     = NULL;
+        ssl->hostname_len = 0;
+    }
+    else
+    {
+        ssl->hostname = polarssl_malloc( hostname_len + 1 );
 
-    ssl->hostname_len = strlen( hostname );
+        if( ssl->hostname == NULL )
+        {
+            ssl->hostname_len = 0;
+            return( POLARSSL_ERR_SSL_MALLOC_FAILED );
+        }
 
-    if( ssl->hostname_len + 1 == 0 )
-        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+        memcpy( ssl->hostname, (const unsigned char*) hostname,
+                hostname_len );
 
-    if( ssl->hostname_len > SSL_MAX_HOST_NAME_LEN )
-        return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
-
-    ssl->hostname = polarssl_malloc( ssl->hostname_len + 1 );
-
-    if( ssl->hostname == NULL )
-        return( POLARSSL_ERR_SSL_MALLOC_FAILED );
-
-    memcpy( ssl->hostname, (const unsigned char *) hostname,
-            ssl->hostname_len );
-
-    ssl->hostname[ssl->hostname_len] = '\0';
+        ssl->hostname[hostname_len] = '\0';
+        ssl->hostname_len = hostname_len;
+    }
 
     return( 0 );
 }
diff --git a/library/x509.c b/library/x509.c
index 5e6062b..cb6fc6c 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -480,19 +480,26 @@
     }
 }
 
-static int x509_parse_int(unsigned char **p, unsigned n, int *res){
+static int x509_parse_int( unsigned char **p, size_t n, int *res )
+{
     *res = 0;
-    for( ; n > 0; --n ){
-        if( ( **p < '0') || ( **p > '9' ) ) return POLARSSL_ERR_X509_INVALID_DATE;
+
+    for( ; n > 0; --n )
+    {
+        if( ( **p < '0') || ( **p > '9' ) )
+            return( POLARSSL_ERR_X509_INVALID_DATE );
+
         *res *= 10;
-        *res += (*(*p)++ - '0');
+        *res += ( *(*p)++ - '0' );
     }
-    return 0;
+
+    return( 0 );
 }
 
 static int x509_date_is_valid(const x509_time *t)
 {
     int ret = POLARSSL_ERR_X509_INVALID_DATE;
+    int month_len;
 
     CHECK_RANGE( 0, 9999, t->year );
     CHECK_RANGE( 0, 23,   t->hour );
@@ -502,17 +509,22 @@
     switch( t->mon )
     {
         case 1: case 3: case 5: case 7: case 8: case 10: case 12:
-            CHECK_RANGE( 1, 31, t->day );
+            month_len = 31;
             break;
         case 4: case 6: case 9: case 11:
-            CHECK_RANGE( 1, 30, t->day );
+            month_len = 30;
             break;
         case 2:
-            CHECK_RANGE( 1, 28 + (t->year % 4 == 0), t->day );
+            if( ( !( t->year % 4 ) && t->year % 100 ) ||
+                !( t->year % 400 ) )
+                month_len = 29;
+            else
+                month_len = 28;
             break;
         default:
             return( ret );
     }
+    CHECK_RANGE( 1, month_len, t->day );
 
     return( 0 );
 }
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 1856cc4..af3b0d3 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -1267,7 +1267,7 @@
 
     len = polarssl_snprintf( (char *) buf, sizeof(buf) - 1, GET_REQUEST,
                     opt.request_page );
-    tail_len = strlen( GET_REQUEST_END );
+    tail_len = (int) strlen( GET_REQUEST_END );
 
     /* Add padding to GET request to reach opt.request_size in length */
     if( opt.request_size != DFL_REQUEST_SIZE &&
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index 27c57a1..8a7850e 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -57,8 +57,10 @@
 #include <unistd.h>
 #else
 #include <io.h>
-#define read _read
-#define write _write
+#define read(fd, buf, len)                                      \
+    _read( fd, (void *)( buf ), (unsigned int)( len ) )
+#define write(fd, buf, len)                                     \
+    _write( fd, (const void *)( buf ), (unsigned int)( len ) )
 #endif
 
 #if defined(_WIN32) || defined(_WIN32_WCE)
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 2c5d9eb..b99aeb6 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -254,7 +254,7 @@
 #define USAGE \
     "\n usage: ssl_server2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
-    "    server_addr=%%d      default: (all interfaces)\n"  \
+    "    server_addr=%%s      default: (all interfaces)\n"  \
     "    server_port=%%d      default: 4433\n"              \
     "    debug_level=%%d      default: 0 (disabled)\n"      \
     "    nbio=%%d             default: 0 (blocking I/O)\n"  \
@@ -1791,7 +1791,7 @@
             unsigned char *larger_buf;
 
             ori_len = ret;
-            extra_len = ssl_get_bytes_avail( &ssl );
+            extra_len = (int) ssl_get_bytes_avail( &ssl );
 
             larger_buf = polarssl_malloc( ori_len + extra_len + 1 );
             if( larger_buf == NULL )
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index ed695cb..0f97668 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1099,6 +1099,40 @@
             -s "=> renegotiate" \
             -s "write hello request"
 
+# Checks that no Signature Algorithm with SHA-1 gets negotiated. Negotiating SHA-1 would mean that
+# the server did not parse the Signature Algorithm extension. This test is valid only if an MD
+# algorithm stronger than SHA-1 is enabled in config.h
+run_test    "Renegotiation: Signature Algorithms parsing, client-initiated" \
+            "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional" \
+            "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \
+            0 \
+            -c "client hello, adding renegotiation extension" \
+            -s "received TLS_EMPTY_RENEGOTIATION_INFO" \
+            -s "found renegotiation extension" \
+            -s "server hello, secure renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -S "write hello request" \
+            -S "client hello v3, signature_algorithm ext: 2" # Is SHA-1 negotiated?
+
+# Checks that no Signature Algorithm with SHA-1 gets negotiated. Negotiating SHA-1 would mean that
+# the server did not parse the Signature Algorithm extension. This test is valid only if an MD
+# algorithm stronger than SHA-1 is enabled in config.h
+run_test    "Renegotiation: Signature Algorithms parsing, server-initiated" \
+            "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \
+            "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \
+            0 \
+            -c "client hello, adding renegotiation extension" \
+            -s "received TLS_EMPTY_RENEGOTIATION_INFO" \
+            -s "found renegotiation extension" \
+            -s "server hello, secure renegotiation extension" \
+            -c "found renegotiation extension" \
+            -c "=> renegotiate" \
+            -s "=> renegotiate" \
+            -s "write hello request" \
+            -S "client hello v3, signature_algorithm ext: 2" # Is SHA-1 negotiated?
+
 run_test    "Renegotiation: double" \
             "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \
             "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 135ec60..4f6cfd5 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1546,3 +1546,19 @@
 X509 Get time (UTC invalid sec)
 depends_on:POLARSSL_X509_USE_C
 x509_get_time:ASN1_UTC_TIME:"001130235960Z":POLARSSL_ERR_X509_INVALID_DATE:0:0:0:0:0:0
+
+X509 Get time (Generalized Time, year multiple of 100 but not 400 is not a leap year)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"19000229000000Z":POLARSSL_ERR_X509_INVALID_DATE:0:0:0:0:0:0
+
+X509 Get time (Generalized Time, year multiple of 4 but not 100 is a leap year)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"19920229000000Z":0:1992:2:29:0:0:0
+
+X509 Get time (Generalized Time, year multiple of 400 is a leap year)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"20000229000000Z":0:2000:2:29:0:0:0
+
+X509 Get time (Generalized Time invalid leap year not multiple of 4, 100 or 400)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"19910229000000Z":POLARSSL_ERR_X509_INVALID_DATE:0:0:0:0:0:0