Merge remote-tracking branch 'origin/pr/590' into baremetal
diff --git a/ChangeLog b/ChangeLog
index a48baf4..75f6220 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,10 @@
      mbedtls_ssl_session_load() to allow serializing a session, for example to
      store it in non-volatile storage, and later using it for TLS session
      resumption.
+   * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`
+     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
@@ -33,6 +37,10 @@
      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()`.
+     See the Features section for more information.
+
 Bugfix
    * Server's RSA certificate in certs.c was SHA-1 signed. In the default
      mbedTLS configuration only SHA-2 signed certificates are accepted.
@@ -111,6 +119,8 @@
      leading content octet. Fixes #1610.
 
 Changes
+   * Reduce RAM consumption during session renegotiation by not storing
+     the peer CRT chain and session ticket twice.
    * Include configuration file in all header files that use configuration,
      instead of relying on other header files that they include.
      Inserted as an enhancement for #1371
diff --git a/configs/baremetal.h b/configs/baremetal.h
index 2fbc359..24cce6b 100644
--- a/configs/baremetal.h
+++ b/configs/baremetal.h
@@ -34,9 +34,6 @@
 #ifndef MBEDTLS_BAREMETAL_CONFIG_H
 #define MBEDTLS_BAREMETAL_CONFIG_H
 
-#define MBEDTLS_HAVE_TIME
-#define MBEDTLS_HAVE_TIME_DATE
-
 /* Symmetric crypto: AES-CCM only */
 #define MBEDTLS_CIPHER_C
 #define MBEDTLS_AES_C
diff --git a/configs/config-ccm-psk-tls1_2.h b/configs/config-ccm-psk-tls1_2.h
index c9b58dd..bd2c1a3 100644
--- a/configs/config-ccm-psk-tls1_2.h
+++ b/configs/config-ccm-psk-tls1_2.h
@@ -41,6 +41,7 @@
 /* mbed TLS feature support */
 #define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
 #define MBEDTLS_SSL_PROTO_TLS1_2
+#define MBEDTLS_SSL_PROTO_TLS
 
 /* mbed TLS modules */
 #define MBEDTLS_AES_C
diff --git a/configs/config-mini-tls1_1.h b/configs/config-mini-tls1_1.h
index 013bc03..349ea8e 100644
--- a/configs/config-mini-tls1_1.h
+++ b/configs/config-mini-tls1_1.h
@@ -40,6 +40,7 @@
 #define MBEDTLS_PKCS1_V15
 #define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
 #define MBEDTLS_SSL_PROTO_TLS1_1
+#define MBEDTLS_SSL_PROTO_TLS
 
 /* mbed TLS modules */
 #define MBEDTLS_AES_C
diff --git a/configs/config-suite-b.h b/configs/config-suite-b.h
index 18e2c40..e6fad1c 100644
--- a/configs/config-suite-b.h
+++ b/configs/config-suite-b.h
@@ -47,6 +47,7 @@
 #define MBEDTLS_ECP_DP_SECP384R1_ENABLED
 #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
 #define MBEDTLS_SSL_PROTO_TLS1_2
+#define MBEDTLS_SSL_PROTO_TLS
 
 /* mbed TLS modules */
 #define MBEDTLS_AES_C
diff --git a/configs/config-thread.h b/configs/config-thread.h
index 25db16b..3166aa9 100644
--- a/configs/config-thread.h
+++ b/configs/config-thread.h
@@ -29,6 +29,7 @@
  * Distinguishing features:
  * - no RSA or classic DH, fully based on ECC
  * - no X.509
+ * - no TLS, only DTLS
  * - support for experimental EC J-PAKE key exchange
  *
  * See README.txt for usage instructions.
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 48555f6..b3677b5 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -562,7 +562,12 @@
 #if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \
     !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
     !defined(MBEDTLS_SSL_PROTO_TLS1_2))
