Merge remote-tracking branch 'origin/pr/590' into baremetal
diff --git a/ChangeLog b/ChangeLog
index 985c11b..75f6220 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -28,6 +28,14 @@
      which allows copy-less parsing of DER encoded X.509 CRTs,
      at the cost of additional lifetime constraints on the input
      buffer, but at the benefit of reduced RAM consumption.
+   * Add new API function mbedtls_ssl_conf_extended_master_secret_enforce() to
+     allow enforcing the usage of ExtendedMasterSecret extension. If the
+     extension is used and this option is enabled, handshakes not leading to
+     the use of the extended master secret will be aborted. On the server,
+     fail the handshake if client doesn't advertise the ExtendedMasterSecret
+     extension. On the client, fail the handshake if the server doesn't
+     consent to the use of the ExtendedMasterSecret extension in its
+     ServerHello.
 
 API Changes
    * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 653f857..5066807 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -158,6 +158,9 @@
 #define MBEDTLS_SSL_EXTENDED_MS_DISABLED        0
 #define MBEDTLS_SSL_EXTENDED_MS_ENABLED         1
 
+#define MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED    0
+#define MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED     1
+
 #define MBEDTLS_SSL_CID_DISABLED                0
 #define MBEDTLS_SSL_CID_ENABLED                 1
 
@@ -1031,6 +1034,9 @@
 #endif
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
     unsigned int extended_ms : 1;   /*!< negotiate extended master secret?  */
+    unsigned int enforce_extended_master_secret : 1; /*!< enforce the usage
+                                                      *   of extended master
+                                                      *   secret            */
 #endif
 #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
     unsigned int anti_replay : 1;   /*!< detect and prevent replay?         */
@@ -2821,6 +2827,26 @@
  * \param ems       MBEDTLS_SSL_EXTENDED_MS_ENABLED or MBEDTLS_SSL_EXTENDED_MS_DISABLED
  */
 void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems );
+
+/**
+ * \brief           Enable or disable Extended Master Secret enforcing.
+ *                  (Default: MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED)
+ *
+ * \note            If the use of extended master secret is configured (see
+ *                  `mbedtls_ssl_conf_extended_master_secret()`) and this
+ *                  option is set, handshakes not leading to the use of the
+ *                  extended master secret will be aborted: On the server, fail
+ *                  the handshake if the client doesn't advertise the
+ *                  ExtendedMasterSecret extension. On the client: Fail the
+ *                  handshake if the server doesn't consent to the use of the
+ *                  ExtendedMasterSecret extension in its ServerHello.
+ *
+ * \param conf      Currently used SSL configuration struct.
+ * \param ems_enf   MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED or
+ *                  MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED
+ */
+void mbedtls_ssl_conf_extended_master_secret_enforce( mbedtls_ssl_config *conf,
+                                                      char ems_enf );
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
 
 #if defined(MBEDTLS_ARC4_C)
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 97aeac4..cd9793e 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -2085,6 +2085,21 @@
     }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
+    /*
+     * Check if extended master secret is being enforced
+     */
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+    if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED &&
+        ssl->conf->enforce_extended_master_secret ==
+        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED &&
+        ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "Peer not offering extended master "
+                                    "secret, while it is enforced") );
+        handshake_failure = 1;
+    }
+#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
+
     if( handshake_failure == 1 )
     {
         mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index a8fd49b..d40a21f 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -2035,6 +2035,21 @@
     }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