-#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active"
+#error "MBEDTLS_SSL_TLS_C defined, but no protocol version is active"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && \
+    ( !defined(MBEDTLS_SSL_PROTO_TLS) && !defined(MBEDTLS_SSL_PROTO_DTLS) )
+#error "MBEDTLS_SSL_TLS_C defined, but neither TLS or DTLS is active"
 #endif
 
 #if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index f5b2de9..e0b5ba4 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1453,7 +1453,7 @@
 /**
  * \def MBEDTLS_SSL_PROTO_SSL3
  *
- * Enable support for SSL 3.0.
+ * Enable support for SSL 3.0 (if TLS is enabled).
  *
  * Requires: MBEDTLS_MD5_C
  *           MBEDTLS_SHA1_C
@@ -1465,7 +1465,7 @@
 /**
  * \def MBEDTLS_SSL_PROTO_TLS1
  *
- * Enable support for TLS 1.0.
+ * Enable support for TLS 1.0 (if TLS is enabled).
  *
  * Requires: MBEDTLS_MD5_C
  *           MBEDTLS_SHA1_C
@@ -1477,7 +1477,8 @@
 /**
  * \def MBEDTLS_SSL_PROTO_TLS1_1
  *
- * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled).
+ * Enable support for TLS 1.1 (if TLS is enabled) and DTLS 1.0 (if DTLS is
+ * enabled).
  *
  * Requires: MBEDTLS_MD5_C
  *           MBEDTLS_SHA1_C
@@ -1489,7 +1490,8 @@
 /**
  * \def MBEDTLS_SSL_PROTO_TLS1_2
  *
- * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled).
+ * Enable support for TLS 1.2 (if TLS is enabled) and DTLS 1.2 (if DTLS is
+ * enabled).
  *
  * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C
  *           (Depends on ciphersuites)
@@ -1503,8 +1505,10 @@
  *
  * Enable support for DTLS (all available versions).
  *
- * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0,
- * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2.
+ * Enable this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2,
+ * and/or this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0.
+ *
+ * \see MBEDTLS_SSL_PROTO_TLS
  *
  * Requires: MBEDTLS_SSL_PROTO_TLS1_1
  *        or MBEDTLS_SSL_PROTO_TLS1_2
@@ -1514,6 +1518,27 @@
 #define MBEDTLS_SSL_PROTO_DTLS
 
 /**
+ * \def MBEDTLS_SSL_PROTO_TLS
+ *
+ * Enable support for SSL/TLS (all available versions).
+ *
+ * Enable this and MBEDTLS_SSL_PROTO_TLS1_2 to enable TLS 1.2;
+ * enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable TLS 1.1;
+ * enable this and MBEDTLS_SSL_PROTO_TLS1   to enable TLS 1.0;
+ * and/or this and MBEDTLS_SSL_PROTO_SSL3   to enable SSL 3.0 (deprecated).
+ *
+ * \see MBEDTLS_SSL_PROTO_DTLS
+ *
+ * Requires: MBEDTLS_SSL_PROTO_TLS1_2
+ *        or MBEDTLS_SSL_PROTO_TLS1_1
+ *        or MBEDTLS_SSL_PROTO_TLS1
+ *        or MBEDTLS_SSL_PROTO_SSL3 (deprecated)
+ *
+ * Comment this macro to disable support for TLS
+ */
+#define MBEDTLS_SSL_PROTO_TLS
+
+/**
  * \def MBEDTLS_SSL_ALPN
  *
  * Enable support for RFC 7301 Application Layer Protocol Negotiation.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index d219322..5066807 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1343,7 +1343,8 @@
 
 /**
  * \brief           Set the transport type (TLS or DTLS).
- *                  Default: TLS
+ *                  Default: TLS if #MBEDTLS_SSL_PROTO_TLS is defined, else
+ *                  DTLS.
  *
  * \note            For DTLS, you must either provide a recv callback that
  *                  doesn't block, or one that handles timeouts, see
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 45ea26a..1c8709f 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -264,6 +264,57 @@
 #define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT (1 << 0)
 #define MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK                 (1 << 1)
 
+/*
+ * Helpers for code specific to TLS or DTLS.
+ *
+ * Goals for these helpers:
+ *  - generate minimal code, eg don't test if mode is DTLS in a DTLS-only build
+ *  - make the flow clear to the compiler, so that in TLS and DTLS combined
+ *    builds, when there are two branches, it knows exactly one of them is taken
+ *  - preserve readability
+ *
+ * There are three macros:
+ *  - MBEDTLS_SSL_TRANSPORT_IS_TLS( transport )
+ *  - MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport )
+ *  - MBEDTLS_SSL_TRANSPORT_ELSE
+ *
+ * The first two are macros rather than static inline functions because some
+ * compilers (eg arm-none-eabi-gcc 5.4.1 20160919) don't propagate constants
+ * well enough for us with static inline functions.
+ *
+ * Usage 1 (can replace DTLS with TLS):
+ *  #if defined(MBEDTLS_SSL_PROTO_DTLS)
+ *  if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
+ *      // DTLS-specific code
+ *  #endif
+ *
+ * Usage 2 (can swap DTLS and TLS);
+ *  #if defined(MBEDTLS_SSL_PROTO_DTLS)
+ *  if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
+ *      // DTLS-specific code
+ *  MBEDTLS_SSL_TRANSPORT_ELSE
+ *  #endif
+ *  #if defined(MBEDTLS_SSL_PROTO_TLS)
+ *      // TLS-specific code
+ *  #endif
+ */
+#if defined(MBEDTLS_SSL_PROTO_DTLS) && defined(MBEDTLS_SSL_PROTO_TLS) /* both */
+#define MBEDTLS_SSL_TRANSPORT__BOTH /* shortcut for future tests */
+#define MBEDTLS_SSL_TRANSPORT_IS_TLS( transport ) \
+    ( (transport) == MBEDTLS_SSL_TRANSPORT_STREAM )
+#define MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) \
+    ( (transport) == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+#define MBEDTLS_SSL_TRANSPORT_ELSE                  else
+#elif defined(MBEDTLS_SSL_PROTO_DTLS) /* DTLS only */
+#define MBEDTLS_SSL_TRANSPORT_IS_TLS( transport )   0
+#define MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport )  1
+#define MBEDTLS_SSL_TRANSPORT_ELSE                  /* empty: no other branch */
+#else /* TLS only */
+#define MBEDTLS_SSL_TRANSPORT_IS_TLS( transport )   1
+#define MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport )  0
+#define MBEDTLS_SSL_TRANSPORT_ELSE                  /* empty: no other branch */
+#endif /* TLS and/or DTLS */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -905,12 +956,14 @@
 
 static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl )
 {
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
-        return( 12 );
-#else
+#if !defined(MBEDTLS_SSL_PROTO__BOTH)
     ((void) ssl);
 #endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
+        return( 12 );
+#endif
     return( 4 );
 }
 
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 670bd10..62c3c2e 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -52,6 +52,8 @@
  */
 typedef struct mbedtls_x509_crt
 {
+    int own_buffer;                     /**< Indicates if \c raw is owned
+                                         *   by the structure or not.        */
     mbedtls_x509_buf raw;               /**< The raw certificate data (DER). */
     mbedtls_x509_buf tbs;               /**< The raw certificate body (DER). The part that is To Be Signed. */
 
@@ -220,16 +222,58 @@
 
 /**
  * \brief          Parse a single DER formatted certificate and add it
- *                 to the chained list.
+ *                 to the end of the provided chained list.
  *
- * \param chain    points to the start of the chain
- * \param buf      buffer holding the certificate DER data
- * \param buflen   size of the buffer
+ * \param chain    The pointer to the start of the CRT chain to attach to.
+ *                 When parsing the first CRT in a chain, this should point
+ *                 to an instance of ::mbedtls_x509_crt initialized through
+ *                 mbedtls_x509_crt_init().
+ * \param buf      The buffer holding the DER encoded certificate.
+ * \param buflen   The size in Bytes of \p buf.
  *
- * \return         0 if successful, or a specific X509 or PEM error code
+ * \note           This function makes an internal copy of the CRT buffer
+ *                 \p buf. In particular, \p buf may be destroyed or reused
+ *                 after this call returns. To avoid duplicating the CRT
+ *                 buffer (at the cost of stricter lifetime constraints),
+ *                 use mbedtls_x509_crt_parse_der_nocopy() instead.
+ *
+ * \return         \c 0 if successful.
+ * \return         A negative error code on failure.
  */
-int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
-                        size_t buflen );
+int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
+                                const unsigned char *buf,
+                                size_t buflen );
+
+/**
+ * \brief          Parse a single DER formatted certificate and add it
+ *                 to the end of the provided chained list. This is a
+ *                 variant of mbedtls_x509_crt_parse_der() which takes
+ *                 temporary ownership of the CRT buffer until the CRT
+ *                 is destroyed.
+ *
+ * \param chain    The pointer to the start of the CRT chain to attach to.
+ *                 When parsing the first CRT in a chain, this should point
+ *                 to an instance of ::mbedtls_x509_crt initialized through
+ *                 mbedtls_x509_crt_init().
+ * \param buf      The address of the readable buffer holding the DER encoded
+ *                 certificate to use. On success, this buffer must be
+ *                 retained and not be changed for the liftetime of the
+ *                 CRT chain \p chain, that is, until \p chain is destroyed
+ *                 through a call to mbedtls_x509_crt_free().
+ * \param buflen   The size in Bytes of \p buf.
+ *
+ * \note           This call is functionally equivalent to
+ *                 mbedtls_x509_crt_parse_der(), but it avoids creating a
+ *                 copy of the input buffer at the cost of stronger lifetime
+ *                 constraints. This is useful in constrained environments
+ *                 where duplication of the CRT cannot be tolerated.
+ *
+ * \return         \c 0 if successful.
+ * \return         A negative error code on failure.
+ */
+int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain,
+                                       const unsigned char *buf,
+                                       size_t buflen );
 
 /**
  * \brief          Parse one DER-encoded or one or more concatenated PEM-encoded
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 2cf9c79..cd9793e 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -452,7 +452,7 @@
     */
 
     *olen = 0;
-    if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ||
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
         ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED )
     {
         return;
@@ -734,7 +734,7 @@
      * When responding to a verify request, MUST reuse random (RFC 6347 4.2.1)
      */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake->verify_cookie != NULL )
     {
         return( 0 );
@@ -785,7 +785,7 @@
         return( 1 );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
             ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) )
         return( 1 );
 #endif
@@ -926,7 +926,7 @@
      * DTLS cookie
      */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         if( ssl->handshake->verify_cookie == NULL )
         {
@@ -1021,7 +1021,7 @@
      * an actual need for it.
      */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         offer_compress = 0;
 #endif
 
@@ -1137,7 +1137,7 @@
     ssl->state++;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         mbedtls_ssl_send_flight_completed( ssl );
 #endif
 
@@ -1148,7 +1148,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
@@ -1252,7 +1252,7 @@
     size_t peer_cid_len;
 
     if( /* CID extension only makes sense in DTLS */
-        ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ||
+        MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
         /* The server must only send the CID extension if we have offered it. */
         ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED )
     {
@@ -1645,7 +1645,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         if( buf[0] == MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST )
         {
@@ -1762,12 +1762,7 @@
 
 #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 )
-        accept_comp = 0;
-    else
-#endif
-        accept_comp = 1;
+    accept_comp = MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport );
 
     if( comp != MBEDTLS_SSL_COMPRESS_NULL &&
         ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) )
@@ -3016,7 +3011,7 @@
     ssl->state++;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         mbedtls_ssl_recv_flight_completed( ssl );
 #endif
 
@@ -3598,6 +3593,15 @@
     if( ticket_len == 0 )
         return( 0 );
 
+    if( ssl->session != NULL && ssl->session->ticket != NULL )
+    {
+        mbedtls_platform_zeroize( ssl->session->ticket,
+                                  ssl->session->ticket_len );
+        mbedtls_free( ssl->session->ticket );
+        ssl->session->ticket = NULL;
+        ssl->session->ticket_len = 0;
+    }
+
     mbedtls_platform_zeroize( ssl->session_negotiate->ticket,
                               ssl->session_negotiate->ticket_len );
     mbedtls_free( ssl->session_negotiate->ticket );
@@ -3648,7 +3652,7 @@
         return( ret );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
     {
         if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 14202d8..d40a21f 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -441,7 +441,7 @@
     size_t peer_cid_len;
 
     /* CID extension only makes sense in DTLS */
-    if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
         mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
@@ -899,7 +899,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) )
         return( 0 );
 #endif
@@ -1304,12 +1304,13 @@
 
     buf = ssl->in_hdr;
 
-#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM )
-#endif
-        if( ( buf[0] & 0x80 ) != 0 )
-            return( ssl_parse_client_hello_v2( ssl ) );
+#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) && \
+    defined(MBEDTLS_SSL_PROTO_TLS)
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) &&
+        ( buf[0] & 0x80 ) != 0 )
+    {
+        return( ssl_parse_client_hello_v2( ssl ) );
+    }
 #endif
 
     MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, mbedtls_ssl_in_hdr_len( ssl ) );
@@ -1353,7 +1354,7 @@
     /* For DTLS if this is the initial handshake, remember the client sequence
      * number to use it in our next message (RFC 6347 4.2.1) */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport )
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
         && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE
 #endif
@@ -1407,13 +1408,19 @@
             return( ret );
         }
 
-    /* Done reading this record, get ready for the next one */
+        /* Done reading this record, get ready for the next one */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
+        {
             ssl->next_record_offset = msg_len + mbedtls_ssl_in_hdr_len( ssl );
-        else
+        }
+        MBEDTLS_SSL_TRANSPORT_ELSE
 #endif
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+        {
             ssl->in_left = 0;
+        }
+#endif
     }
 
     buf = ssl->in_msg;
@@ -1456,7 +1463,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         /*
          * Copy the client's handshake message_seq on initial handshakes,
@@ -1595,7 +1602,7 @@
      * Check the cookie length and content
      */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         cookie_offset = 35 + sess_len;
         cookie_len = buf[cookie_offset];
@@ -1650,9 +1657,13 @@
      */
         ciph_offset = cookie_offset + 1 + cookie_len;
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    {
         ciph_offset = 35 + sess_len;
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     ciph_len = ( buf[ciph_offset + 0] << 8 )
              | ( buf[ciph_offset + 1]      );
@@ -1704,7 +1715,7 @@
 
     /* See comments in ssl_write_client_hello() */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL;
 #endif
 
@@ -2101,7 +2112,7 @@
     ssl->state++;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         mbedtls_ssl_recv_flight_completed( ssl );
 #endif
 
@@ -2536,7 +2547,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
@@ -2562,7 +2573,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello" ) );
 
 #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake->verify_cookie_len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "client hello was not authenticated" ) );
@@ -3520,7 +3531,7 @@
     ssl->state++;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         mbedtls_ssl_send_flight_completed( ssl );
 #endif
 
@@ -3531,7 +3542,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
@@ -4416,7 +4427,7 @@
         return( ret );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
     {
         if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 1f8690a..ca4ab36 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -61,12 +61,14 @@
 /* Length of the "epoch" field in the record header */
 static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl )
 {
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
-        return( 2 );
-#else
+#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
     ((void) ssl);
 #endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
+        return( 2 );
+#endif
     return( 0 );
 }
 
@@ -135,7 +137,7 @@
                          unsigned char const *own_cid,
                          size_t own_cid_len )
 {
-    if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
     ssl->negotiate_cid = enable;
@@ -170,7 +172,7 @@
 {
     *enabled = MBEDTLS_SSL_CID_DISABLED;
 
-    if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ||
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
         ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
@@ -3023,7 +3025,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         uint32_t timeout;
 
@@ -3164,8 +3166,9 @@
 
         ssl->in_left = ret;
     }
-    else
-#endif
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d",
                        ssl->in_left, nb_want ) );
@@ -3212,6 +3215,7 @@
             ssl->in_left += ret;
         }
     }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) );
 
@@ -3267,15 +3271,17 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         ssl->out_hdr = ssl->out_buf;
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         ssl->out_hdr = ssl->out_buf + 8;
     }
+#endif
     ssl_update_out_pointers( ssl, ssl->transform_out );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) );