+    /*
+     * Check if extended master secret is being enforced
+     */
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+    if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED &&
+        ssl->conf->enforce_extended_master_secret ==
+        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED &&
+        ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "Peer not offering extended master "
+                                    "secret, while it is enforced") );
+        handshake_failure = 1;
+    }
+#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
+
     if( handshake_failure == 1 )
     {
         mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index bab00bb..ca4ab36 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -8413,6 +8413,12 @@
 {
     conf->extended_ms = ems;
 }
+
+void mbedtls_ssl_conf_extended_master_secret_enforce( mbedtls_ssl_config *conf,
+                                                        char ems_enf )
+{
+    conf->enforce_extended_master_secret = ems_enf;
+}
 #endif
 
 #if defined(MBEDTLS_ARC4_C)
@@ -10375,6 +10381,8 @@
 
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
     conf->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED;
+    conf->enforce_extended_master_secret =
+        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED;
 #endif
 
 #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 1665784..bbd4d25 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -122,6 +122,7 @@
 #define DFL_FALLBACK            -1
 #define DFL_EXTENDED_MS         -1
 #define DFL_ETM                 -1
+#define DFL_EXTENDED_MS_ENFORCE -1
 
 #define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: "
 #define GET_REQUEST_END "\r\n\r\n"
@@ -243,7 +244,8 @@
 
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
 #define USAGE_EMS \
-    "    extended_ms=0/1     default: (library default: on)\n"
+    "    extended_ms=0/1     default: (library default: on)\n" \
+    "    enforce_extended_master_secret=0/1 default: (library default: off)\n"
 #else
 #define USAGE_EMS ""
 #endif
@@ -410,6 +412,8 @@
     int fallback;               /* is this a fallback connection?           */
     int dgram_packing;          /* allow/forbid datagram packing            */
     int extended_ms;            /* negotiate extended master secret?        */
+    int enforce_extended_master_secret; /* Enforce the usage of extended
+                                         * master secret */
     int etm;                    /* negotiate encrypt then mac?              */
     int cid_enabled;            /* whether to use the CID extension or not  */
     int cid_enabled_renego;     /* whether to use the CID extension or not
@@ -825,6 +829,7 @@
     opt.dtls_mtu            = DFL_DTLS_MTU;
     opt.fallback            = DFL_FALLBACK;
     opt.extended_ms         = DFL_EXTENDED_MS;
+    opt.enforce_extended_master_secret = DFL_EXTENDED_MS_ENFORCE;
     opt.etm                 = DFL_ETM;
     opt.dgram_packing       = DFL_DGRAM_PACKING;
 
@@ -1025,6 +1030,21 @@
                 default: goto usage;
             }
         }
+        else if( strcmp( p, "enforce_extended_master_secret" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:
+                    opt.enforce_extended_master_secret =
+                        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED;
+                    break;
+                case 1:
+                    opt.enforce_extended_master_secret =
+                        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED;
+                    break;
+                default: goto usage;
+            }
+        }
         else if( strcmp( p, "curves" ) == 0 )
             opt.curves = q;
         else if( strcmp( p, "etm" ) == 0 )
@@ -1638,6 +1658,9 @@
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
     if( opt.extended_ms != DFL_EXTENDED_MS )
         mbedtls_ssl_conf_extended_master_secret( &conf, opt.extended_ms );
+    if( opt.enforce_extended_master_secret != DFL_EXTENDED_MS_ENFORCE )
+        mbedtls_ssl_conf_extended_master_secret_enforce( &conf,
+            opt.enforce_extended_master_secret );
 #endif
 
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 6d6293a..b048bc7 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -163,6 +163,7 @@
 #define DFL_DGRAM_PACKING        1
 #define DFL_EXTENDED_MS         -1
 #define DFL_ETM                 -1
+#define DFL_EXTENDED_MS_ENFORCE -1
 
 #define LONG_RESPONSE "<p>01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
     "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n"  \
@@ -342,7 +343,8 @@
 
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
 #define USAGE_EMS \
-    "    extended_ms=0/1     default: (library default: on)\n"
+    "    extended_ms=0/1     default: (library default: on)\n" \
+    "    enforce_extended_master_secret=0/1 default: (library default: off)\n"
 #else
 #define USAGE_EMS ""
 #endif
@@ -525,6 +527,8 @@
     const char *alpn_string;    /* ALPN supported protocols                 */
     const char *dhm_file;       /* the file with the DH parameters          */
     int extended_ms;            /* allow negotiation of extended MS?        */
+    int enforce_extended_master_secret; /* Enforce the usage of extended
+                                         * master secret */
     int etm;                    /* allow negotiation of encrypt-then-MAC?   */
     int transport;              /* TLS or DTLS?                             */
     int cookies;                /* Use cookies for DTLS? -1 to break them   */
@@ -1494,6 +1498,7 @@
     opt.dgram_packing       = DFL_DGRAM_PACKING;
     opt.badmac_limit        = DFL_BADMAC_LIMIT;
     opt.extended_ms         = DFL_EXTENDED_MS;
+    opt.enforce_extended_master_secret = DFL_EXTENDED_MS_ENFORCE;
     opt.etm                 = DFL_ETM;
 
     for( i = 1; i < argc; i++ )
@@ -1813,6 +1818,21 @@
                 default: goto usage;
             }
         }