@@ -3686,7 +3692,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake != NULL &&
         ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
     {
@@ -3729,7 +3735,7 @@
          *      uint24 fragment_length;
          */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         {
             /* Make room for the additional DTLS fields */
             if( MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen < 8 )
@@ -3771,7 +3777,7 @@
 
     /* Either send now, or just save to be sent (and resent) later */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
             hs_type          == MBEDTLS_SSL_HS_HELLO_REQUEST ) )
     {
@@ -3909,7 +3915,7 @@
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
         /* In case of DTLS, double-check that we don't exceed
          * the remaining space in the datagram. */
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         {
             ret = ssl_get_remaining_space_in_datagram( ssl );
             if( ret < 0 )
@@ -3951,7 +3957,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         flush == SSL_DONT_FORCE_FLUSH )
     {
         size_t remaining;
@@ -4135,7 +4141,7 @@
                         ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         int ret;
         unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
@@ -4199,14 +4205,18 @@
             return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
         }
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
-    /* With TLS we don't handle fragmentation (for now) */
-    if( ssl->in_msglen < ssl->in_hslen )
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLS handshake fragmentation not supported" ) );
-        return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        /* With TLS we don't handle fragmentation (for now) */
+        if( ssl->in_msglen < ssl->in_hslen )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLS handshake fragmentation not supported" ) );
+            return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
     }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     return( 0 );
 }
@@ -4222,7 +4232,7 @@
 
     /* Handshake message is complete, increment counter */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake != NULL )
     {
         unsigned offset;
@@ -4574,7 +4584,7 @@
 
     /* Check record type */
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->in_msgtype      == MBEDTLS_SSL_MSG_CID            &&
         ssl->conf->cid_len   != 0 )
     {
@@ -4602,13 +4612,15 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) );
 
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
+#if defined(MBEDTLS_SSL_PROTO_TLS)
         /* Silently ignore invalid DTLS records as recommended by RFC 6347
-         * Section 4.1.2.7 */
-        if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
+         * Section 4.1.2.7, that is, send alert only with TLS */
+        if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
+        {
             mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
                                     MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
         return( MBEDTLS_ERR_SSL_INVALID_RECORD );
     }
@@ -4669,7 +4681,7 @@
      * record leads to the entire datagram being dropped.
      */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1];
 
@@ -4904,26 +4916,23 @@
         else
             ssl->nb_zero = 0;
 
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
-        {
-            ; /* in_ctr read from peer, not maintained internally */
-        }
-        else
-#endif
+        /* Only needed for TLS, as with DTLS in_ctr is read from the header */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+        if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
         {
             unsigned i;
-            for( i = 8; i > ssl_ep_len( ssl ); i-- )
+            for( i = 8; i > 0; i-- )
                 if( ++ssl->in_ctr[i - 1] != 0 )
                     break;
 
-            /* The loop goes to its end iff the counter is wrapping */
-            if( i == ssl_ep_len( ssl ) )
+            /* The loop goes to its end only if the counter is wrapping around */
+            if( i == 0 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) );
                 return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
             }
         }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     }
 
@@ -4940,7 +4949,7 @@
 #endif /* MBEDTLS_ZLIB_SUPPORT */
 
 #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         mbedtls_ssl_dtls_replay_update( ssl );
     }
@@ -4986,7 +4995,7 @@
 
                 /* We only check for buffered messages if the
                  * current datagram is fully consumed. */
-                if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+                if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
                     ssl_next_record_is_in_datagram( ssl ) == 0 )
                 {
                     if( ssl_load_buffered_message( ssl ) == 0 )
@@ -5509,7 +5518,7 @@
     size_t rec_len;
     unsigned rec_epoch;
 
-    if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
         return( 0 );
 
     if( hs == NULL )
@@ -5647,7 +5656,7 @@
     if( ( ret = ssl_parse_record_header( ssl ) ) != 0 )
     {
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
             ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
         {
             if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE )
@@ -5698,7 +5707,7 @@
 
     /* Done reading this record, get ready for the next one */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         ssl->next_record_offset = ssl->in_msglen + mbedtls_ssl_in_hdr_len( ssl );
         if( ssl->next_record_offset < ssl->in_left )
@@ -5706,14 +5715,18 @@
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "more than one record within datagram" ) );
         }
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    {
         ssl->in_left = 0;
+    }
+#endif
 
     if( ( ret = ssl_prepare_record_content( ssl ) ) != 0 )
     {
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         {
             /* Silently discard invalid records */
             if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
@@ -5756,8 +5769,9 @@
 
             return( ret );
         }
-        else
-#endif
+        MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
         {
             /* Error out (and send alert) on invalid records */
 #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
@@ -5770,6 +5784,7 @@
 #endif
             return( ret );
         }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
     }
 
     return( 0 );
@@ -5807,7 +5822,7 @@
         }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
             ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC    &&
             ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
         {
@@ -5882,7 +5897,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         /* Drop unexpected ApplicationData records,
          * except at the beginning of renegotiations */
@@ -6120,6 +6135,23 @@
     return( ret );
 }
 
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
+                                         unsigned char *crt_buf,
+                                         size_t crt_buf_len )
+{
+    mbedtls_x509_crt const * const peer_crt = ssl->session->peer_cert;
+
+    if( peer_crt == NULL )
+        return( -1 );
+
+    if( peer_crt->raw.len != crt_buf_len )
+        return( -1 );
+
+    return( memcmp( peer_crt->raw.p, crt_buf, crt_buf_len ) );
+}
+#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
+
 /*
  * Once the certificate message is read, parse it into a cert chain and
  * perform basic checks, but leave actual verification to the caller
@@ -6210,43 +6242,40 @@
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
+    /* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */
+    i += 3;
+
     /* In case we tried to reuse a session but it failed */
     if( ssl->session_negotiate->peer_cert != NULL )
     {
         mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert );
         mbedtls_free( ssl->session_negotiate->peer_cert );
+        ssl->session_negotiate->peer_cert = NULL;
     }
 
-    if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1,
-                    sizeof( mbedtls_x509_crt ) ) ) == NULL )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
-                       sizeof( mbedtls_x509_crt ) ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
-        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-    }
-
-    mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert );
-
-    i += 3;
-
+    /* Iterate through and parse the CRTs in the provided chain. */
     while( i < ssl->in_hslen )
     {
+        /* Check that there's room for the next CRT's length fields. */
         if ( i + 3 > ssl->in_hslen ) {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                           MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_send_alert_message( ssl,
+                              MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                              MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
+        /* In theory, the CRT can be up to 2**24 Bytes, but we don't support
+         * anything beyond 2**16 ~ 64K. */
         if( ssl->in_msg[i] != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_send_alert_message( ssl,
+                            MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
+        /* Read length of the next CRT in the chain. */
         n = ( (unsigned int) ssl->in_msg[i + 1] << 8 )
             | (unsigned int) ssl->in_msg[i + 2];
         i += 3;
@@ -6254,72 +6283,101 @@
         if( n < 128 || i + n > ssl->in_hslen )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_send_alert_message( ssl,
+                                 MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                 MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
+        /* Check if we're handling the first CRT in the chain. */
+        if( ssl->session_negotiate->peer_cert == NULL )
+        {
+            /* During client-side renegotiation, check that the server's
+             * end-CRTs hasn't changed compared to the initial handshake,
+             * mitigating the triple handshake attack. On success, reuse
+             * the original end-CRT instead of parsing it again. */
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+            if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
+                ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) );
+                if( ssl_check_peer_crt_unchanged( ssl,
+                                                  &ssl->in_msg[i],
+                                                  n ) != 0 )
+                {
+                    MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
+                    mbedtls_ssl_send_alert_message( ssl,
+                             MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                             MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
+                    return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
+                }
+
+                /* Move CRT chain structure to new session instance. */
+                ssl->session_negotiate->peer_cert = ssl->session->peer_cert;
+                ssl->session->peer_cert = NULL;
+
+                /* Delete all remaining CRTs from the original CRT chain. */
+                mbedtls_x509_crt_free(
+                    ssl->session_negotiate->peer_cert->next );
+                mbedtls_free( ssl->session_negotiate->peer_cert->next );
+                ssl->session_negotiate->peer_cert->next = NULL;
+
+                i += n;
+                continue;
+            }
+#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
+
+            /* Outside of client-side renegotiation, create a fresh X.509 CRT
+             * instance to parse the end-CRT into. */
+
+            ssl->session_negotiate->peer_cert =
+                mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
+            if( ssl->session_negotiate->peer_cert == NULL )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
+                                            sizeof( mbedtls_x509_crt ) ) );
+                mbedtls_ssl_send_alert_message( ssl,
+                               MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                               MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+                return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+            }
+
+            mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert );
+
+            /* Intentional fall through */
+        }
+
+        /* Parse the next certificate in the chain. */
         ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert,
-                                  ssl->in_msg + i, n );
+                                          ssl->in_msg + i, n );
         switch( ret )
         {
-        case 0: /*ok*/
-        case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND:
-            /* Ignore certificate with an unknown algorithm: maybe a
-               prior certificate was already trusted. */
-            break;
+            case 0: /*ok*/
+            case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND:
+                /* Ignore certificate with an unknown algorithm: maybe a
+                   prior certificate was already trusted. */
+                break;
 
-        case MBEDTLS_ERR_X509_ALLOC_FAILED:
-            alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR;
-            goto crt_parse_der_failed;
+            case MBEDTLS_ERR_X509_ALLOC_FAILED:
+                alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR;
+                goto crt_parse_der_failed;
 
-        case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
-            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            goto crt_parse_der_failed;
+            case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
+                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+                goto crt_parse_der_failed;
 
-        default:
-            alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
-        crt_parse_der_failed:
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
-            MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
-            return( ret );
+            default:
+                alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
+            crt_parse_der_failed:
+                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
+                MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
+                return( ret );
         }
 
         i += n;
     }
 
     MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert );
-
-    /*
-     * On client, make sure the server cert doesn't change during renego to
-     * avoid "triple handshake" attack: https://secure-resumption.com/
-     */
-#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
-        ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
-    {
-        if( ssl->session->peer_cert == NULL )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
-            return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
-        }
-
-        if( ssl->session->peer_cert->raw.len !=
-            ssl->session_negotiate->peer_cert->raw.len ||
-            memcmp( ssl->session->peer_cert->raw.p,
-                    ssl->session_negotiate->peer_cert->raw.p,
-                    ssl->session->peer_cert->raw.len ) != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "server cert changed during renegotiation" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
-            return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
-        }
-    }
-#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
-
     return( 0 );
 }
 
@@ -6612,7 +6670,7 @@
     ssl->session_in = ssl->session_negotiate;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
 #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
         ssl_dtls_replay_reset( ssl );
@@ -6627,9 +6685,13 @@
             return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
         }
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
-    memset( ssl->in_ctr, 0, 8 );
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    {
+        memset( ssl->in_ctr, 0, 8 );
+    }
+#endif
 
     ssl_update_in_pointers( ssl );
 
@@ -7057,7 +7119,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->handshake->flight != NULL )
     {
         /* Cancel handshake timer */
@@ -7128,7 +7190,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         unsigned char i;
 
@@ -7151,9 +7213,13 @@
             return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
         }
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
-    memset( ssl->cur_out_ctr, 0, 8 );
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    {
+        memset( ssl->cur_out_ctr, 0, 8 );
+    }
+#endif
 
     ssl->transform_out = ssl->transform_negotiate;
     ssl->session_out = ssl->session_negotiate;
@@ -7170,7 +7236,7 @@
 #endif
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         mbedtls_ssl_send_flight_completed( ssl );
 #endif
 
@@ -7181,7 +7247,7 @@
     }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
@@ -7270,7 +7336,7 @@
         ssl->state++;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         mbedtls_ssl_recv_flight_completed( ssl );
 #endif
 
@@ -7402,7 +7468,7 @@
     ssl_handshake_params_init( ssl->handshake );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         ssl->handshake->alt_transform_out = ssl->transform_out;
 
@@ -7459,7 +7525,7 @@
                                      mbedtls_ssl_transform *transform )
 {
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         ssl->out_ctr = ssl->out_hdr +  3;
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
@@ -7472,8 +7538,9 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
         ssl->out_iv  = ssl->out_len + 2;
     }
-    else
-#endif
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         ssl->out_ctr = ssl->out_hdr - 8;
         ssl->out_len = ssl->out_hdr + 3;
@@ -7482,6 +7549,7 @@
 #endif
         ssl->out_iv  = ssl->out_hdr + 5;
     }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     /* Adjust out_msg to make space for explicit IV, if used. */
     if( transform != NULL &&
@@ -7514,7 +7582,7 @@
      */
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         /* This sets the header pointers to match records
          * without CID. When we receive a record containing
@@ -7529,8 +7597,9 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
         ssl->in_iv  = ssl->in_len + 2;
     }
-    else
-#endif
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         ssl->in_ctr = ssl->in_hdr - 8;
         ssl->in_len = ssl->in_hdr + 3;
@@ -7539,6 +7608,7 @@
 #endif
         ssl->in_iv  = ssl->in_hdr + 5;
     }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     /* This will be adjusted at record decryption time. */
     ssl->in_msg = ssl->in_iv;
@@ -7560,17 +7630,19 @@
 {
     /* Set the incoming and outgoing record pointers. */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         ssl->out_hdr = ssl->out_buf;
         ssl->in_hdr  = ssl->in_buf;
     }
-    else
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         ssl->out_hdr = ssl->out_buf + 8;
         ssl->in_hdr  = ssl->in_buf  + 8;
     }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 
     /* Derive other internal pointers. */
     ssl_update_out_pointers( ssl, NULL /* no transform enabled */ );