+        else if( strcmp( p, "enforce_extended_master_secret" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:
+                    opt.enforce_extended_master_secret =
+                        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED;
+                    break;
+                case 1:
+                    opt.enforce_extended_master_secret =
+                        MBEDTLS_SSL_EXTENDED_MS_ENFORCE_ENABLED;
+                    break;
+                default: goto usage;
+            }
+        }
         else if( strcmp( p, "etm" ) == 0 )
         {
             switch( atoi( q ) )
@@ -2440,6 +2460,9 @@
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
     if( opt.extended_ms != DFL_EXTENDED_MS )
         mbedtls_ssl_conf_extended_master_secret( &conf, opt.extended_ms );
+    if( opt.enforce_extended_master_secret != DFL_EXTENDED_MS_ENFORCE )
+        mbedtls_ssl_conf_extended_master_secret_enforce( &conf,
+            opt.enforce_extended_master_secret );
 #endif
 
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index da89642..2ba0991 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1763,7 +1763,7 @@
 
 # Tests for Extended Master Secret extension
 
-run_test    "Extended Master Secret: default" \
+run_test    "Extended Master Secret: default (not enforcing)" \
             "$P_SRV debug_level=3" \
             "$P_CLI debug_level=3" \
             0 \
@@ -1774,7 +1774,60 @@
             -c "session hash for extended master secret" \
             -s "session hash for extended master secret"
 
-run_test    "Extended Master Secret: client enabled, server disabled" \
+run_test    "Extended Master Secret: both enabled, both enforcing" \
+            "$P_SRV debug_level=3 enforce_extended_master_secret=1" \
+            "$P_CLI debug_level=3 enforce_extended_master_secret=1" \
+            0 \
+            -c "client hello, adding extended_master_secret extension" \
+            -s "found extended master secret extension" \
+            -s "server hello, adding extended master secret extension" \
+            -c "found extended_master_secret extension" \
+            -c "session hash for extended master secret" \
+            -s "session hash for extended master secret"
+
+run_test    "Extended Master Secret: both enabled, client enforcing" \
+            "$P_SRV debug_level=3 enforce_extended_master_secret=0" \
+            "$P_CLI debug_level=3 enforce_extended_master_secret=1" \
+            0 \
+            -c "client hello, adding extended_master_secret extension" \
+            -s "found extended master secret extension" \
+            -s "server hello, adding extended master secret extension" \
+            -c "found extended_master_secret extension" \
+            -c "session hash for extended master secret" \
+            -s "session hash for extended master secret"
+
+run_test    "Extended Master Secret: both enabled, server enforcing" \
+            "$P_SRV debug_level=3 enforce_extended_master_secret=1" \
+            "$P_CLI debug_level=3 enforce_extended_master_secret=0" \
+            0 \
+            -c "client hello, adding extended_master_secret extension" \
+            -s "found extended master secret extension" \
+            -s "server hello, adding extended master secret extension" \
+            -c "found extended_master_secret extension" \
+            -c "session hash for extended master secret" \
+            -s "session hash for extended master secret"
+
+run_test    "Extended Master Secret: client enabled, server disabled, client enforcing" \
+            "$P_SRV debug_level=3 extended_ms=0" \
+            "$P_CLI debug_level=3 extended_ms=1 enforce_extended_master_secret=1" \
+            1 \
+            -c "client hello, adding extended_master_secret extension" \
+            -s "found extended master secret extension" \
+            -S "server hello, adding extended master secret extension" \
+            -C "found extended_master_secret extension" \
+            -c "Peer not offering extended master secret, while it is enforced"
+
+run_test    "Extended Master Secret enforced: client disabled, server enabled, server enforcing" \
+            "$P_SRV debug_level=3 extended_ms=1 enforce_extended_master_secret=1" \
+            "$P_CLI debug_level=3 extended_ms=0" \
+            1 \
+            -C "client hello, adding extended_master_secret extension" \
+            -S "found extended master secret extension" \
+            -S "server hello, adding extended master secret extension" \
+            -C "found extended_master_secret extension" \
+            -s "Peer not offering extended master secret, while it is enforced"
+
+run_test    "Extended Master Secret: client enabled, server disabled, not enforcing" \
             "$P_SRV debug_level=3 extended_ms=0" \
             "$P_CLI debug_level=3 extended_ms=1" \
             0 \
@@ -1785,7 +1838,7 @@
             -C "session hash for extended master secret" \
             -S "session hash for extended master secret"
 
-run_test    "Extended Master Secret: client disabled, server enabled" \
+run_test    "Extended Master Secret: client disabled, server enabled, not enforcing" \
             "$P_SRV debug_level=3 extended_ms=1" \
             "$P_CLI debug_level=3 extended_ms=0" \
             0 \
@@ -1796,6 +1849,17 @@
             -C "session hash for extended master secret" \
             -S "session hash for extended master secret"
 
+run_test    "Extended Master Secret: client disabled, server disabled" \
+            "$P_SRV debug_level=3 extended_ms=0" \
+            "$P_CLI debug_level=3 extended_ms=0" \
+            0 \
+            -C "client hello, adding extended_master_secret extension" \
+            -S "found extended master secret extension" \
+            -S "server hello, adding extended master secret extension" \
+            -C "found extended_master_secret extension" \
+            -C "session hash for extended master secret" \
+            -S "session hash for extended master secret"
+
 requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
 run_test    "Extended Master Secret: client SSLv3, server enabled" \
             "$P_SRV debug_level=3 min_version=ssl3" \