@@ -8502,7 +8574,7 @@
      */
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->in_left > ssl->next_record_offset )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more records within current datagram" ) );
@@ -8561,7 +8633,7 @@
 const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl )
 {
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         switch( ssl->minor_ver )
         {
@@ -9356,7 +9428,7 @@
     /* RFC 6347 4.2.2: "[...] the HelloRequest will have message_seq = 0 and
      * the ServerHello will have message_seq = 1" */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
         ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING )
     {
         if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
@@ -9482,7 +9554,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
         if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
             return( ret );
@@ -9583,7 +9655,7 @@
 
                 /* With DTLS, drop the packet (probably from last handshake) */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-                if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+                if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
                 {
                     continue;
                 }
@@ -9600,7 +9672,7 @@
 
                 /* With DTLS, drop the packet (probably from last handshake) */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-                if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+                if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
                 {
                     continue;
                 }
@@ -9622,7 +9694,7 @@
 
                 /* DTLS clients need to know renego is server-initiated */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-                if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+                if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
                     ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
                 {
                     ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING;
@@ -9799,16 +9871,20 @@
     if( len > max_len )
     {
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-        if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+        if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment larger than the (negotiated) "
                                 "maximum fragment length: %d > %d",
                                 len, max_len ) );
             return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
         }
-        else
+        MBEDTLS_SSL_TRANSPORT_ELSE
 #endif
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+        {
             len = max_len;
+        }
+#endif
     }
 
     if( ssl->out_left != 0 )
@@ -10222,6 +10298,10 @@
 void mbedtls_ssl_config_init( mbedtls_ssl_config *conf )
 {
     memset( conf, 0, sizeof( mbedtls_ssl_config ) );
+
+#if !defined(MBEDTLS_SSL_PROTO_TLS)
+    conf->transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
+#endif
 }
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
@@ -10399,7 +10479,7 @@
             conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION;
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-            if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+            if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
                 conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2;
 #endif
 
@@ -10772,8 +10852,12 @@
 void mbedtls_ssl_write_version( int major, int minor, int transport,
                         unsigned char ver[2] )
 {
+#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
+    ((void) transport);
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
     {
         if( minor == MBEDTLS_SSL_MINOR_VERSION_2 )
             --minor; /* DTLS 1.0 stored as TLS 1.1 internally */
@@ -10781,21 +10865,25 @@
         ver[0] = (unsigned char)( 255 - ( major - 2 ) );
         ver[1] = (unsigned char)( 255 - ( minor - 1 ) );
     }
-    else
-#else
-    ((void) transport);
+    MBEDTLS_SSL_TRANSPORT_ELSE
 #endif
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         ver[0] = (unsigned char) major;
         ver[1] = (unsigned char) minor;
     }
+#endif
 }
 
 void mbedtls_ssl_read_version( int *major, int *minor, int transport,
                        const unsigned char ver[2] )
 {
+#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
+    ((void) transport);
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
     {
         *major = 255 - ver[0] + 2;
         *minor = 255 - ver[1] + 1;
@@ -10803,14 +10891,14 @@
         if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 )
             ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */
     }
-    else
-#else
-    ((void) transport);
-#endif
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
     {
         *major = ver[0];
         *minor = ver[1];
     }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 }
 
 int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md )
diff --git a/library/version_features.c b/library/version_features.c
index 7494b42..fc0b1f8 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -486,6 +486,9 @@
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     "MBEDTLS_SSL_PROTO_DTLS",
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    "MBEDTLS_SSL_PROTO_TLS",
+#endif /* MBEDTLS_SSL_PROTO_TLS */
 #if defined(MBEDTLS_SSL_ALPN)
     "MBEDTLS_SSL_ALPN",
 #endif /* MBEDTLS_SSL_ALPN */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index ebd118d..2c93311 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -829,8 +829,10 @@
 /*
  * Parse and fill a single X.509 certificate in DER format
  */
-static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf,
-                                    size_t buflen )
+static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
+                                    const unsigned char *buf,
+                                    size_t buflen,
+                                    int make_copy )
 {
     int ret;
     size_t len;
@@ -847,7 +849,7 @@
     if( crt == NULL || buf == NULL )
         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
 
-    // Use the original buffer until we figure out actual length
+    /* Use the original buffer until we figure out actual length. */
     p = (unsigned char*) buf;
     len = buflen;
     end = p + len;
@@ -865,25 +867,26 @@
         return( MBEDTLS_ERR_X509_INVALID_FORMAT );
     }
 
-    if( len > (size_t) ( end - p ) )
-    {
-        mbedtls_x509_crt_free( crt );
-        return( MBEDTLS_ERR_X509_INVALID_FORMAT +
-                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
-    }
-    crt_end = p + len;
-
-    // Create and populate a new buffer for the raw field
-    crt->raw.len = crt_end - buf;
-    crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
-    if( p == NULL )
-        return( MBEDTLS_ERR_X509_ALLOC_FAILED );
-
-    memcpy( p, buf, crt->raw.len );
-
-    // Direct pointers to the new buffer
-    p += crt->raw.len - len;
     end = crt_end = p + len;
+    crt->raw.len = crt_end - buf;
+    if( make_copy != 0 )
+    {
+        /* Create and populate a new buffer for the raw field. */
+        crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
+        if( crt->raw.p == NULL )
+            return( MBEDTLS_ERR_X509_ALLOC_FAILED );
+
+        memcpy( crt->raw.p, buf, crt->raw.len );
+        crt->own_buffer = 1;
+
+        p += crt->raw.len - len;
+        end = crt_end = p + len;
+    }
+    else
+    {
+        crt->raw.p = (unsigned char*) buf;
+        crt->own_buffer = 0;
+    }
 
     /*
      * TBSCertificate  ::=  SEQUENCE  {
@@ -1086,8 +1089,10 @@
  * Parse one X.509 certificate in DER format from a buffer and add them to a
  * chained list
  */
-int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
-                        size_t buflen )
+static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain,
+                                                const unsigned char *buf,
+                                                size_t buflen,
+                                                int make_copy )
 {
     int ret;
     mbedtls_x509_crt *crt = chain, *prev = NULL;
@@ -1119,7 +1124,7 @@
         crt = crt->next;
     }
 
-    if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 )
+    if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 )
     {
         if( prev )
             prev->next = NULL;
@@ -1133,11 +1138,27 @@
     return( 0 );
 }
 
+int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain,
+                                       const unsigned char *buf,
+                                       size_t buflen )
+{
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0 ) );
+}
+
+int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
+                                const unsigned char *buf,
+                                size_t buflen )
+{
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1 ) );
+}
+
 /*
  * Parse one or more PEM certificates from a buffer and add them to the chained
  * list
  */
-int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen )
+int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain,
+                            const unsigned char *buf,
+                            size_t buflen )
 {
 #if defined(MBEDTLS_PEM_PARSE_C)
     int success = 0, first_error = 0, total_failed = 0;
@@ -2675,7 +2696,7 @@
             mbedtls_free( seq_prv );
         }
 
-        if( cert_cur->raw.p != NULL )
+        if( cert_cur->raw.p != NULL && cert_cur->own_buffer )
         {
             mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );
             mbedtls_free( cert_cur->raw.p );
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index e1d1332..be35a76 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -1338,6 +1338,14 @@
     }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    if( strcmp( "MBEDTLS_SSL_PROTO_TLS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_PROTO_TLS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
+
 #if defined(MBEDTLS_SSL_ALPN)
     if( strcmp( "MBEDTLS_SSL_ALPN", config ) == 0 )
     {
diff --git a/programs/ssl/ssl_client1.c b/programs/ssl/ssl_client1.c
index 646909f..fc601ec 100644
--- a/programs/ssl/ssl_client1.c
+++ b/programs/ssl/ssl_client1.c
@@ -43,14 +43,15 @@
     !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
     !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) ||         \
     !defined(MBEDTLS_CERTS_C) || !defined(MBEDTLS_PEM_PARSE_C) || \
-    !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C)
+    !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+    !defined(MBEDTLS_SSL_PROTO_TLS)
 int main( void )
 {
     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
            "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
            "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
-           "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
-           "not defined.\n");
+           "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or"
+           "MBEDTLS_SSL_PROTO_TLS not defined.\n");
     return( 0 );
 }
 #else
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 9220d5d..bbd4d25 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -224,7 +224,7 @@
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 #define USAGE_DTLS \
-    "    dtls=%%d             default: 0 (TLS)\n"                           \
+    "    dtls=%%d             default: 0 (TLS) (if both enabled)\n" \
     "    hs_timeout=%%d-%%d    default: (library default: 1000-60000)\n"    \
     "                        range of DTLS handshake timeouts in millisecs\n" \
     "    mtu=%%d              default: (library default: unlimited)\n"  \
diff --git a/programs/ssl/ssl_fork_server.c b/programs/ssl/ssl_fork_server.c
index b6f1cc4..62b4c40 100644
--- a/programs/ssl/ssl_fork_server.c
+++ b/programs/ssl/ssl_fork_server.c
@@ -43,7 +43,8 @@
     !defined(MBEDTLS_SSL_SRV_C) || !defined(MBEDTLS_NET_C) ||     \
     !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_CTR_DRBG_C) ||    \
     !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_TIMING_C) || \
-    !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_PEM_PARSE_C)
+    !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_PEM_PARSE_C) || \
+    !defined(MBEDTLS_SSL_PROTO_TLS)
 int main( int argc, char *argv[] )
 {
     ((void) argc);
@@ -53,7 +54,8 @@
            "and/or MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or "
            "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
            "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
-           "MBEDTLS_TIMING_C and/or MBEDTLS_PEM_PARSE_C not defined.\n");
+           "MBEDTLS_TIMING_C and/or MBEDTLS_PEM_PARSE_C and/or "
+           "MBEDTLS_SSL_PROTO_TLS not defined.\n");
     return( 0 );
 }
 #elif defined(_WIN32)
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index c73297c..55c90c6 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -48,14 +48,14 @@
     !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
     !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) ||         \
     !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
-    !defined(MBEDTLS_FS_IO)
+    !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_SSL_PROTO_TLS)
 int main( void )
 {
     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
            "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
            "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
-           "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
-           "not defined.\n");
+           "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
+           "MBEDTLS_SSL_PROTO_TLS not defined.\n");
     return( 0 );
 }
 #else
diff --git a/programs/ssl/ssl_pthread_server.c b/programs/ssl/ssl_pthread_server.c
index b502695..b00f476 100644
--- a/programs/ssl/ssl_pthread_server.c
+++ b/programs/ssl/ssl_pthread_server.c
@@ -45,7 +45,7 @@
     !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_CTR_DRBG_C) ||            \
     !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) ||      \
     !defined(MBEDTLS_THREADING_C) || !defined(MBEDTLS_THREADING_PTHREAD) || \
-    !defined(MBEDTLS_PEM_PARSE_C)
+    !defined(MBEDTLS_PEM_PARSE_C) || !defined(MBEDTLS_SSL_PROTO_TLS)
 int main( void )
 {
     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_CERTS_C and/or MBEDTLS_ENTROPY_C "
@@ -53,7 +53,8 @@
            "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
            "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
            "MBEDTLS_THREADING_C and/or MBEDTLS_THREADING_PTHREAD "
-           "and/or MBEDTLS_PEM_PARSE_C not defined.\n");
+           "and/or MBEDTLS_PEM_PARSE_C and/or "
+           "MBEDTLS_SSL_PROTO_TLS not defined.\n");
     return( 0 );
 }
 #else
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
index 1852b2b..05d58fa 100644
--- a/programs/ssl/ssl_server.c
+++ b/programs/ssl/ssl_server.c
@@ -44,14 +44,15 @@
     !defined(MBEDTLS_SSL_SRV_C) || !defined(MBEDTLS_NET_C) ||     \
     !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_CTR_DRBG_C) ||    \
     !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) || \
-    !defined(MBEDTLS_PEM_PARSE_C)
+    !defined(MBEDTLS_PEM_PARSE_C) || !defined(MBEDTLS_SSL_PROTO_TLS)
 int main( void )
 {
     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_CERTS_C and/or MBEDTLS_ENTROPY_C "
            "and/or MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or "
            "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
            "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
-           "and/or MBEDTLS_PEM_PARSE_C not defined.\n");
+           "and/or MBEDTLS_PEM_PARSE_C and/or "
+           "MBEDTLS_SSL_PROTO_TLS not defined.\n");
     return( 0 );
 }
 #else
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 4dcbb16..b048bc7 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -330,7 +330,7 @@
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 #define USAGE_DTLS \
-    "    dtls=%%d             default: 0 (TLS)\n"                           \
+    "    dtls=%%d             default: 0 (TLS) (if both enabled)\n" \
     "    hs_timeout=%%d-%%d    default: (library default: 1000-60000)\n"    \
     "                        range of DTLS handshake timeouts in millisecs\n" \
     "    mtu=%%d              default: (library default: unlimited)\n"  \
diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c
index 999c87e..979910e 100644
--- a/programs/test/udp_proxy.c
+++ b/programs/test/udp_proxy.c
@@ -637,32 +637,17 @@
 static unsigned char dropped[2048] = { 0 };
 #define DROP_MAX 2
 
-/*
- * OpenSSL groups packets in a datagram the first time it sends them, but not
- * when it resends them. Count every record as seen the first time.
- */
+/* We only drop packets at the level of entire datagrams, not at the level
+ * of records. In particular, if the peer changes the way it packs multiple
+ * records into a single datagram, we don't necessarily count the number of
+ * times a record has been dropped correctly. However, the only known reason
+ * why a peer would change datagram packing is disabling the latter on
+ * retransmission, in which case we'd drop involved records at most
+ * DROP_MAX + 1 times. */
 void update_dropped( const packet *p )
 {
     size_t id = p->len % sizeof( dropped );
-    const unsigned char *end = p->buf + p->len;
-    const unsigned char *cur = p->buf;
-    size_t len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
-
     ++dropped[id];
-
-    /* Avoid counting single record twice */
-    if( len == p->len )
-        return;
-
-    while( cur < end )
-    {
-        len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
-
-        id = len % sizeof( dropped );
-        ++dropped[id];
-
-        cur += len;
-    }
 }
 
 int handle_message( const char *way,
diff --git a/scripts/baremetal.sh b/scripts/baremetal.sh
index 86fac56..4b798b9 100755
--- a/scripts/baremetal.sh
+++ b/scripts/baremetal.sh
@@ -94,6 +94,11 @@
     echo "ROM statistics written to:"
     echo "* $ROM_OUT_FILE"
     echo "* $ROM_OUT_SYMS"
+
+    # Print summary
+    cat $ROM_OUT_FILE | grep "libmbedtls.a"    | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
+    cat $ROM_OUT_FILE | grep "libmbedcrypto.a" | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
+    cat $ROM_OUT_FILE | grep "libmbedx509.a"   | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
 }
 
 baremetal_build_armc5()
@@ -122,6 +127,11 @@
     echo "ROM statistics written to:"
     echo "* $ROM_OUT_FILE"
     echo "* $ROM_OUT_SYMS"
+
+    # Print summary
+    cat $ROM_OUT_FILE | grep "libmbedtls.a"    | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
+    cat $ROM_OUT_FILE | grep "libmbedcrypto.a" | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
+    cat $ROM_OUT_FILE | grep "libmbedx509.a"   | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
 }
 
 baremetal_build_armc6()
@@ -150,6 +160,11 @@
     echo "ROM statistics written to:"
     echo "* $ROM_OUT_FILE"
     echo "* $ROM_OUT_SYMS"
+
+    # Print summary
+    cat $ROM_OUT_FILE | grep "libmbedtls.a"    | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
+    cat $ROM_OUT_FILE | grep "libmbedcrypto.a" | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
+    cat $ROM_OUT_FILE | grep "libmbedx509.a"   | awk  '{printf( "%15s: %s Bytes\n", $4, $5)}'
 }
 
 # 32-bit host-build of library, tests and example programs,
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index d023c8d..acf8e9b 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -44,7 +44,9 @@
 
 test-ca.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
 	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=3 request_file=test-ca.req.sha256 selfsign=1 issuer_name="C=NL,O=PolarSSL,CN=PolarSSL Test CA" issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144400 not_after=20210212144400 md=SHA1 version=3 output_file=$@
-all_final += test-ca.crt
+test-ca.der: test-ca.crt
+	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
+all_final += test-ca.crt test-ca.der
 
 test-ca-sha1.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
 	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=3 request_file=test-ca.req.sha256 selfsign=1 issuer_name="C=NL,O=PolarSSL,CN=PolarSSL Test CA" issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144400 not_after=20210212144400 md=SHA1 version=3 output_file=$@
@@ -903,7 +905,9 @@
 
 server2.crt: server2.req.sha256
 	$(MBEDTLS_CERT_WRITE) request_file=server2.req.sha256 serial=2 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144406 not_after=20210212144406 md=SHA1 version=3 output_file=$@
-all_final += server2.crt
+server2.der: server2.crt
+	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
+all_final += server2.crt server2.der
 
 server2-sha256.crt: server2.req.sha256
 	$(MBEDTLS_CERT_WRITE) request_file=server2.req.sha256 serial=2 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144406 not_after=20210212144406 md=SHA256 version=3 output_file=$@
diff --git a/tests/data_files/server1.der b/tests/data_files/server1.der
new file mode 100644
index 0000000..fcf45cd
--- /dev/null
+++ b/tests/data_files/server1.der
Binary files differ
diff --git a/tests/data_files/server2.der b/tests/data_files/server2.der
new file mode 100644
index 0000000..ec03190
--- /dev/null
+++ b/tests/data_files/server2.der
Binary files differ
diff --git a/tests/data_files/test-ca.der b/tests/data_files/test-ca.der
new file mode 100644
index 0000000..039fb9e
--- /dev/null
+++ b/tests/data_files/test-ca.der
Binary files differ
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 6786c36..042d653 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -2,14 +2,26 @@
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/server1.crt":"cert. version     \: 3\nserial number     \: 01\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
 
+X509 Certificate information #1 (DER)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_cert_info:"data_files/server1.der":"cert. version     \: 3\nserial number     \: 01\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
+
 X509 Certificate information #2
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/server2.crt":"cert. version     \: 3\nserial number     \: 02\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=localhost\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
 
+X509 Certificate information #2 (DER)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_cert_info:"data_files/server2.der":"cert. version     \: 3\nserial number     \: 02\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=localhost\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
+
 X509 Certificate information #3
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/test-ca.crt":"cert. version     \: 3\nserial number     \: 03\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2011-02-12 14\:44\:00\nexpires on        \: 2021-02-12 14\:44\:00\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\n"
 
+X509 Certificate information #3 (DER)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_cert_info:"data_files/test-ca.der":"cert. version     \: 3\nserial number     \: 03\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2011-02-12 14\:44\:00\nexpires on        \: 2021-02-12 14\:44\:00\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\n"
+
 X509 Certificate information MD2 Digest
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_MD2_C
 x509_cert_info:"data_files/cert_md2.crt":"cert. version     \: 3\nserial number     \: 09\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Cert MD2\nissued  on        \: 2009-07-12 10\:56\:59\nexpires on        \: 2011-07-12 10\:56\:59\nsigned using      \: RSA with MD2\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 552c494..a921310 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -505,8 +505,22 @@
     mbedtls_x509_crt_init( &crt );
     memset( output, 0, 2000 );
 
+    TEST_ASSERT( mbedtls_x509_crt_parse_der( &crt, buf->x, buf->len ) == ( result ) );
+    if( ( result ) == 0 )
+    {
+        res = mbedtls_x509_crt_info( (char *) output, 2000, "", &crt );
 
-    TEST_ASSERT( mbedtls_x509_crt_parse( &crt, buf->x, buf->len ) == ( result ) );
+        TEST_ASSERT( res != -1 );
+        TEST_ASSERT( res != -2 );
+
+        TEST_ASSERT( strcmp( (char *) output, result_str ) == 0 );
+    }
+
+    mbedtls_x509_crt_free( &crt );
+    mbedtls_x509_crt_init( &crt );
+    memset( output, 0, 2000 );
+
+    TEST_ASSERT( mbedtls_x509_crt_parse_der_nocopy( &crt, buf->x, buf->len ) == ( result ) );
     if( ( result ) == 0 )
     {
         res = mbedtls_x509_crt_info( (char *) output, 2000, "", &crt );