Merge pull request #80 from yanesca/iotcrypt-685-rewrite-dh-example

Remove Diffie-Hellman examples
diff --git a/ChangeLog b/ChangeLog
index 2e75000..9deefa5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,10 +7,22 @@
      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 a new function mbedtls_asn1_write_named_bitstring() to write ASN.1
+     named bitstring in DER as required by RFC 5280 Appendix B.
+   * Add MBEDTLS_REMOVE_3DES_CIPHERSUITES to allow removing 3DES ciphersuites
+     from the default list (enabled by default). See
+     https://sweet32.info/SWEET32_CCS16.pdf.
 
 API Changes
    * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`.
      See the Features section for more information.
+   * Allow to opt in to the removal the API mbedtls_ssl_get_peer_cert()
+     for the benefit of saving RAM, by disabling the new compile-time
+     option MBEDTLS_SSL_KEEP_PEER_CERTIFICATE (enabled by default for
+     API stability). Disabling this option makes mbedtls_ssl_get_peer_cert()
+     always return NULL, and removes the peer_cert field from the
+     mbedtls_ssl_session structure which otherwise stores the peer's
+     certificate.
 
 Bugfix
    * Fix a compilation issue with mbedtls_ecp_restart_ctx not being defined
@@ -31,6 +43,15 @@
      Fixes #2190.
    * Fix false failure in all.sh when backup files exist in include/mbedtls
      (e.g. config.h.bak). Fixed by Peter Kolbus (Garmin) #2407.
+   * Ensure that unused bits are zero when writing ASN.1 bitstrings when using
+     mbedtls_asn1_write_bitstring().
+   * Fix issue when writing the named bitstrings in KeyUsage and NsCertType
+     extensions in CSRs and CRTs that caused these bitstrings to not be encoded
+     correctly as trailing zeroes were not accounted for as unused bits in the
+     leading content octet. Fixes #1610.
+   * Fix private key DER output in the key_app_writer example. File contents
+     were shifted by one byte, creating an invalid ASN.1 tag. Fixed by
+     Christian Walther in #2239.
 
 Changes
    * Reduce RAM consumption during session renegotiation by not storing
@@ -53,16 +74,23 @@
      underlying OS actually guarantees.
    * Fix configuration queries in ssl-opt.h. #2030
    * Ensure that ssl-opt.h can be run in OS X. #2029
-   * Ensure that unused bits are zero when writing ASN.1 bitstrings when using
-     mbedtls_asn1_write_bitstring().
-   * Fix issue when writing the named bitstrings in KeyUsage and NsCertType
-     extensions in CSRs and CRTs that caused these bitstrings to not be encoded
-     correctly as trailing zeroes were not accounted for as unused bits in the
-     leading content octet. Fixes #1610.
-
-Features
-   * Add a new function mbedtls_asn1_write_named_bitstring() to write ASN.1
-     named bitstring in DER as required by RFC 5280 Appendix B.
+   * Re-enable certain interoperability tests in ssl-opt.sh which had previously
+     been disabled for lack of a sufficiently recent version of GnuTLS on the CI.
+   * Ciphersuites based on 3DES now have the lowest priority by default when
+     they are enabled.
+   * Server's RSA certificate in certs.c was SHA-1 signed. In the default
+     mbedTLS configuration only SHA-2 signed certificates are accepted.
+     This certificate is used in the demo server programs, which lead the
+     client programs to fail at the peer's certificate verification
+     due to an unacceptable hash signature. The certificate has been
+     updated to one that is SHA-256 signed. Fix contributed by
+     Illya Gerasymchuk.
+   * Return from various debugging routines immediately if the
+     provided SSL context is unset.
+   * Remove dead code from bignum.c in the default configuration.
+     Found by Coverity, reported and fixed by Peter Kolbus (Garmin). Fixes #2309.
+   * Add test for minimal value of MBEDTLS_MPI_WINDOW_SIZE to all.sh.
+     Contributed by Peter Kolbus (Garmin).
 
 = mbed TLS 2.16.0 branch released 2018-12-21
 
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index ffc3cec..d9177fb 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -24,7 +24,7 @@
  */
 
 /**
- * @mainpage mbed TLS v2.16.0 source code documentation
+ * @mainpage mbed TLS v0.0.0 source code documentation
  *
  * This documentation describes the internal structure of mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index 574db8d..b0190e4 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@
 # identify the project. Note that if you do not use Doxywizard you need
 # to put quotes around the project name if it contains spaces.
 
-PROJECT_NAME           = "mbed TLS v2.16.0"
+PROJECT_NAME           = "mbed TLS v0.0.0"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
 # This could be handy for archiving the generated documentation or
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index ea05938..962d3db 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -280,6 +280,14 @@
 #error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) &&        \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) &&              \
+    ( !defined(MBEDTLS_SHA256_C) &&                             \
+      !defined(MBEDTLS_SHA512_C) &&                             \
+      !defined(MBEDTLS_SHA1_C) )
+#error "!MBEDTLS_SSL_KEEP_PEER_CERTIFICATE requires MBEDTLS_SHA512_C, MBEDTLS_SHA256_C or MBEDTLS_SHA1_C"
+#endif
+
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) &&                          \
     ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
 #error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 097361a..f17381e 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -688,6 +688,26 @@
 #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
 
 /**
+ * \def MBEDTLS_REMOVE_3DES_CIPHERSUITES
+ *
+ * Remove 3DES ciphersuites by default in SSL / TLS.
+ * This flag removes the ciphersuites based on 3DES from the default list as
+ * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible
+ * to enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including
+ * them explicitly.
+ *
+ * A man-in-the-browser attacker can recover authentication tokens sent through
+ * a TLS connection using a 3DES based cipher suite (see "On the Practical
+ * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Gaëtan
+ * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls
+ * in your threat model or you are unsure, then you should keep this option
+ * enabled to remove 3DES based cipher suites.
+ *
+ * Comment this macro to keep 3DES in the default ciphersuite list.
+ */
+#define MBEDTLS_REMOVE_3DES_CIPHERSUITES
+
+/**
  * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED
  *
  * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve
@@ -1380,6 +1400,28 @@
 #define MBEDTLS_SSL_FALLBACK_SCSV
 
 /**
+ * \def MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+ *
+ * This option controls the availability of the API mbedtls_ssl_get_peer_cert()
+ * giving access to the peer's certificate after completion of the handshake.
+ *
+ * Unless you need mbedtls_ssl_peer_cert() in your application, it is
+ * recommended to disable this option for reduced RAM usage.
+ *
+ * \note If this option is disabled, mbedtls_ssl_get_peer_cert() is still
+ *       defined, but always returns \c NULL.
+ *
+ * \note This option has no influence on the protection against the
+ *       triple handshake attack. Even if it is disabled, Mbed TLS will
+ *       still ensure that certificates do not change during renegotiation,
+ *       for exaple by keeping a hash of the peer's certificate.
+ *
+ * Comment this macro to disable storing the peer's certificate
+ * after the handshake.
+ */
+#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+
+/**
  * \def MBEDTLS_SSL_HW_RECORD_ACCEL
  *
  * Enable hooking functions in SSL module for hardware acceleration of
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index 6fbd018..65e626e 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -43,13 +43,31 @@
 #include "md.h"
 #endif
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
-#include "x509.h"
-#endif
-
 #define MBEDTLS_ERR_OID_NOT_FOUND                         -0x002E  /**< OID is not found. */
 #define MBEDTLS_ERR_OID_BUF_TOO_SMALL                     -0x000B  /**< output buffer is too small */
 
+/* This is for the benefit of X.509, but defined here in order to avoid
+ * having a "backwards" include of x.509.h here */
+/*
+ * X.509 extension types (internal, arbitrary values for bitsets)
+ */
+#define MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER    (1 << 0)
+#define MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER      (1 << 1)
+#define MBEDTLS_OID_X509_EXT_KEY_USAGE                   (1 << 2)
+#define MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES        (1 << 3)
+#define MBEDTLS_OID_X509_EXT_POLICY_MAPPINGS             (1 << 4)
+#define MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME            (1 << 5)
+#define MBEDTLS_OID_X509_EXT_ISSUER_ALT_NAME             (1 << 6)
+#define MBEDTLS_OID_X509_EXT_SUBJECT_DIRECTORY_ATTRS     (1 << 7)
+#define MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS           (1 << 8)
+#define MBEDTLS_OID_X509_EXT_NAME_CONSTRAINTS            (1 << 9)
+#define MBEDTLS_OID_X509_EXT_POLICY_CONSTRAINTS          (1 << 10)
+#define MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE          (1 << 11)
+#define MBEDTLS_OID_X509_EXT_CRL_DISTRIBUTION_POINTS     (1 << 12)
+#define MBEDTLS_OID_X509_EXT_INIHIBIT_ANYPOLICY          (1 << 13)
+#define MBEDTLS_OID_X509_EXT_FRESHEST_CRL                (1 << 14)
+#define MBEDTLS_OID_X509_EXT_NS_CERT_TYPE                (1 << 16)
+
 /*
  * Top level OID tuples
  */
@@ -424,7 +442,6 @@
  */
 int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid );
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
 /**
  * \brief          Translate an X.509 extension OID into local values
  *
@@ -434,7 +451,6 @@
  * \return         0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
  */
 int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type );
-#endif
 
 /**
  * \brief          Translate an X.509 attribute type OID into the short name
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 46007a7..b793ac0 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -787,6 +787,25 @@
 typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) &&        \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN  48
+#if defined(MBEDTLS_SHA256_C)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA256
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN  32
+#elif defined(MBEDTLS_SHA512_C)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA384
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN  48
+#elif defined(MBEDTLS_SHA1_C)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA1
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN  20
+#else
+/* This is already checked in check_config.h, but be sure. */
+#error "Bad configuration - need SHA-1, SHA-256 or SHA-512 enabled to compute digest of peer CRT."
+#endif
+#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED &&
+          !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 /*
  * This structure is used for storing current session data.
  */
@@ -802,7 +821,15 @@
     unsigned char master[48];   /*!< the master secret  */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
-    mbedtls_x509_crt *peer_cert;        /*!< peer X.509 cert chain */
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_x509_crt *peer_cert;       /*!< peer X.509 cert chain */
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /*! The digest of the peer's end-CRT. This must be kept to detect CRT
+     *  changes during renegotiation, mitigating the triple handshake attack. */
+    unsigned char *peer_cert_digest;
+    size_t peer_cert_digest_len;
+    mbedtls_md_type_t peer_cert_digest_type;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
     uint32_t verify_result;          /*!<  verification result     */
 
@@ -2972,18 +2999,34 @@
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 /**
- * \brief          Return the peer certificate from the current connection
+ * \brief          Return the peer certificate from the current connection.
  *
- *                 Note: Can be NULL in case no certificate was sent during
- *                 the handshake. Different calls for the same connection can
- *                 return the same or different pointers for the same
- *                 certificate and even a different certificate altogether.
- *                 The peer cert CAN change in a single connection if
- *                 renegotiation is performed.
+ * \param  ssl     The SSL context to use. This must be initialized and setup.
  *
- * \param ssl      SSL context
+ * \return         The current peer certificate, if available.
+ *                 The returned certificate is owned by the SSL context and
+ *                 is valid only until the next call to the SSL API.
+ * \return         \c NULL if no peer certificate is available. This might
+ *                 be because the chosen ciphersuite doesn't use CRTs
+ *                 (PSK-based ciphersuites, for example), or because
+ *                 #MBEDTLS_SSL_KEEP_PEER_CERTIFICATE has been disabled,
+ *                 allowing the stack to free the peer's CRT to save memory.
  *
- * \return         the current peer certificate
+ * \note           For one-time inspection of the peer's certificate during
+ *                 the handshake, consider registering an X.509 CRT verification
+ *                 callback through mbedtls_ssl_conf_verify() instead of calling
+ *                 this function. Using mbedtls_ssl_conf_verify() also comes at
+ *                 the benefit of allowing you to influence the verification
+ *                 process, for example by masking expected and tolerated
+ *                 verification failures.
+ *
+ * \warning        You must not use the pointer returned by this function
+ *                 after any further call to the SSL API, including
+ *                 mbedtls_ssl_read() and mbedtls_ssl_write(); this is
+ *                 because the pointer might change during renegotiation,
+ *                 which happens transparently to the user.
+ *                 If you want to use the certificate across API calls,
+ *                 you must make a copy.
  */
 const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
diff --git a/include/mbedtls/ssl_cache.h b/include/mbedtls/ssl_cache.h
index 52ba094..84254d3 100644
--- a/include/mbedtls/ssl_cache.h
+++ b/include/mbedtls/ssl_cache.h
@@ -70,7 +70,8 @@
     mbedtls_time_t timestamp;           /*!< entry timestamp    */
 #endif
     mbedtls_ssl_session session;        /*!< entry session      */
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     mbedtls_x509_buf peer_cert;         /*!< entry peer_cert    */
 #endif
     mbedtls_ssl_cache_entry *next;      /*!< chain pointer      */
diff --git a/include/mbedtls/ssl_ciphersuites.h b/include/mbedtls/ssl_ciphersuites.h
index 71053e5..7126783 100644
--- a/include/mbedtls/ssl_ciphersuites.h
+++ b/include/mbedtls/ssl_ciphersuites.h
@@ -486,6 +486,24 @@
     }
 }
 
+static inline int mbedtls_ssl_ciphersuite_uses_srv_cert( const mbedtls_ssl_ciphersuite_t *info )
+{
+    switch( info->key_exchange )
+    {
+        case MBEDTLS_KEY_EXCHANGE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
+        case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
+            return( 1 );
+
+        default:
+            return( 0 );
+    }
+}
+
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED)
 static inline int mbedtls_ssl_ciphersuite_uses_dhe( const mbedtls_ssl_ciphersuite_t *info )
 {
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index be7f41b..5dde239 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -331,8 +331,13 @@
         ssl_ecrs_cke_ecdh_calc_secret,  /*!< ClientKeyExchange: ECDH step 2 */
         ssl_ecrs_crt_vrfy_sign,         /*!< CertificateVerify: pk_sign()   */
     } ecrs_state;                       /*!< current (or last) operation    */
+    mbedtls_x509_crt *ecrs_peer_cert;   /*!< The peer's CRT chain.          */
     size_t ecrs_n;                      /*!< place for saving a length      */
 #endif
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_pk_context peer_pubkey;     /*!< The public key from the peer.  */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     unsigned int out_msg_seq;           /*!<  Outgoing handshake sequence number */
     unsigned int in_msg_seq;            /*!<  Incoming handshake sequence number */
@@ -766,6 +771,9 @@
 void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl );
 #endif
 
+int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
+                              const mbedtls_ssl_session *src );
+
 /* constant-time buffer comparison */
 static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
 {
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index 56e7398..3f2e12c 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -38,8 +38,8 @@
  * The version number x.y.z is split into three parts.
  * Major, Minor, Patchlevel
  */
-#define MBEDTLS_VERSION_MAJOR  2
-#define MBEDTLS_VERSION_MINOR  16
+#define MBEDTLS_VERSION_MAJOR  0
+#define MBEDTLS_VERSION_MINOR  0
 #define MBEDTLS_VERSION_PATCH  0
 
 /**
@@ -47,9 +47,9 @@
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x02100000
-#define MBEDTLS_VERSION_STRING         "2.16.0"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.16.0"
+#define MBEDTLS_VERSION_NUMBER         0x00000000
+#define MBEDTLS_VERSION_STRING         "0.0.0"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 0.0.0"
 
 #if defined(MBEDTLS_VERSION_C)
 
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index 63aae32..b63e864 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -142,24 +142,26 @@
  *
  * Comments refer to the status for using certificates. Status can be
  * different for writing certificates or reading CRLs or CSRs.
+ *
+ * Those are defined in oid.h as oid.c needs them in a data structure. Since
+ * these were previously defined here, let's have aliases for compatibility.
  */
-#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER    (1 << 0)
-#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER      (1 << 1)
-#define MBEDTLS_X509_EXT_KEY_USAGE                   (1 << 2)
-#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES        (1 << 3)
-#define MBEDTLS_X509_EXT_POLICY_MAPPINGS             (1 << 4)
-#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME            (1 << 5)    /* Supported (DNS) */
-#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME             (1 << 6)
-#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS     (1 << 7)
-#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS           (1 << 8)    /* Supported */
-#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS            (1 << 9)
-#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS          (1 << 10)
-#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE          (1 << 11)
-#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS     (1 << 12)
-#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY          (1 << 13)
-#define MBEDTLS_X509_EXT_FRESHEST_CRL                (1 << 14)
-
-#define MBEDTLS_X509_EXT_NS_CERT_TYPE                (1 << 16)
+#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER
+#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER   MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER
+#define MBEDTLS_X509_EXT_KEY_USAGE                MBEDTLS_OID_X509_EXT_KEY_USAGE
+#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES     MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES
+#define MBEDTLS_X509_EXT_POLICY_MAPPINGS          MBEDTLS_OID_X509_EXT_POLICY_MAPPINGS
+#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME         MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME         /* Supported (DNS) */
+#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME          MBEDTLS_OID_X509_EXT_ISSUER_ALT_NAME
+#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS  MBEDTLS_OID_X509_EXT_SUBJECT_DIRECTORY_ATTRS
+#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS        MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS        /* Supported */
+#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS         MBEDTLS_OID_X509_EXT_NAME_CONSTRAINTS
+#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS       MBEDTLS_OID_X509_EXT_POLICY_CONSTRAINTS
+#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE       MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE
+#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS  MBEDTLS_OID_X509_EXT_CRL_DISTRIBUTION_POINTS
+#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY       MBEDTLS_OID_X509_EXT_INIHIBIT_ANYPOLICY
+#define MBEDTLS_X509_EXT_FRESHEST_CRL             MBEDTLS_OID_X509_EXT_FRESHEST_CRL
+#define MBEDTLS_X509_EXT_NS_CERT_TYPE             MBEDTLS_OID_X509_EXT_NS_CERT_TYPE
 
 /*
  * Storage format identifiers
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 72c3901..b3f27be 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -70,6 +70,7 @@
     mbedtls_x509_time valid_from;       /**< Start time of certificate validity. */
     mbedtls_x509_time valid_to;         /**< End time of certificate validity. */
 
+    mbedtls_x509_buf pk_raw;
     mbedtls_pk_context pk;              /**< Container for the public key context. */
 
     mbedtls_x509_buf issuer_id;         /**< Optional X.509 v2/v3 issuer unique identifier. */
diff --git a/include/psa/crypto_accel_driver.h b/include/psa/crypto_accel_driver.h
index b752fed..4a540f0 100644
--- a/include/psa/crypto_accel_driver.h
+++ b/include/psa/crypto_accel_driver.h
@@ -38,12 +38,13 @@
 extern "C" {
 #endif
 
-/** \defgroup driver_digest Message Digests
+/** \defgroup driver_digest Hardware-Accelerated Message Digests
  *
  * Generation and authentication of Message Digests (aka hashes) must be done
  * in parts using the following sequence:
  * - `psa_drv_hash_setup_t`
  * - `psa_drv_hash_update_t`
+ * - `psa_drv_hash_update_t`
  * - ...
  * - `psa_drv_hash_finish_t`
  *
@@ -64,7 +65,7 @@
 /** \brief The function prototype for the start operation of a hash (message
  * digest) operation
  *
- *  Functions that implement the prototype should be named in the following
+ *  Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
  * psa_drv_hash_<ALGO>_setup
@@ -81,7 +82,7 @@
 /** \brief The function prototype for the update operation of a hash (message
  * digest) operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
  * psa_drv_hash_<ALGO>_update
@@ -99,10 +100,10 @@
                                               const uint8_t *p_input,
                                               size_t input_length);
 
-/** \brief  The prototype for the finish operation of a hash (message digest)
- * operation
+/** \brief  The function prototype for the finish operation of a hash (message
+ * digest) operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
  * psa_drv_hash_<ALGO>_finish
@@ -130,7 +131,7 @@
 /** \brief The function prototype for the abort operation of a hash (message
  * digest) operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
  * psa_drv_hash_<ALGO>_abort
@@ -144,39 +145,39 @@
 
 /**@}*/
 
-/** \defgroup transparent_mac Transparent Message Authentication Code
+/** \defgroup accel_mac Hardware-Accelerated Message Authentication Code
  * Generation and authentication of Message Authentication Codes (MACs) using
- * transparent keys can be done either as a single function call (via the
- * `psa_drv_mac_transparent_generate_t` or `psa_drv_mac_transparent_verify_t`
+ * cryptographic accelerators can be done either as a single function call (via the
+ * `psa_drv_accel_mac_generate_t` or `psa_drv_accel_mac_verify_t`
  * functions), or in parts using the following sequence:
- * - `psa_drv_mac_transparent_setup_t`
- * - `psa_drv_mac_transparent_update_t`
- * - `psa_drv_mac_transparent_update_t`
+ * - `psa_drv_accel_mac_setup_t`
+ * - `psa_drv_accel_mac_update_t`
+ * - `psa_drv_accel_mac_update_t`
  * - ...
- * - `psa_drv_mac_transparent_finish_t` or `psa_drv_mac_transparent_finish_verify_t`
+ * - `psa_drv_accel_mac_finish_t` or `psa_drv_accel_mac_finish_verify_t`
  *
- * If a previously started Transparent MAC operation needs to be terminated, it
- * should be done so by the `psa_drv_mac_transparent_abort_t`. Failure to do so may
+ * If a previously started MAC operation needs to be terminated, it
+ * should be done so by the `psa_drv_accel_mac_abort_t`. Failure to do so may
  * result in allocated resources not being freed or in other undefined
  * behavior.
  *
  */
 /**@{*/
 
-/** \brief The hardware-specific transparent-key MAC context structure
+/** \brief The hardware-accelerator-specific MAC context structure
  *
  * The contents of this structure are implementation dependent and are
  * therefore not described here.
  */
-typedef struct psa_drv_mac_transparent_context_s psa_drv_mac_transparent_context_t;
+typedef struct psa_drv_accel_mac_context_s psa_drv_accel_mac_context_t;
 
 /** \brief The function prototype for the setup operation of a
- * transparent-key MAC operation
+ * hardware-accelerated MAC operation
  *
- *  Functions that implement the prototype should be named in the following
+ *  Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>_setup
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>_setup
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying primitive, and `MAC_VARIANT`
  * is the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -190,17 +191,17 @@
  * \retval  PSA_SUCCESS
  *          Success.
  */
-typedef psa_status_t (*psa_drv_mac_transparent_setup_t)(psa_drv_mac_transparent_context_t *p_context,
-                                                        const uint8_t *p_key,
-                                                        size_t key_length);
+typedef psa_status_t (*psa_drv_accel_mac_setup_t)(psa_drv_accel_mac_context_t *p_context,
+                                                  const uint8_t *p_key,
+                                                  size_t key_length);
 
 /** \brief The function prototype for the update operation of a
- * transparent-key MAC operation
+ * hardware-accelerated MAC operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>_update
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>_update
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying algorithm, and `MAC_VARIANT`
  * is the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -212,17 +213,17 @@
  *                              to the MAC operation
  * \param[in] input_length      The size in bytes of the input message buffer
  */
-typedef psa_status_t (*psa_drv_mac_transparent_update_t)(psa_drv_mac_transparent_context_t *p_context,
-                                                         const uint8_t *p_input,
-                                                         size_t input_length);
+typedef psa_status_t (*psa_drv_accel_mac_update_t)(psa_drv_accel_mac_context_t *p_context,
+                                                   const uint8_t *p_input,
+                                                   size_t input_length);
 
 /** \brief  The function prototype for the finish operation of a
- * transparent-key MAC operation
+ * hardware-accelerated MAC operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  *  convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>_finish
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>_finish
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying algorithm, and `MAC_VARIANT` is
  * the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -237,17 +238,17 @@
  * \retval PSA_SUCCESS
  *          Success.
  */
-typedef psa_status_t (*psa_drv_mac_transparent_finish_t)(psa_drv_mac_transparent_context_t *p_context,
-                                                         uint8_t *p_mac,
-                                                         size_t mac_length);
+typedef psa_status_t (*psa_drv_accel_mac_finish_t)(psa_drv_accel_mac_context_t *p_context,
+                                                   uint8_t *p_mac,
+                                                   size_t mac_length);
 
 /** \brief The function prototype for the finish and verify operation of a
- * transparent-key MAC operation
+ * hardware-accelerated MAC operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>_finish_verify
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>_finish_verify
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying algorithm, and `MAC_VARIANT` is
  * the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -263,17 +264,17 @@
  * \retval PSA_SUCCESS
  *          The operation completed successfully and the comparison matched
  */
-typedef psa_status_t (*psa_drv_mac_transparent_finish_verify_t)(psa_drv_mac_transparent_context_t *p_context,
-                                                                const uint8_t *p_mac,
-                                                                size_t mac_length);
+typedef psa_status_t (*psa_drv_accel_mac_finish_verify_t)(psa_drv_accel_mac_context_t *p_context,
+                                                          const uint8_t *p_mac,
+                                                          size_t mac_length);
 
 /** \brief The function prototype for the abort operation for a previously
- * started transparent-key MAC operation
+ * started hardware-accelerated MAC operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>_abort
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>_abort
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying algorithm, and `MAC_VARIANT` is
  * the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -283,15 +284,15 @@
  *                              aborted
  *
  */
-typedef psa_status_t (*psa_drv_mac_transparent_abort_t)(psa_drv_mac_transparent_context_t *p_context);
+typedef psa_status_t (*psa_drv_accel_mac_abort_t)(psa_drv_accel_mac_context_t *p_context);
 
-/** \brief The function prototype for a one-shot operation of a transparent-key
- * MAC operation
+/** \brief The function prototype for the one-shot operation of a
+ * hardware-accelerated MAC operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying algorithm, and `MAC_VARIANT` is
  * the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -306,21 +307,21 @@
  *                           upon success
  * \param[in] mac_length     The length in bytes of the `p_mac` buffer
  */
-typedef psa_status_t (*psa_drv_mac_transparent_t)(const uint8_t *p_input,
-                                                  size_t input_length,
-                                                  const uint8_t *p_key,
-                                                  size_t key_length,
-                                                  psa_algorithm_t alg,
-                                                  uint8_t *p_mac,
-                                                  size_t mac_length);
+typedef psa_status_t (*psa_drv_accel_mac_t)(const uint8_t *p_input,
+                                            size_t input_length,
+                                            const uint8_t *p_key,
+                                            size_t key_length,
+                                            psa_algorithm_t alg,
+                                            uint8_t *p_mac,
+                                            size_t mac_length);
 
-/** \brief The function prototype for a one-shot operation of a transparent-key
- * MAC Verify operation
+/** \brief The function prototype for the one-shot hardware-accelerated MAC
+ * Verify operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_mac_transparent_<ALGO>_<MAC_VARIANT>_verify
+ * psa_drv_accel_mac_<ALGO>_<MAC_VARIANT>_verify
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the underlying algorithm, and `MAC_VARIANT` is
  * the specific variant of a MAC operation (such as HMAC or CMAC)
@@ -337,51 +338,53 @@
  * \retval PSA_SUCCESS
  *  The operation completed successfully and the comparison matched
  */
-typedef psa_status_t (*psa_drv_mac_transparent_verify_t)(const uint8_t *p_input,
-                                                         size_t input_length,
-                                                         const uint8_t *p_key,
-                                                         size_t key_length,
-                                                         psa_algorithm_t alg,
-                                                         const uint8_t *p_mac,
-                                                         size_t mac_length);
+typedef psa_status_t (*psa_drv_accel_mac_verify_t)(const uint8_t *p_input,
+                                                   size_t input_length,
+                                                   const uint8_t *p_key,
+                                                   size_t key_length,
+                                                   psa_algorithm_t alg,
+                                                   const uint8_t *p_mac,
+                                                   size_t mac_length);
 /**@}*/
 
-/** \defgroup transparent_cipher Transparent Block Cipher
- * Encryption and Decryption using transparent keys in block modes other than
- * ECB must be done in multiple parts, using the following flow:
- * - `psa_drv_cipher_transparent_setup_t`
- * - `psa_drv_cipher_transparent_set_iv_t` (optional depending upon block mode)
- * - `psa_drv_cipher_transparent_update_t`
+/** \defgroup accel_cipher Hardware-Accelerated Block Ciphers
+ * Encryption and Decryption using hardware-acceleration in block modes other
+ * than ECB must be done in multiple parts, using the following flow:
+ * - `psa_drv_accel_ciphersetup_t`
+ * - `psa_drv_accel_cipher_set_iv_t` (optional depending upon block mode)
+ * - `psa_drv_accel_cipher_update_t`
+ * - `psa_drv_accel_cipher_update_t`
  * - ...
- * - `psa_drv_cipher_transparent_finish_t`
-
- * If a previously started Transparent Cipher operation needs to be terminated,
- * it should be done so by the `psa_drv_cipher_transparent_abort_t`. Failure to do
- * so may result in allocated resources not being freed or in other undefined
- * behavior.
+ * - `psa_drv_accel_cipher_finish_t`
+ *
+ * If a previously started hardware-accelerated Cipher operation needs to be
+ * terminated, it should be done so by the `psa_drv_accel_cipher_abort_t`.
+ * Failure to do so may result in allocated resources not being freed or in
+ * other undefined behavior.
  */
 /**@{*/
 
-/** \brief The hardware-specific transparent-key Cipher context structure
+/** \brief The hardware-accelerator-specific cipher context structure
  *
  * The contents of this structure are implementation dependent and are
  * therefore not described here.
  */
-typedef struct psa_drv_cipher_transparent_context_s psa_drv_cipher_transparent_context_t;
+typedef struct psa_drv_accel_cipher_context_s psa_drv_accel_cipher_context_t;
 
-/** \brief The function prototype for the setup operation of transparent-key
- * block cipher operations.
- *  Functions that implement the prototype should be named in the following
+/** \brief The function prototype for the setup operation of
+ * hardware-accelerated block cipher operations.
+ *  Functions that implement this prototype should be named in the following
  * conventions:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_cipher_transparent_setup_<CIPHER_NAME>_<MODE>
+ * psa_drv_accel_cipher_setup_<CIPHER_NAME>_<MODE>
  * ~~~~~~~~~~~~~
  * Where
  * - `CIPHER_NAME` is the name of the underlying block cipher (i.e. AES or DES)
  * - `MODE` is the block mode of the cipher operation (i.e. CBC or CTR)
- * or for stream ciphers:
+ *
+ * For stream ciphers:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_cipher_transparent_setup_<CIPHER_NAME>
+ * psa_drv_accel_cipher_setup_<CIPHER_NAME>
  * ~~~~~~~~~~~~~
  * Where `CIPHER_NAME` is the name of a stream cipher (i.e. RC4)
  *
@@ -395,17 +398,17 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_transparent_setup_t)(psa_drv_cipher_transparent_context_t *p_context,
-                                                           psa_encrypt_or_decrypt_t direction,
-                                                           const uint8_t *p_key_data,
-                                                           size_t key_data_size);
+typedef psa_status_t (*psa_drv_accel_cipher_setup_t)(psa_drv_accel_cipher_context_t *p_context,
+                                                     psa_encrypt_or_decrypt_t direction,
+                                                     const uint8_t *p_key_data,
+                                                     size_t key_data_size);
 
 /** \brief The function prototype for the set initialization vector operation
- * of transparent-key block cipher operations
- * Functions that implement the prototype should be named in the following
+ * of hardware-accelerated block cipher operations
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_cipher_transparent_set_iv_<CIPHER_NAME>_<MODE>
+ * psa_drv_accel_cipher_set_iv_<CIPHER_NAME>_<MODE>
  * ~~~~~~~~~~~~~
  * Where
  * - `CIPHER_NAME` is the name of the underlying block cipher (i.e. AES or DES)
@@ -418,17 +421,17 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_transparent_set_iv_t)(psa_drv_cipher_transparent_context_t *p_context,
-                                                            const uint8_t *p_iv,
-                                                            size_t iv_length);
+typedef psa_status_t (*psa_drv_accel_cipher_set_iv_t)(psa_drv_accel_cipher_context_t *p_context,
+                                                      const uint8_t *p_iv,
+                                                      size_t iv_length);
 
-/** \brief The function prototype for the update operation of transparent-key
- * block cipher operations.
+/** \brief The function prototype for the update operation of
+ * hardware-accelerated block cipher operations.
  *
- *  Functions that implement the prototype should be named in the following
+ *  Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_cipher_transparent_update_<CIPHER_NAME>_<MODE>
+ * psa_drv_accel_cipher_update_<CIPHER_NAME>_<MODE>
  * ~~~~~~~~~~~~~
  * Where
  * - `CIPHER_NAME` is the name of the underlying block cipher (i.e. AES or DES)
@@ -447,20 +450,20 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_transparent_update_t)(psa_drv_cipher_transparent_context_t *p_context,
-                                                            const uint8_t *p_input,
-                                                            size_t input_size,
-                                                            uint8_t *p_output,
-                                                            size_t output_size,
-                                                            size_t *p_output_length);
+typedef psa_status_t (*psa_drv_accel_cipher_update_t)(psa_drv_accel_cipher_context_t *p_context,
+                                                      const uint8_t *p_input,
+                                                      size_t input_size,
+                                                      uint8_t *p_output,
+                                                      size_t output_size,
+                                                      size_t *p_output_length);
 
-/** \brief The function prototype for the finish operation of transparent-key
- * block cipher operations.
+/** \brief The function prototype for the finish operation of
+ * hardware-accelerated block cipher operations.
  *
- *  Functions that implement the prototype should be named in the following
+ *  Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_cipher_transparent_finish_<CIPHER_NAME>_<MODE>
+ * psa_drv_accel_cipher_finish_<CIPHER_NAME>_<MODE>
  * ~~~~~~~~~~~~~
  * Where
  * - `CIPHER_NAME` is the name of the underlying block cipher (i.e. AES or DES)
@@ -476,18 +479,18 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_transparent_finish_t)(psa_drv_cipher_transparent_context_t *p_context,
-                                                            uint8_t *p_output,
-                                                            size_t output_size,
-                                                            size_t *p_output_length);
+typedef psa_status_t (*psa_drv_accel_cipher_finish_t)(psa_drv_accel_cipher_context_t *p_context,
+                                                      uint8_t *p_output,
+                                                      size_t output_size,
+                                                      size_t *p_output_length);
 
-/** \brief The function prototype for the abort operation of transparent-key
- * block cipher operations.
+/** \brief The function prototype for the abort operation of
+ * hardware-accelerated block cipher operations.
  *
  *  Functions that implement the following prototype should be named in the
  * following convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_cipher_transparent_abort_<CIPHER_NAME>_<MODE>
+ * psa_drv_accel_cipher_abort_<CIPHER_NAME>_<MODE>
  * ~~~~~~~~~~~~~
  * Where
  * - `CIPHER_NAME` is the name of the underlying block cipher (i.e. AES or DES)
@@ -498,27 +501,27 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_transparent_abort_t)(psa_drv_cipher_transparent_context_t *p_context);
+typedef psa_status_t (*psa_drv_accel_cipher_abort_t)(psa_drv_accel_cipher_context_t *p_context);
 
 /**@}*/
 
-/** \defgroup aead_transparent AEAD Transparent
+/** \defgroup accel_aead Hardware-Accelerated Authenticated Encryption with Additional Data
  *
- * Authenticated Encryption with Additional Data (AEAD) operations with
- * transparent keys must be done in one function call. While this creates a
- * burden for implementers as there must be sufficient space in memory for the
- * entire message, it prevents decrypted data from being made available before
- * the authentication operation is complete and the data is known to be
- * authentic.
+ * Hardware-accelerated Authenticated Encryption with Additional Data (AEAD)
+ * operations must be done in one function call. While this creates a burden
+ * for implementers as there must be sufficient space in memory for the entire
+ * message, it prevents decrypted data from being made available before the
+ * authentication operation is complete and the data is known to be authentic.
  */
 /**@{*/
 
-/** Process an authenticated encryption operation using an opaque key.
+/** \brief The function prototype for the hardware-accelerated authenticated
+ * encryption operation.
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_aead_<ALGO>_encrypt
+ * psa_drv_accel_aead_<ALGO>_encrypt
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the AEAD algorithm
  *
@@ -551,27 +554,28 @@
  *                                      the `ciphertext` buffer
  *
  * \retval #PSA_SUCCESS
-
- */
-typedef psa_status_t (*psa_drv_aead_transparent_encrypt_t)(const uint8_t *p_key,
-                                                           size_t key_length,
-                                                           psa_algorithm_t alg,
-                                                           const uint8_t *nonce,
-                                                           size_t nonce_length,
-                                                           const uint8_t *additional_data,
-                                                           size_t additional_data_length,
-                                                           const uint8_t *plaintext,
-                                                           size_t plaintext_length,
-                                                           uint8_t *ciphertext,
-                                                           size_t ciphertext_size,
-                                                           size_t *ciphertext_length);
-
-/** Process an authenticated decryption operation using an opaque key.
  *
- * Functions that implement the prototype should be named in the following
+ */
+typedef psa_status_t (*psa_drv_accel_aead_encrypt_t)(const uint8_t *p_key,
+                                                     size_t key_length,
+                                                     psa_algorithm_t alg,
+                                                     const uint8_t *nonce,
+                                                     size_t nonce_length,
+                                                     const uint8_t *additional_data,
+                                                     size_t additional_data_length,
+                                                     const uint8_t *plaintext,
+                                                     size_t plaintext_length,
+                                                     uint8_t *ciphertext,
+                                                     size_t ciphertext_size,
+                                                     size_t *ciphertext_length);
+
+/** \brief The function prototype for the hardware-accelerated authenticated
+ * decryption operation.
+ *
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_aead_<ALGO>_decrypt
+ * psa_drv_accel_aead_<ALGO>_decrypt
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the AEAD algorithm
  * \param[in] p_key                     A pointer to the key material
@@ -604,41 +608,45 @@
  * \retval #PSA_SUCCESS
  *         Success.
  */
-typedef psa_status_t (*psa_drv_aead_transparent_decrypt_t)(const uint8_t *p_key,
-                                                           size_t key_length,
-                                                           psa_algorithm_t alg,
-                                                           const uint8_t *nonce,
-                                                           size_t nonce_length,
-                                                           const uint8_t *additional_data,
-                                                           size_t additional_data_length,
-                                                           const uint8_t *ciphertext,
-                                                           size_t ciphertext_length,
-                                                           uint8_t *plaintext,
-                                                           size_t plaintext_size,
-                                                           size_t *plaintext_length);
+typedef psa_status_t (*psa_drv_accel_aead_decrypt_t)(const uint8_t *p_key,
+                                                     size_t key_length,
+                                                     psa_algorithm_t alg,
+                                                     const uint8_t *nonce,
+                                                     size_t nonce_length,
+                                                     const uint8_t *additional_data,
+                                                     size_t additional_data_length,
+                                                     const uint8_t *ciphertext,
+                                                     size_t ciphertext_length,
+                                                     uint8_t *plaintext,
+                                                     size_t plaintext_size,
+                                                     size_t *plaintext_length);
 
 /**@}*/
 
-/** \defgroup transparent_asymmetric Transparent Asymmetric Cryptography
+/** \defgroup accel_asymmetric Hardware-Accelerated Asymmetric Cryptography
  *
  * Since the amount of data that can (or should) be encrypted or signed using
- * asymmetric keys is limited by the key size, asymmetric key operations using
- * transparent keys must be done in single function calls.
+ * asymmetric keys is limited by the key size, hardware-accelerated asymmetric
+ * key operations must be done in single function calls.
  */
 /**@{*/
 
 
 /**
- * \brief A function that signs a hash or short message with a transparent
- * asymmetric private key
+ * \brief The function prototype for the hardware-accelerated asymmetric sign
+ * operation.
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_asymmetric_<ALGO>_sign
+ * psa_drv_accel_asymmetric_<ALGO>_sign
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the signing algorithm
  *
+ * This function supports any asymmetric-key output from psa_export_key() as
+ * the buffer in \p p_key. Refer to the documentation of \ref
+ * psa_export_key() for the formats.
+ *
  * \param[in] p_key                 A buffer containing the private key
  *                                  material
  * \param[in] key_size              The size in bytes of the `p_key` data
@@ -653,26 +661,32 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_asymmetric_transparent_sign_t)(const uint8_t *p_key,
-                                                              size_t key_size,
-                                                              psa_algorithm_t alg,
-                                                              const uint8_t *p_hash,
-                                                              size_t hash_length,
-                                                              uint8_t *p_signature,
-                                                              size_t signature_size,
-                                                              size_t *p_signature_length);
+typedef psa_status_t (*psa_drv_accel_asymmetric_sign_t)(const uint8_t *p_key,
+                                                        size_t key_size,
+                                                        psa_algorithm_t alg,
+                                                        psa_key_type_t key_type,
+                                                        const uint8_t *p_hash,
+                                                        size_t hash_length,
+                                                        uint8_t *p_signature,
+                                                        size_t signature_size,
+                                                        size_t *p_signature_length);
 
 /**
- * \brief A function that verifies the signature a hash or short message using
- * a transparent asymmetric public key
+ * \brief The function prototype for the hardware-accelerated signature verify
+ * operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_asymmetric_<ALGO>_verify
+ * psa_drv_accel_asymmetric_<ALGO>_verify
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the signing algorithm
  *
+ * This function supports any output from \ref psa_export_public_key() as the
+ * buffer in \p p_key. Refer to the documentation of \ref
+ * psa_export_public_key() for the format of public keys and to the
+ * documentation of \ref psa_export_key() for the format for other key types.
+ *
  * \param[in] p_key             A buffer containing the public key material
  * \param[in] key_size          The size in bytes of the `p_key` data
  * \param[in] alg               A signature algorithm that is compatible with
@@ -686,25 +700,31 @@
  * \retval PSA_SUCCESS
  *         The signature is valid.
  */
-typedef psa_status_t (*psa_drv_asymmetric_transparent_verify_t)(const uint8_t *p_key,
-                                                                size_t key_size,
-                                                                psa_algorithm_t alg,
-                                                                const uint8_t *p_hash,
-                                                                size_t hash_length,
-                                                                const uint8_t *p_signature,
-                                                                size_t signature_length);
+typedef psa_status_t (*psa_drv_accel_asymmetric_verify_t)(const uint8_t *p_key,
+                                                          size_t key_size,
+                                                          psa_algorithm_t alg,
+                                                          psa_key_type_t key_type,
+                                                          const uint8_t *p_hash,
+                                                          size_t hash_length,
+                                                          const uint8_t *p_signature,
+                                                          size_t signature_length);
 
 /**
- * \brief A function that encrypts a short message with a transparent
- * asymmetric public key
+ * \brief The function prototype for the hardware-accelerated asymmetric
+ * encrypt operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_asymmetric_<ALGO>_encrypt
+ * psa_drv_accel_asymmetric_<ALGO>_encrypt
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the encryption algorithm
  *
+ * This function supports any output from \ref psa_export_public_key() as the
+ * buffer in \p p_key. Refer to the documentation of \ref
+ * psa_export_public_key() for the format of public keys and to the
+ * documentation of \ref psa_export_key() for the format for other key types.
+ *
  * \param[in] p_key             A buffer containing the public key material
  * \param[in] key_size          The size in bytes of the `p_key` data
  * \param[in] alg               An asymmetric encryption algorithm that is
@@ -730,27 +750,33 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_asymmetric_transparent_encrypt_t)(const uint8_t *p_key,
-                                                                 size_t key_size,
-                                                                 psa_algorithm_t alg,
-                                                                 const uint8_t *p_input,
-                                                                 size_t input_length,
-                                                                 const uint8_t *p_salt,
-                                                                 size_t salt_length,
-                                                                 uint8_t *p_output,
-                                                                 size_t output_size,
-                                                                 size_t *p_output_length);
+typedef psa_status_t (*psa_drv_accel_asymmetric_encrypt_t)(const uint8_t *p_key,
+                                                           size_t key_size,
+                                                           psa_algorithm_t alg,
+                                                           psa_key_type_t key_type,
+                                                           const uint8_t *p_input,
+                                                           size_t input_length,
+                                                           const uint8_t *p_salt,
+                                                           size_t salt_length,
+                                                           uint8_t *p_output,
+                                                           size_t output_size,
+                                                           size_t *p_output_length);
 
 /**
- * \brief Decrypt a short message with a transparent asymmetric private key
+ * \brief The function prototype for the hardware=acce;erated asymmetric
+ * decrypt operation
  *
- * Functions that implement the prototype should be named in the following
+ * Functions that implement this prototype should be named in the following
  * convention:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_asymmetric_<ALGO>_decrypt
+ * psa_drv_accel_asymmetric_<ALGO>_decrypt
  * ~~~~~~~~~~~~~
  * Where `ALGO` is the name of the encryption algorithm
  *
+ * This function supports any asymmetric-key output from psa_export_key() as
+ * the buffer in \p p_key. Refer to the documentation of \ref
+ * psa_export_key() for the formats.
+ *
  * \param[in] p_key             A buffer containing the private key material
  * \param[in] key_size          The size in bytes of the `p_key` data
  * \param[in] alg               An asymmetric encryption algorithm that is
@@ -776,16 +802,17 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_asymmetric_transparent_decrypt_t)(const uint8_t *p_key,
-                                                                 size_t key_size,
-                                                                 psa_algorithm_t alg,
-                                                                 const uint8_t *p_input,
-                                                                 size_t input_length,
-                                                                 const uint8_t *p_salt,
-                                                                 size_t salt_length,
-                                                                 uint8_t *p_output,
-                                                                 size_t output_size,
-                                                                 size_t *p_output_length);
+typedef psa_status_t (*psa_drv_accel_asymmetric_decrypt_t)(const uint8_t *p_key,
+                                                           size_t key_size,
+                                                           psa_algorithm_t alg,
+                                                           psa_key_type_t key_type,
+                                                           const uint8_t *p_input,
+                                                           size_t input_length,
+                                                           const uint8_t *p_salt,
+                                                           size_t salt_length,
+                                                           uint8_t *p_output,
+                                                           size_t output_size,
+                                                           size_t *p_output_length);
 
 /**@}*/
 
diff --git a/include/psa/crypto_entropy_driver.h b/include/psa/crypto_entropy_driver.h
index f5e383e..f596b6b 100644
--- a/include/psa/crypto_entropy_driver.h
+++ b/include/psa/crypto_entropy_driver.h
@@ -40,10 +40,6 @@
  */
 /**@{*/
 
-/** \brief A hardware-specific structure for a entropy providing hardware
- */
-typedef struct psa_drv_entropy_context_s psa_drv_entropy_context_t;
-
 /** \brief Initialize an entropy driver
  *
  *
@@ -53,7 +49,7 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_entropy_init_t)(psa_drv_entropy_context_t *p_context);
+typedef psa_status_t (*psa_drv_entropy_init_t)(void *p_context);
 
 /** \brief Get a specified number of bits from the entropy source
  *
@@ -81,7 +77,7 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_entropy_get_bits_t)(psa_drv_entropy_context_t *p_context,
+typedef psa_status_t (*psa_drv_entropy_get_bits_t)(void *p_context,
                                                    uint8_t *p_buffer,
                                                    uint32_t buffer_size,
                                                    uint32_t *p_received_entropy_bits);
@@ -96,11 +92,12 @@
  * If one of the functions is not implemented, it should be set to NULL.
  */
 typedef struct {
+    /** The driver-specific size of the entropy context */
+    const size_t                context_size;
     /** Function that performs initialization for the entropy source */
-    psa_drv_entropy_init_t *p_init;
-    /** Function that performs the get_bits operation for the entropy source
-    */
-    psa_drv_entropy_get_bits_t *p_get_bits;
+    psa_drv_entropy_init_t      p_init;
+    /** Function that performs the get_bits operation for the entropy source */
+    psa_drv_entropy_get_bits_t  p_get_bits;
 } psa_drv_entropy_t;
 /**@}*/
 
diff --git a/include/psa/crypto_se_driver.h b/include/psa/crypto_se_driver.h
index 20cd4b4..5fb7bc3 100644
--- a/include/psa/crypto_se_driver.h
+++ b/include/psa/crypto_se_driver.h
@@ -3,10 +3,10 @@
  * \brief PSA external cryptoprocessor driver module
  *
  * This header declares types and function signatures for cryptography
- * drivers that access key material via opaque references. This is
- * meant for cryptoprocessors that have a separate key storage from the
+ * drivers that access key material via opaque references.
+ * This is meant for cryptoprocessors that have a separate key storage from the
  * space in which the PSA Crypto implementation runs, typically secure
- * elements.
+ * elements (SEs).
  *
  * This file is part of the PSA Crypto Driver Model, containing functions for
  * driver developers to implement to enable hardware to be called in a
@@ -43,27 +43,27 @@
 /** An internal designation of a key slot between the core part of the
  * PSA Crypto implementation and the driver. The meaning of this value
  * is driver-dependent. */
-typedef uint32_t psa_key_slot_t;
+typedef uint32_t psa_key_slot_number_t; // Change this to psa_key_slot_t after psa_key_slot_t is removed from Mbed crypto
 
-/** \defgroup opaque_mac Opaque Message Authentication Code
+/** \defgroup se_mac Secure Element Message Authentication Codes
  * Generation and authentication of Message Authentication Codes (MACs) using
- * opaque keys can be done either as a single function call (via the
- * `psa_drv_mac_opaque_generate_t` or `psa_drv_mac_opaque_verify_t` functions), or in
+ * a secure element can be done either as a single function call (via the
+ * `psa_drv_se_mac_generate_t` or `psa_drv_se_mac_verify_t` functions), or in
  * parts using the following sequence:
- * - `psa_drv_mac_opaque_setup_t`
- * - `psa_drv_mac_opaque_update_t`
- * - `psa_drv_mac_opaque_update_t`
+ * - `psa_drv_se_mac_setup_t`
+ * - `psa_drv_se_mac_update_t`
+ * - `psa_drv_se_mac_update_t`
  * - ...
- * - `psa_drv_mac_opaque_finish_t` or `psa_drv_mac_opaque_finish_verify_t`
+ * - `psa_drv_se_mac_finish_t` or `psa_drv_se_mac_finish_verify_t`
  *
- * If a previously started Opaque MAC operation needs to be terminated, it
- * should be done so by the `psa_drv_mac_opaque_abort_t`. Failure to do so may
+ * If a previously started secure element MAC operation needs to be terminated,
+ * it should be done so by the `psa_drv_se_mac_abort_t`. Failure to do so may
  * result in allocated resources not being freed or in other undefined
  * behavior.
  */
 /**@{*/
-/** \brief A function that starts a MAC operation for a PSA Crypto Driver
- * implementation using an opaque key
+/** \brief A function that starts a secure element  MAC operation for a PSA
+ * Crypto Driver implementation
  *
  * \param[in,out] p_context     A structure that will contain the
  *                              hardware-specific MAC context
@@ -75,26 +75,26 @@
  * \retval  PSA_SUCCESS
  *          Success.
  */
-typedef psa_status_t (*psa_drv_mac_opaque_setup_t)(void *p_context,
-                                                   psa_key_slot_t key_slot,
-                                                   psa_algorithm_t algorithm);
+typedef psa_status_t (*psa_drv_se_mac_setup_t)(void *p_context,
+                                               psa_key_slot_number_t key_slot,
+                                               psa_algorithm_t algorithm);
 
-/** \brief A function that continues a previously started MAC operation using
- * an opaque key
+/** \brief A function that continues a previously started secure element MAC
+ * operation
  *
  * \param[in,out] p_context     A hardware-specific structure for the
  *                              previously-established MAC operation to be
- *                              continued
+ *                              updated
  * \param[in] p_input           A buffer containing the message to be appended
  *                              to the MAC operation
  * \param[in] input_length  The size in bytes of the input message buffer
  */
-typedef psa_status_t (*psa_drv_mac_opaque_update_t)(void *p_context,
-                                                    const uint8_t *p_input,
-                                                    size_t input_length);
+typedef psa_status_t (*psa_drv_se_mac_update_t)(void *p_context,
+                                                const uint8_t *p_input,
+                                                size_t input_length);
 
-/** \brief a function that completes a previously started MAC operation by
- * returning the resulting MAC using an opaque key
+/** \brief a function that completes a previously started secure element MAC
+ * operation by returning the resulting MAC.
  *
  * \param[in,out] p_context     A hardware-specific structure for the
  *                              previously started MAC operation to be
@@ -109,13 +109,13 @@
  * \retval PSA_SUCCESS
  *          Success.
  */
-typedef psa_status_t (*psa_drv_mac_opaque_finish_t)(void *p_context,
-                                                    uint8_t *p_mac,
-                                                    size_t mac_size,
-                                                    size_t *p_mac_length);
+typedef psa_status_t (*psa_drv_se_mac_finish_t)(void *p_context,
+                                                uint8_t *p_mac,
+                                                size_t mac_size,
+                                                size_t *p_mac_length);
 
-/** \brief A function that completes a previously started MAC operation by
- * comparing the resulting MAC against a known value using an opaque key
+/** \brief A function that completes a previously started secure element MAC
+ * operation by comparing the resulting MAC against a provided value
  *
  * \param[in,out] p_context A hardware-specific structure for the previously
  *                          started MAC operation to be fiinished
@@ -130,19 +130,20 @@
  *         The operation completed successfully, but the calculated MAC did
  *         not match the provided MAC
  */
-typedef psa_status_t (*psa_drv_mac_opaque_finish_verify_t)(void *p_context,
-                                                           const uint8_t *p_mac,
-                                                           size_t mac_length);
+typedef psa_status_t (*psa_drv_se_mac_finish_verify_t)(void *p_context,
+                                                       const uint8_t *p_mac,
+                                                       size_t mac_length);
 
-/** \brief A function that aborts a previous started opaque-key MAC operation
-
+/** \brief A function that aborts a previous started secure element MAC
+ * operation
+ *
  * \param[in,out] p_context A hardware-specific structure for the previously
  *                          started MAC operation to be aborted
  */
-typedef psa_status_t (*psa_drv_mac_opaque_abort_t)(void *p_context);
+typedef psa_status_t (*psa_drv_se_mac_abort_t)(void *p_context);
 
-/** \brief A function that performs a MAC operation in one command and returns
- * the calculated MAC using an opaque key
+/** \brief A function that performs a secure element MAC operation in one
+ * command and returns the calculated MAC
  *
  * \param[in] p_input           A buffer containing the message to be MACed
  * \param[in] input_length      The size in bytes of `p_input`
@@ -158,16 +159,16 @@
  * \retval PSA_SUCCESS
  *         Success.
  */
-typedef psa_status_t (*psa_drv_mac_opaque_generate_t)(const uint8_t *p_input,
-                                                      size_t input_length,
-                                                      psa_key_slot_t key_slot,
-                                                      psa_algorithm_t alg,
-                                                      uint8_t *p_mac,
-                                                      size_t mac_size,
-                                                      size_t *p_mac_length);
+typedef psa_status_t (*psa_drv_se_mac_generate_t)(const uint8_t *p_input,
+                                                  size_t input_length,
+                                                  psa_key_slot_number_t key_slot,
+                                                  psa_algorithm_t alg,
+                                                  uint8_t *p_mac,
+                                                  size_t mac_size,
+                                                  size_t *p_mac_length);
 
-/** \brief A function that performs an MAC operation in one command and
- * compare the resulting MAC against a known value using an opaque key
+/** \brief A function that performs a secure element MAC operation in one
+ * command and compares the resulting MAC against a provided value
  *
  * \param[in] p_input       A buffer containing the message to be MACed
  * \param[in] input_length  The size in bytes of `input`
@@ -185,21 +186,21 @@
  *         The operation completed successfully, but the calculated MAC did
  *         not match the provided MAC
  */
-typedef psa_status_t (*psa_drv_mac_opaque_verify_t)(const uint8_t *p_input,
-                                                    size_t input_length,
-                                                    psa_key_slot_t key_slot,
-                                                    psa_algorithm_t alg,
-                                                    const uint8_t *p_mac,
-                                                    size_t mac_length);
+typedef psa_status_t (*psa_drv_se_mac_verify_t)(const uint8_t *p_input,
+                                                size_t input_length,
+                                                psa_key_slot_number_t key_slot,
+                                                psa_algorithm_t alg,
+                                                const uint8_t *p_mac,
+                                                size_t mac_length);
 
 /** \brief A struct containing all of the function pointers needed to
- * implement MAC operations using opaque keys.
+ * perform secure element MAC operations
  *
  * PSA Crypto API implementations should populate the table as appropriate
  * upon startup.
  *
  * If one of the functions is not implemented (such as
- * `psa_drv_mac_opaque_generate_t`), it should be set to NULL.
+ * `psa_drv_se_mac_generate_t`), it should be set to NULL.
  *
  * Driver implementers should ensure that they implement all of the functions
  * that make sense for their hardware, and that they provide a full solution
@@ -208,57 +209,59 @@
  *
  */
 typedef struct {
-    /**The size in bytes of the hardware-specific Opaque-MAC Context structure
+    /**The size in bytes of the hardware-specific secure element MAC context
+     * structure
     */
-    size_t                              context_size;
-    /** Function that performs the setup operation
+    size_t                    context_size;
+    /** Function that performs a MAC setup operation
      */
-    psa_drv_mac_opaque_setup_t          *p_setup;
-    /** Function that performs the update operation
+    psa_drv_se_mac_setup_t          p_setup;
+    /** Function that performs a MAC update operation
      */
-    psa_drv_mac_opaque_update_t         *p_update;
-    /** Function that completes the operation
+    psa_drv_se_mac_update_t         p_update;
+    /** Function that completes a MAC operation
      */
-    psa_drv_mac_opaque_finish_t         *p_finish;
-    /** Function that completed a MAC operation with a verify check
+    psa_drv_se_mac_finish_t         p_finish;
+    /** Function that completes a MAC operation with a verify check
      */
-    psa_drv_mac_opaque_finish_verify_t  *p_finish_verify;
-    /** Function that aborts a previoustly started operation
+    psa_drv_se_mac_finish_verify_t  p_finish_verify;
+    /** Function that aborts a previoustly started MAC operation
      */
-    psa_drv_mac_opaque_abort_t          *p_abort;
-    /** Function that performs the MAC operation in one call
+    psa_drv_se_mac_abort_t          p_abort;
+    /** Function that performs a MAC operation in one call
      */
-    psa_drv_mac_opaque_generate_t       *p_mac;
-    /** Function that performs the MAC and verify operation in one call
+    psa_drv_se_mac_generate_t       p_mac;
+    /** Function that performs a MAC and verify operation in one call
      */
-    psa_drv_mac_opaque_verify_t         *p_mac_verify;
-} psa_drv_mac_opaque_t;
+    psa_drv_se_mac_verify_t         p_mac_verify;
+} psa_drv_se_mac_t;
 /**@}*/
 
-/** \defgroup opaque_cipher Opaque Symmetric Ciphers
+/** \defgroup se_cipher Secure Element Symmetric Ciphers
  *
- * Encryption and Decryption using opaque keys in block modes other than ECB
- * must be done in multiple parts, using the following flow:
- * - `psa_drv_cipher_opaque_setup_t`
- * - `psa_drv_cipher_opaque_set_iv_t` (optional depending upon block mode)
- * - `psa_drv_cipher_opaque_update_t`
+ * Encryption and Decryption using secure element keys in block modes other
+ * than ECB must be done in multiple parts, using the following flow:
+ * - `psa_drv_se_cipher_setup_t`
+ * - `psa_drv_se_cipher_set_iv_t` (optional depending upon block mode)
+ * - `psa_drv_se_cipher_update_t`
+ * - `psa_drv_se_cipher_update_t`
  * - ...
- * - `psa_drv_cipher_opaque_finish_t`
-
- * If a previously started Opaque Cipher operation needs to be terminated, it
- * should be done so by the `psa_drv_cipher_opaque_abort_t`. Failure to do so may
- * result in allocated resources not being freed or in other undefined
- * behavior.
+ * - `psa_drv_se_cipher_finish_t`
+ *
+ * If a previously started secure element Cipher operation needs to be
+ * terminated, it should be done so by the `psa_drv_se_cipher_abort_t`. Failure
+ * to do so may result in allocated resources not being freed or in other
+ * undefined behavior.
  *
  * In situations where a PSA Cryptographic API implementation is using a block
  * mode not-supported by the underlying hardware or driver, it can construct
- * the block mode itself, while calling the `psa_drv_cipher_opaque_ecb_t` function
- * pointer for the cipher operations.
+ * the block mode itself, while calling the `psa_drv_se_cipher_ecb_t` function
+ * for the cipher operations.
  */
 /**@{*/
 
-/** \brief A function pointer that provides the cipher setup function for
- * opaque-key operations
+/** \brief A function that provides the cipher setup function for a
+ * secure element driver
  *
  * \param[in,out] p_context     A structure that will contain the
  *                              hardware-specific cipher context.
@@ -272,16 +275,16 @@
  * \retval PSA_SUCCESS
  * \retval PSA_ERROR_NOT_SUPPORTED
  */
-typedef psa_status_t (*psa_drv_cipher_opaque_setup_t)(void *p_context,
-                                                      psa_key_slot_t key_slot,
-                                                      psa_algorithm_t algorithm,
-                                                      psa_encrypt_or_decrypt_t direction);
+typedef psa_status_t (*psa_drv_se_cipher_setup_t)(void *p_context,
+                                                  psa_key_slot_number_t key_slot,
+                                                  psa_algorithm_t algorithm,
+                                                  psa_encrypt_or_decrypt_t direction);
 
-/** \brief A function pointer that sets the initialization vector (if
- * necessary) for an opaque cipher operation
+/** \brief A function that sets the initialization vector (if
+ * necessary) for an secure element cipher operation
  *
- * Rationale: The `psa_cipher_*` function in the PSA Cryptographic API has two
- * IV functions: one to set the IV, and one to generate it internally. The
+ * Rationale: The `psa_se_cipher_*` operation in the PSA Cryptographic API has
+ * two IV functions: one to set the IV, and one to generate it internally. The
  * generate function is not necessary for the drivers to implement as the PSA
  * Crypto implementation can do the generation using its RNG features.
  *
@@ -292,11 +295,11 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_opaque_set_iv_t)(void *p_context,
-                                                       const uint8_t *p_iv,
-                                                       size_t iv_length);
+typedef psa_status_t (*psa_drv_se_cipher_set_iv_t)(void *p_context,
+                                                   const uint8_t *p_iv,
+                                                   size_t iv_length);
 
-/** \brief A function that continues a previously started opaque-key cipher
+/** \brief A function that continues a previously started secure element cipher
  * operation
  *
  * \param[in,out] p_context         A hardware-specific structure for the
@@ -314,14 +317,14 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_opaque_update_t)(void *p_context,
-                                                       const uint8_t *p_input,
-                                                       size_t input_size,
-                                                       uint8_t *p_output,
-                                                       size_t output_size,
-                                                       size_t *p_output_length);
+typedef psa_status_t (*psa_drv_se_cipher_update_t)(void *p_context,
+                                                   const uint8_t *p_input,
+                                                   size_t input_size,
+                                                   uint8_t *p_output,
+                                                   size_t output_size,
+                                                   size_t *p_output_length);
 
-/** \brief A function that completes a previously started opaque-key cipher
+/** \brief A function that completes a previously started secure element cipher
  * operation
  *
  * \param[in,out] p_context     A hardware-specific structure for the
@@ -335,21 +338,21 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_cipher_opaque_finish_t)(void *p_context,
-                                                       uint8_t *p_output,
-                                                       size_t output_size,
-                                                       size_t *p_output_length);
+typedef psa_status_t (*psa_drv_se_cipher_finish_t)(void *p_context,
+                                                   uint8_t *p_output,
+                                                   size_t output_size,
+                                                   size_t *p_output_length);
 
-/** \brief A function that aborts a previously started opaque-key cipher
+/** \brief A function that aborts a previously started secure element cipher
  * operation
  *
  * \param[in,out] p_context     A hardware-specific structure for the
  *                              previously started cipher operation
  */
-typedef psa_status_t (*psa_drv_cipher_opaque_abort_t)(void *p_context);
+typedef psa_status_t (*psa_drv_se_cipher_abort_t)(void *p_context);
 
-/** \brief A function that performs the ECB block mode for opaque-key cipher
- * operations
+/** \brief A function that performs the ECB block mode for secure element
+ * cipher operations
  *
  * Note: this function should only be used with implementations that do not
  * provide a needed higher-level operation.
@@ -370,58 +373,59 @@
  * \retval PSA_SUCCESS
  * \retval PSA_ERROR_NOT_SUPPORTED
  */
-typedef psa_status_t (*psa_drv_cipher_opaque_ecb_t)(psa_key_slot_t key_slot,
-                                                    psa_algorithm_t algorithm,
-                                                    psa_encrypt_or_decrypt_t direction,
-                                                    const uint8_t *p_input,
-                                                    size_t input_size,
-                                                    uint8_t *p_output,
-                                                    size_t output_size);
+typedef psa_status_t (*psa_drv_se_cipher_ecb_t)(psa_key_slot_number_t key_slot,
+                                                psa_algorithm_t algorithm,
+                                                psa_encrypt_or_decrypt_t direction,
+                                                const uint8_t *p_input,
+                                                size_t input_size,
+                                                uint8_t *p_output,
+                                                size_t output_size);
 
 /**
  * \brief A struct containing all of the function pointers needed to implement
- * cipher operations using opaque keys.
+ * cipher operations using secure elements.
  *
  * PSA Crypto API implementations should populate instances of the table as
- * appropriate upon startup.
+ * appropriate upon startup or at build time.
  *
  * If one of the functions is not implemented (such as
- * `psa_drv_cipher_opaque_ecb_t`), it should be set to NULL.
+ * `psa_drv_se_cipher_ecb_t`), it should be set to NULL.
  */
 typedef struct {
-    /** The size in bytes of the hardware-specific Opaque Cipher context
-     * structure
+    /** The size in bytes of the hardware-specific secure element cipher
+     * context structure
      */
-    size_t                         size;
-    /** Function that performs the setup operation */
-    psa_drv_cipher_opaque_setup_t  *p_setup;
-    /** Function that sets the IV (if necessary) */
-    psa_drv_cipher_opaque_set_iv_t *p_set_iv;
-    /** Function that performs the update operation */
-    psa_drv_cipher_opaque_update_t *p_update;
-    /** Function that completes the operation */
-    psa_drv_cipher_opaque_finish_t *p_finish;
-    /** Function that aborts the operation */
-    psa_drv_cipher_opaque_abort_t  *p_abort;
-    /** Function that performs ECB mode for the cipher
+    size_t               context_size;
+    /** Function that performs a cipher setup operation */
+    psa_drv_se_cipher_setup_t  p_setup;
+    /** Function that sets a cipher IV (if necessary) */
+    psa_drv_se_cipher_set_iv_t p_set_iv;
+    /** Function that performs a cipher update operation */
+    psa_drv_se_cipher_update_t p_update;
+    /** Function that completes a cipher operation */
+    psa_drv_se_cipher_finish_t p_finish;
+    /** Function that aborts a cipher operation */
+    psa_drv_se_cipher_abort_t  p_abort;
+    /** Function that performs ECB mode for a cipher operation
      * (Danger: ECB mode should not be used directly by clients of the PSA
      * Crypto Client API)
      */
-    psa_drv_cipher_opaque_ecb_t    *p_ecb;
-} psa_drv_cipher_opaque_t;
+    psa_drv_se_cipher_ecb_t    p_ecb;
+} psa_drv_se_cipher_t;
 
 /**@}*/
 
-/** \defgroup opaque_asymmetric Opaque Asymmetric Cryptography
+/** \defgroup se_asymmetric Secure Element Asymmetric Cryptography
  *
  * Since the amount of data that can (or should) be encrypted or signed using
  * asymmetric keys is limited by the key size, asymmetric key operations using
- * opaque keys must be done in single function calls.
+ * keys in a secure element must be done in single function calls.
  */
 /**@{*/
 
 /**
- * \brief A function that signs a hash or short message with a private key
+ * \brief A function that signs a hash or short message with a private key in
+ * a secure element
  *
  * \param[in] key_slot              Key slot of an asymmetric key pair
  * \param[in] alg                   A signature algorithm that is compatible
@@ -435,17 +439,17 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_asymmetric_opaque_sign_t)(psa_key_slot_t key_slot,
-                                                         psa_algorithm_t alg,
-                                                         const uint8_t *p_hash,
-                                                         size_t hash_length,
-                                                         uint8_t *p_signature,
-                                                         size_t signature_size,
-                                                         size_t *p_signature_length);
+typedef psa_status_t (*psa_drv_se_asymmetric_sign_t)(psa_key_slot_number_t key_slot,
+                                                     psa_algorithm_t alg,
+                                                     const uint8_t *p_hash,
+                                                     size_t hash_length,
+                                                     uint8_t *p_signature,
+                                                     size_t signature_size,
+                                                     size_t *p_signature_length);
 
 /**
  * \brief A function that verifies the signature a hash or short message using
- * an asymmetric public key
+ * an asymmetric public key in a secure element
  *
  * \param[in] key_slot          Key slot of a public key or an asymmetric key
  *                              pair
@@ -459,16 +463,16 @@
  * \retval PSA_SUCCESS
  *         The signature is valid.
  */
-typedef psa_status_t (*psa_drv_asymmetric_opaque_verify_t)(psa_key_slot_t key_slot,
-                                                           psa_algorithm_t alg,
-                                                           const uint8_t *p_hash,
-                                                           size_t hash_length,
-                                                           const uint8_t *p_signature,
-                                                           size_t signature_length);
+typedef psa_status_t (*psa_drv_se_asymmetric_verify_t)(psa_key_slot_number_t key_slot,
+                                                       psa_algorithm_t alg,
+                                                       const uint8_t *p_hash,
+                                                       size_t hash_length,
+                                                       const uint8_t *p_signature,
+                                                       size_t signature_length);
 
 /**
  * \brief A function that encrypts a short message with an asymmetric public
- * key
+ * key in a secure element
  *
  * \param[in] key_slot          Key slot of a public key or an asymmetric key
  *                              pair
@@ -495,18 +499,19 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_asymmetric_opaque_encrypt_t)(psa_key_slot_t key_slot,
-                                                            psa_algorithm_t alg,
-                                                            const uint8_t *p_input,
-                                                            size_t input_length,
-                                                            const uint8_t *p_salt,
-                                                            size_t salt_length,
-                                                            uint8_t *p_output,
-                                                            size_t output_size,
-                                                            size_t *p_output_length);
+typedef psa_status_t (*psa_drv_se_asymmetric_encrypt_t)(psa_key_slot_number_t key_slot,
+                                                        psa_algorithm_t alg,
+                                                        const uint8_t *p_input,
+                                                        size_t input_length,
+                                                        const uint8_t *p_salt,
+                                                        size_t salt_length,
+                                                        uint8_t *p_output,
+                                                        size_t output_size,
+                                                        size_t *p_output_length);
 
 /**
- * \brief Decrypt a short message with an asymmetric private key.
+ * \brief A function that decrypts a short message with an asymmetric private
+ * key in a secure element.
  *
  * \param[in] key_slot          Key slot of an asymmetric key pair
  * \param[in] alg               An asymmetric encryption algorithm that is
@@ -532,48 +537,49 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_asymmetric_opaque_decrypt_t)(psa_key_slot_t key_slot,
-                                                            psa_algorithm_t alg,
-                                                            const uint8_t *p_input,
-                                                            size_t input_length,
-                                                            const uint8_t *p_salt,
-                                                            size_t salt_length,
-                                                            uint8_t *p_output,
-                                                            size_t output_size,
-                                                            size_t *p_output_length);
+typedef psa_status_t (*psa_drv_se_asymmetric_decrypt_t)(psa_key_slot_number_t key_slot,
+                                                        psa_algorithm_t alg,
+                                                        const uint8_t *p_input,
+                                                        size_t input_length,
+                                                        const uint8_t *p_salt,
+                                                        size_t salt_length,
+                                                        uint8_t *p_output,
+                                                        size_t output_size,
+                                                        size_t *p_output_length);
 
 /**
  * \brief A struct containing all of the function pointers needed to implement
- * asymmetric cryptographic operations using opaque keys.
+ * asymmetric cryptographic operations using secure elements.
  *
  * PSA Crypto API implementations should populate instances of the table as
- * appropriate upon startup.
+ * appropriate upon startup or at build time.
  *
  * If one of the functions is not implemented, it should be set to NULL.
  */
 typedef struct {
-    /** Function that performs the asymmetric sign operation */
-    psa_drv_asymmetric_opaque_sign_t    *p_sign;
-    /** Function that performs the asymmetric verify operation */
-    psa_drv_asymmetric_opaque_verify_t  *p_verify;
-    /** Function that performs the asymmetric encrypt operation */
-    psa_drv_asymmetric_opaque_encrypt_t *p_encrypt;
-    /** Function that performs the asymmetric decrypt operation */
-    psa_drv_asymmetric_opaque_decrypt_t *p_decrypt;
-} psa_drv_asymmetric_opaque_t;
+    /** Function that performs an asymmetric sign operation */
+    psa_drv_se_asymmetric_sign_t    p_sign;
+    /** Function that performs an asymmetric verify operation */
+    psa_drv_se_asymmetric_verify_t  p_verify;
+    /** Function that performs an asymmetric encrypt operation */
+    psa_drv_se_asymmetric_encrypt_t p_encrypt;
+    /** Function that performs an asymmetric decrypt operation */
+    psa_drv_se_asymmetric_decrypt_t p_decrypt;
+} psa_drv_se_asymmetric_t;
 
 /**@}*/
 
-/** \defgroup aead_opaque AEAD Opaque
- * Authenticated Encryption with Additional Data (AEAD) operations with opaque
- * keys must be done in one function call. While this creates a burden for
+/** \defgroup se_aead Secure Element Authenticated Encryption with Additional Data
+ * Authenticated Encryption with Additional Data (AEAD) operations with secure
+ * elements must be done in one function call. While this creates a burden for
  * implementers as there must be sufficient space in memory for the entire
  * message, it prevents decrypted data from being made available before the
  * authentication operation is complete and the data is known to be authentic.
  */
 /**@{*/
 
-/** \brief Process an authenticated encryption operation using an opaque key
+/** \brief A function that performs a secure element authenticated encryption
+ * operation
  *
  * \param[in] key_slot                  Slot containing the key to use.
  * \param[in] algorithm                 The AEAD algorithm to compute
@@ -602,19 +608,19 @@
  * \retval #PSA_SUCCESS
  *         Success.
  */
-typedef psa_status_t (*psa_drv_aead_opaque_encrypt_t)(psa_key_slot_t key_slot,
-                                                      psa_algorithm_t algorithm,
-                                                      const uint8_t *p_nonce,
-                                                      size_t nonce_length,
-                                                      const uint8_t *p_additional_data,
-                                                      size_t additional_data_length,
-                                                      const uint8_t *p_plaintext,
-                                                      size_t plaintext_length,
-                                                      uint8_t *p_ciphertext,
-                                                      size_t ciphertext_size,
-                                                      size_t *p_ciphertext_length);
+typedef psa_status_t (*psa_drv_se_aead_encrypt_t)(psa_key_slot_number_t key_slot,
+                                                  psa_algorithm_t algorithm,
+                                                  const uint8_t *p_nonce,
+                                                  size_t nonce_length,
+                                                  const uint8_t *p_additional_data,
+                                                  size_t additional_data_length,
+                                                  const uint8_t *p_plaintext,
+                                                  size_t plaintext_length,
+                                                  uint8_t *p_ciphertext,
+                                                  size_t ciphertext_size,
+                                                  size_t *p_ciphertext_length);
 
-/** Process an authenticated decryption operation using an opaque key
+/** A function that peforms a secure element authenticated decryption operation
  *
  * \param[in] key_slot                  Slot containing the key to use
  * \param[in] algorithm                 The AEAD algorithm to compute
@@ -642,21 +648,21 @@
  * \retval #PSA_SUCCESS
  *         Success.
  */
-typedef psa_status_t (*psa_drv_aead_opaque_decrypt_t)(psa_key_slot_t key_slot,
-                                                      psa_algorithm_t algorithm,
-                                                      const uint8_t *p_nonce,
-                                                      size_t nonce_length,
-                                                      const uint8_t *p_additional_data,
-                                                      size_t additional_data_length,
-                                                      const uint8_t *p_ciphertext,
-                                                      size_t ciphertext_length,
-                                                      uint8_t *p_plaintext,
-                                                      size_t plaintext_size,
-                                                      size_t *p_plaintext_length);
+typedef psa_status_t (*psa_drv_se_aead_decrypt_t)(psa_key_slot_number_t key_slot,
+                                                  psa_algorithm_t algorithm,
+                                                  const uint8_t *p_nonce,
+                                                  size_t nonce_length,
+                                                  const uint8_t *p_additional_data,
+                                                  size_t additional_data_length,
+                                                  const uint8_t *p_ciphertext,
+                                                  size_t ciphertext_length,
+                                                  uint8_t *p_plaintext,
+                                                  size_t plaintext_size,
+                                                  size_t *p_plaintext_length);
 
 /**
  * \brief A struct containing all of the function pointers needed to implement
- * Authenticated Encryption with Additional Data operations using opaque keys
+ * secure element Authenticated Encryption with Additional Data operations
  *
  * PSA Crypto API implementations should populate instances of the table as
  * appropriate upon startup.
@@ -665,13 +671,13 @@
  */
 typedef struct {
     /** Function that performs the AEAD encrypt operation */
-    psa_drv_aead_opaque_encrypt_t *p_encrypt;
+    psa_drv_se_aead_encrypt_t p_encrypt;
     /** Function that performs the AEAD decrypt operation */
-    psa_drv_aead_opaque_decrypt_t *p_decrypt;
-} psa_drv_aead_opaque_t;
+    psa_drv_se_aead_decrypt_t p_decrypt;
+} psa_drv_se_aead_t;
 /**@}*/
 
-/** \defgroup driver_key_management Key Management
+/** \defgroup se_key_management Secure Element Key Management
  * Currently, key management is limited to importing keys in the clear,
  * destroying keys, and exporting keys in the clear.
  * Whether a key may be exported is determined by the key policies in place
@@ -679,7 +685,7 @@
  */
 /**@{*/
 
-/** \brief Import a key in binary format
+/** \brief A function that imports a key into a secure element in binary format
  *
  * This function can support any output from psa_export_key(). Refer to the
  * documentation of psa_export_key() for the format for each key type.
@@ -687,6 +693,7 @@
  * \param[in] key_slot      Slot where the key will be stored
  *                          This must be a valid slot for a key of the chosen
  *                          type. It must be unoccupied.
+ * \param[in] lifetime      The required lifetime of the key storage
  * \param[in] type          Key type (a \c PSA_KEY_TYPE_XXX value)
  * \param[in] algorithm     Key algorithm (a \c PSA_ALG_XXX value)
  * \param[in] usage         The allowed uses of the key
@@ -696,33 +703,33 @@
  * \retval #PSA_SUCCESS
  *         Success.
  */
-typedef psa_status_t (*psa_drv_opaque_import_key_t)(psa_key_slot_t key_slot,
-                                                    psa_key_type_t type,
-                                                    psa_algorithm_t algorithm,
-                                                    psa_key_usage_t usage,
-                                                    const uint8_t *p_data,
-                                                    size_t data_length);
+typedef psa_status_t (*psa_drv_se_import_key_t)(psa_key_slot_number_t key_slot,
+                                                psa_key_lifetime_t lifetime,
+                                                psa_key_type_t type,
+                                                psa_algorithm_t algorithm,
+                                                psa_key_usage_t usage,
+                                                const uint8_t *p_data,
+                                                size_t data_length);
 
 /**
- * \brief Destroy a key and restore the slot to its default state
+ * \brief A function that destroys a secure element key and restore the slot to
+ * its default state
  *
- * This function destroys the content of the key slot from both volatile
- * memory and, if applicable, non-volatile storage. Implementations shall
- * make a best effort to ensure that any previous content of the slot is
- * unrecoverable.
+ * This function destroys the content of the key from a secure element.
+ * Implementations shall make a best effort to ensure that any previous content
+ * of the slot is unrecoverable.
  *
- * This function also erases any metadata such as policies. It returns the
- * specified slot to its default state.
+ * This function returns the specified slot to its default state.
  *
  * \param[in] key_slot        The key slot to erase.
  *
  * \retval #PSA_SUCCESS
  *         The slot's content, if any, has been erased.
  */
-typedef psa_status_t (*psa_drv_destroy_key_t)(psa_key_slot_t key);
+typedef psa_status_t (*psa_drv_se_destroy_key_t)(psa_key_slot_number_t key);
 
 /**
- * \brief Export a key in binary format
+ * \brief A function that exports a secure element key in binary format
  *
  * The output of this function can be passed to psa_import_key() to
  * create an equivalent object.
@@ -732,19 +739,9 @@
  * identical: the implementation may choose a different representation
  * of the same key if the format permits it.
  *
- * For standard key types, the output format is as follows:
- *
- * - For symmetric keys (including MAC keys), the format is the
- *   raw bytes of the key.
- * - For DES, the key data consists of 8 bytes. The parity bits must be
- *   correct.
- * - For Triple-DES, the format is the concatenation of the
- *   two or three DES keys.
- * - For RSA key pairs (#PSA_KEY_TYPE_RSA_KEYPAIR), the format
- *   is the non-encrypted DER representation defined by PKCS\#1 (RFC 8017)
- *   as RSAPrivateKey.
- * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY), the format
- *   is the DER representation defined by RFC 5280 as SubjectPublicKeyInfo.
+ * This function should generate output in the same format that
+ * `psa_export_key()` does. Refer to the
+ * documentation of `psa_export_key()` for the format for each key type.
  *
  * \param[in] key               Slot whose content is to be exported. This must
  *                              be an occupied key slot.
@@ -761,60 +758,72 @@
  * \retval #PSA_ERROR_HARDWARE_FAILURE
  * \retval #PSA_ERROR_TAMPERING_DETECTED
  */
-typedef psa_status_t (*psa_drv_export_key_t)(psa_key_slot_t key,
-                                             uint8_t *p_data,
-                                             size_t data_size,
-                                             size_t *p_data_length);
+typedef psa_status_t (*psa_drv_se_export_key_t)(psa_key_slot_number_t key,
+                                                uint8_t *p_data,
+                                                size_t data_size,
+                                                size_t *p_data_length);
 
 /**
- * \brief Export a public key or the public part of a key pair in binary format
+ * \brief A function that generates a symmetric or asymmetric key on a secure
+ * element
  *
- * The output of this function can be passed to psa_import_key() to
- * create an object that is equivalent to the public key.
+ * If \p type is asymmetric (`#PSA_KEY_TYPE_IS_ASYMMETRIC(\p type) == 1`),
+ * the public component of the generated key will be placed in `p_pubkey_out`.
+ * The format of the public key information will match the format specified for
+ * the psa_export_key() function for the key type.
  *
- * For standard key types, the output format is as follows:
- *
- * - For RSA keys (#PSA_KEY_TYPE_RSA_KEYPAIR or #PSA_KEY_TYPE_RSA_PUBLIC_KEY),
- *   the format is the DER representation of the public key defined by RFC 5280
- *   as SubjectPublicKeyInfo.
- *
- * \param[in] key_slot          Slot whose content is to be exported. This must
- *                              be an occupied key slot.
- * \param[out] p_data           Buffer where the key data is to be written.
- * \param[in] data_size         Size of the `data` buffer in bytes.
- * \param[out] p_data_length    On success, the number of bytes
- *                              that make up the key data.
- *
- * \retval #PSA_SUCCESS
+ * \param[in] key_slot      Slot where the generated key will be placed
+ * \param[in] type          The type of the key to be generated
+ * \param[in] usage         The prescribed usage of the generated key
+ *                          Note: Not all Secure Elements support the same
+ *                          restrictions that PSA Crypto does (and vice versa).
+ *                          Driver developers should endeavor to match the
+ *                          usages as close as possible.
+ * \param[in] bits          The size in bits of the key to be generated.
+ * \param[in] extra         Extra parameters for key generation. The
+ *                          interpretation of this parameter should match the
+ *                          interpretation in the `extra` parameter is the
+ *                          `psa_generate_key` function
+ * \param[in] extra_size    The size in bytes of the \p extra buffer
+ * \param[out] p_pubkey_out The buffer where the public key information will
+ *                          be placed
+ * \param[in] pubkey_out_size   The size in bytes of the `p_pubkey_out` buffer
+ * \param[out] p_pubkey_length  Upon successful completion, will contain the
+ *                              size of the data placed in `p_pubkey_out`.
  */
-typedef psa_status_t (*psa_drv_export_public_key_t)(psa_key_slot_t key,
-                                                    uint8_t *p_data,
-                                                    size_t data_size,
-                                                    size_t *p_data_length);
+typedef psa_status_t (*psa_drv_se_generate_key_t)(psa_key_slot_number_t key_slot,
+                                                  psa_key_type_t type,
+                                                  psa_key_usage_t usage,
+                                                  size_t bits,
+                                                  const void *extra,
+                                                  size_t extra_size,
+                                                  uint8_t *p_pubkey_out,
+                                                  size_t pubkey_out_size,
+                                                  size_t *p_pubkey_length);
 
 /**
- * \brief A struct containing all of the function pointers needed to for key
- * management using opaque keys
+ * \brief A struct containing all of the function pointers needed to for secure
+ * element key management
  *
  * PSA Crypto API implementations should populate instances of the table as
- * appropriate upon startup.
+ * appropriate upon startup or at build time.
  *
  * If one of the functions is not implemented, it should be set to NULL.
  */
 typedef struct {
-    /** Function that performs the key import operation */
-    psa_drv_opaque_import_key_t *p_import;
-    /** Function that performs the key destroy operation */
-    psa_drv_destroy_key_t       *p_destroy;
-    /** Function that performs the key export operation */
-    psa_drv_export_key_t        *p_export;
-    /** Function that perforsm the public key export operation */
-    psa_drv_export_public_key_t *p_export_public;
-} psa_drv_key_management_t;
+    /** Function that performs a key import operation */
+    psa_drv_se_import_key_t     p_import;
+    /** Function that performs a generation */
+    psa_drv_se_generate_key_t   p_generate;
+    /** Function that performs a key destroy operation */
+    psa_drv_se_destroy_key_t    p_destroy;
+    /** Function that performs a key export operation */
+    psa_drv_se_export_key_t     p_export;
+} psa_drv_se_key_management_t;
 
 /**@}*/
 
-/** \defgroup driver_derivation Key Derivation and Agreement
+/** \defgroup driver_derivation Secure Element Key Derivation and Agreement
  * Key derivation is the process of generating new key material using an
  * existing key and additional parameters, iterating through a basic
  * cryptographic function, such as a hash.
@@ -825,53 +834,46 @@
  * for both of the flows.
  *
  * There are two different final functions for the flows,
- * `psa_drv_key_derivation_derive` and `psa_drv_key_derivation_export`.
- * `psa_drv_key_derivation_derive` is used when the key material should be placed
- * in a slot on the hardware and not exposed to the caller.
- * `psa_drv_key_derivation_export` is used when the key material should be returned
- * to the PSA Cryptographic API implementation.
+ * `psa_drv_se_key_derivation_derive` and `psa_drv_se_key_derivation_export`.
+ * `psa_drv_se_key_derivation_derive` is used when the key material should be
+ * placed in a slot on the hardware and not exposed to the caller.
+ * `psa_drv_se_key_derivation_export` is used when the key material should be
+ * returned to the PSA Cryptographic API implementation.
  *
  * Different key derivation algorithms require a different number of inputs.
  * Instead of having an API that takes as input variable length arrays, which
  * can be problemmatic to manage on embedded platforms, the inputs are passed
- * to the driver via a function, `psa_drv_key_derivation_collateral`, that is
- * called multiple times with different `collateral_id`s. Thus, for a key
+ * to the driver via a function, `psa_drv_se_key_derivation_collateral`, that
+ * is called multiple times with different `collateral_id`s. Thus, for a key
  * derivation algorithm that required 3 paramter inputs, the flow would look
  * something like:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_key_derivation_setup(kdf_algorithm, source_key, dest_key_size_bytes);
- * psa_drv_key_derivation_collateral(kdf_algorithm_collateral_id_0,
- *                                   p_collateral_0,
- *                                   collateral_0_size);
- * psa_drv_key_derivation_collateral(kdf_algorithm_collateral_id_1,
- *                                   p_collateral_1,
- *                                   collateral_1_size);
- * psa_drv_key_derivation_collateral(kdf_algorithm_collateral_id_2,
- *                                   p_collateral_2,
- *                                   collateral_2_size);
- * psa_drv_key_derivation_derive();
+ * psa_drv_se_key_derivation_setup(kdf_algorithm, source_key, dest_key_size_bytes);
+ * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_0,
+ *                                      p_collateral_0,
+ *                                      collateral_0_size);
+ * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_1,
+ *                                      p_collateral_1,
+ *                                      collateral_1_size);
+ * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_2,
+ *                                      p_collateral_2,
+ *                                      collateral_2_size);
+ * psa_drv_se_key_derivation_derive();
  * ~~~~~~~~~~~~~
  *
  * key agreement example:
  * ~~~~~~~~~~~~~{.c}
- * psa_drv_key_derivation_setup(alg, source_key. dest_key_size_bytes);
- * psa_drv_key_derivation_collateral(DHE_PUBKEY, p_pubkey, pubkey_size);
- * psa_drv_key_derivation_export(p_session_key,
- *                               session_key_size,
- *                               &session_key_length);
+ * psa_drv_se_key_derivation_setup(alg, source_key. dest_key_size_bytes);
+ * psa_drv_se_key_derivation_collateral(DHE_PUBKEY, p_pubkey, pubkey_size);
+ * psa_drv_se_key_derivation_export(p_session_key,
+ *                                  session_key_size,
+ *                                  &session_key_length);
  * ~~~~~~~~~~~~~
  */
 /**@{*/
 
-/** \brief The hardware-specific key derivation context structure
- *
- * The contents of this structure are implementation dependent and are
- * therefore not described here
- */
-typedef struct psa_drv_key_derivation_context_s psa_drv_key_derivation_context_t;
-
-/** \brief Set up a key derivation operation by specifying the algorithm and
- * the source key sot
+/** \brief A function that Sets up a secure element key derivation operation by
+ * specifying the algorithm and the source key sot
  *
  * \param[in,out] p_context A hardware-specific structure containing any
  *                          context information for the implementation
@@ -881,12 +883,12 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_key_derivation_setup_t)(psa_drv_key_derivation_context_t *p_context,
-                                                       psa_algorithm_t kdf_alg,
-                                                       psa_key_slot_t source_key);
+typedef psa_status_t (*psa_drv_se_key_derivation_setup_t)(void *p_context,
+                                                          psa_algorithm_t kdf_alg,
+                                                          psa_key_slot_number_t source_key);
 
-/** \brief Provide collateral (parameters) needed for a key derivation or key
- * agreement operation
+/** \brief A function that provides collateral (parameters) needed for a secure
+ * element key derivation or key agreement operation
  *
  * Since many key derivation algorithms require multiple parameters, it is
  * expeced that this function may be called multiple times for the same
@@ -900,13 +902,14 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_key_derivation_collateral_t)(psa_drv_key_derivation_context_t *p_context,
-                                                            uint32_t collateral_id,
-                                                            const uint8_t *p_collateral,
-                                                            size_t collateral_size);
+typedef psa_status_t (*psa_drv_se_key_derivation_collateral_t)(void *p_context,
+                                                               uint32_t collateral_id,
+                                                               const uint8_t *p_collateral,
+                                                               size_t collateral_size);
 
-/** \brief Perform the final key derivation step and place the generated key
- * material in a slot
+/** \brief A function that performs the final secure element key derivation
+ * step and place the generated key material in a slot
+ *
  * \param[in,out] p_context     A hardware-specific structure containing any
  *                              context information for the implementation
  * \param[in] dest_key          The slot where the generated key material
@@ -914,11 +917,11 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_key_derivation_derive_t)(psa_drv_key_derivation_context_t *p_context,
-                                                        psa_key_slot_t dest_key);
+typedef psa_status_t (*psa_drv_se_key_derivation_derive_t)(void *p_context,
+                                                          psa_key_slot_number_t dest_key);
 
-/** \brief Perform the final step of a key agreement and place the generated
- * key material in a buffer
+/** \brief A function that performs the final step of a secure element key
+ * agreement and place the generated key material in a buffer
  *
  * \param[out] p_output         Buffer in which to place the generated key
  *                              material
@@ -928,13 +931,14 @@
  *
  * \retval PSA_SUCCESS
  */
-typedef psa_status_t (*psa_drv_key_derivation_export_t)(uint8_t *p_output,
-                                                        size_t output_size,
-                                                        size_t *p_output_length);
+typedef psa_status_t (*psa_drv_se_key_derivation_export_t)(void *p_context,
+                                                           uint8_t *p_output,
+                                                           size_t output_size,
+                                                           size_t *p_output_length);
 
 /**
- * \brief A struct containing all of the function pointers needed to for key
- * derivation and agreement
+ * \brief A struct containing all of the function pointers needed to for secure
+ * element key derivation and agreement
  *
  * PSA Crypto API implementations should populate instances of the table as
  * appropriate upon startup.
@@ -942,16 +946,18 @@
  * If one of the functions is not implemented, it should be set to NULL.
  */
 typedef struct {
-    /** Function that performs the key derivation setup */
-    psa_drv_key_derivation_setup_t      *p_setup;
-    /** Function that sets the key derivation collateral */
-    psa_drv_key_derivation_collateral_t *p_collateral;
-    /** Function that performs the final key derivation step */
-    psa_drv_key_derivation_derive_t     *p_derive;
-    /** Function that perforsm the final key derivation or agreement and
+    /** The driver-specific size of the key derivation context */
+    size_t                           context_size;
+    /** Function that performs a key derivation setup */
+    psa_drv_se_key_derivation_setup_t      p_setup;
+    /** Function that sets key derivation collateral */
+    psa_drv_se_key_derivation_collateral_t p_collateral;
+    /** Function that performs a final key derivation step */
+    psa_drv_se_key_derivation_derive_t     p_derive;
+    /** Function that perforsm a final key derivation or agreement and
      * exports the key */
-    psa_drv_key_derivation_export_t     *p_export;
-} psa_drv_key_derivation_t;
+    psa_drv_se_key_derivation_export_t     p_export;
+} psa_drv_se_key_derivation_t;
 
 /**@}*/
 
diff --git a/library/bignum.c b/library/bignum.c
index 87015af..47e4529 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -1869,8 +1869,10 @@
     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
 
+#if( MBEDTLS_MPI_WINDOW_SIZE < 6 )
     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
         wsize = MBEDTLS_MPI_WINDOW_SIZE;
+#endif
 
     j = N->n + 1;
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
diff --git a/library/ccm.c b/library/ccm.c
index 01e58b0..2c87b3e 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -80,7 +80,8 @@
     CCM_VALIDATE_RET( ctx != NULL );
     CCM_VALIDATE_RET( key != NULL );
 
-    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
+    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
+                                                   MBEDTLS_MODE_ECB );
     if( cipher_info == NULL )
         return( MBEDTLS_ERR_CCM_BAD_INPUT );
 
@@ -423,34 +424,34 @@
 /*
  * The data is the same for all tests, only the used length changes
  */
-static const unsigned char key[] = {
+static const unsigned char key_test_data[] = {
     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
 };
 
-static const unsigned char iv[] = {
+static const unsigned char iv_test_data[] = {
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     0x18, 0x19, 0x1a, 0x1b
 };
 
-static const unsigned char ad[] = {
+static const unsigned char ad_test_data[] = {
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x10, 0x11, 0x12, 0x13
 };
 
-static const unsigned char msg[CCM_SELFTEST_PT_MAX_LEN] = {
+static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
 };
 
-static const size_t iv_len [NB_TESTS] = { 7, 8,  12 };
-static const size_t add_len[NB_TESTS] = { 8, 16, 20 };
-static const size_t msg_len[NB_TESTS] = { 4, 16, 24 };
-static const size_t tag_len[NB_TESTS] = { 4, 6,  8  };
+static const size_t iv_len_test_data [NB_TESTS] = { 7, 8,  12 };
+static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
+static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
+static const size_t tag_len_test_data[NB_TESTS] = { 4, 6,  8  };
 
-static const unsigned char res[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
+static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
     {   0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
     {   0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
         0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
@@ -476,7 +477,8 @@
 
     mbedtls_ccm_init( &ctx );
 
-    if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
+    if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
+                            8 * sizeof key_test_data ) != 0 )
     {
         if( verbose != 0 )
             mbedtls_printf( "  CCM: setup failed" );
@@ -491,15 +493,18 @@
 
         memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
         memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN );
-        memcpy( plaintext, msg, msg_len[i] );
+        memcpy( plaintext, msg_test_data, msg_len_test_data[i] );
 
-        ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i],
-                                           iv, iv_len[i], ad, add_len[i],
+        ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i],
+                                           iv_test_data, iv_len_test_data[i],
+                                           ad_test_data, add_len_test_data[i],
                                            plaintext, ciphertext,
-                                           ciphertext + msg_len[i], tag_len[i] );
+                                           ciphertext + msg_len_test_data[i],
+                                           tag_len_test_data[i] );
 
         if( ret != 0 ||
-            memcmp( ciphertext, res[i], msg_len[i] + tag_len[i] ) != 0 )
+            memcmp( ciphertext, res_test_data[i],
+                    msg_len_test_data[i] + tag_len_test_data[i] ) != 0 )
         {
             if( verbose != 0 )
                 mbedtls_printf( "failed\n" );
@@ -508,13 +513,15 @@
         }
         memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
 
-        ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i],
-                                        iv, iv_len[i], ad, add_len[i],
+        ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i],
+                                        iv_test_data, iv_len_test_data[i],
+                                        ad_test_data, add_len_test_data[i],
                                         ciphertext, plaintext,
-                                        ciphertext + msg_len[i], tag_len[i] );
+                                        ciphertext + msg_len_test_data[i],
+                                        tag_len_test_data[i] );
 
         if( ret != 0 ||
-            memcmp( plaintext, msg, msg_len[i] ) != 0 )
+            memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 )
         {
             if( verbose != 0 )
                 mbedtls_printf( "failed\n" );
diff --git a/library/certs.c b/library/certs.c
index ff0f11e..b54ff61 100644
--- a/library/certs.c
+++ b/library/certs.c
@@ -116,7 +116,6 @@
 #endif /* MBEDTLS_ECDSA_C */
 
 #if defined(MBEDTLS_RSA_C)
-
 #if defined(MBEDTLS_SHA256_C)
 #define TEST_CA_CRT_RSA_SHA256                                          \
 "-----BEGIN CERTIFICATE-----\r\n"                                       \
@@ -141,13 +140,11 @@
 "n20NRVA1Vjs6GAROr4NqW4k/+LofY9y0LLDE+p0oIEKXIsIvhPr39swxSA==\r\n"      \
 "-----END CERTIFICATE-----\r\n"
 
+static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256;
 const char   mbedtls_test_ca_crt_rsa[]   = TEST_CA_CRT_RSA_SHA256;
 const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa );
 #define TEST_CA_CRT_RSA_SOME
-
-static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256;
-
-#endif
+#endif /* MBEDTLS_SHA256_C */
 
 #if !defined(TEST_CA_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C)
 #define TEST_CA_CRT_RSA_SHA1                                            \
@@ -173,14 +170,72 @@
 "7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n"      \
 "-----END CERTIFICATE-----\r\n"
 
+static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1;
+
 #if !defined (TEST_CA_CRT_RSA_SOME)
 const char   mbedtls_test_ca_crt_rsa[]   = TEST_CA_CRT_RSA_SHA1;
 const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa );
-#endif
+#endif /* !TEST_CA_CRT_RSA_SOME */
+#endif /* !TEST_CA_CRT_RSA_COME || MBEDTLS_SHA1_C */
 
-static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1;
+#if defined(MBEDTLS_SHA256_C)
+/* tests/data_files/server2-sha256.crt */
+#define TEST_SRV_CRT_RSA_SHA256                                          \
+"-----BEGIN CERTIFICATE-----\r\n"                                        \
+"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"   \
+"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"   \
+"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"   \
+"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"   \
+"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n"   \
+"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n"   \
+"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n"   \
+"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n"   \
+"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n"   \
+"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n"   \
+"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n"   \
+"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQELBQADggEBAGGEshT5\r\n"   \
+"kvnRmLVScVeUEdwIrvW7ezbGbUvJ8VxeJ79/HSjlLiGbMc4uUathwtzEdi9R/4C5\r\n"   \
+"DXBNeEPTkbB+fhG1W06iHYj/Dp8+aaG7fuDxKVKHVZSqBnmQLn73ymyclZNHii5A\r\n"   \
+"3nTS8WUaHAzxN/rajOtoM7aH1P9tULpHrl+7HOeLMpxUnwI12ZqZaLIzxbcdJVcr\r\n"   \
+"ra2F00aXCGkYVLvyvbZIq7LC+yVysej5gCeQYD7VFOEks0jhFjrS06gP0/XnWv6v\r\n"   \
+"eBoPez9d+CCjkrhseiWzXOiriIMICX48EloO/DrsMRAtvlwq7EDz4QhILz6ffndm\r\n"   \
+"e4K1cVANRPN2o9Y=\r\n"                                                   \
+"-----END CERTIFICATE-----\r\n"
 
-#endif
+const char mbedtls_test_srv_crt_rsa[]     =  TEST_SRV_CRT_RSA_SHA256;
+const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
+#define TEST_SRV_CRT_RSA_SOME
+#endif /* MBEDTLS_SHA256_C */
+
+#if !defined(TEST_SRV_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C)
+/* tests/data_files/server2.crt */
+#define TEST_SRV_CRT_RSA_SHA1                                          \
+"-----BEGIN CERTIFICATE-----\r\n"                                      \
+"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \
+"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \
+"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \
+"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" \
+"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" \
+"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" \
+"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" \
+"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" \
+"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" \
+"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" \
+"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" \
+"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAAFzC0rF\r\n" \
+"y6De8WMcdgQrEw3AhBHFjzqnxZw1ene4IBSC7lTw8rBSy3jOWQdPUWn+0y/pCeeF\r\n" \
+"kti6sevFdl1hLemGtd4q+T9TKEKGg3ND4ARfB5AUZZ9uEHq8WBkiwus5clGS17Qd\r\n" \
+"dS/TOisB59tQruLx1E1bPLtBKyqk4koC5WAULJwfpswGSyWJTpYwIpxcWE3D2tBu\r\n" \
+"UB6MZfXZFzWmWEOyKbeoXjXe8GBCGgHLywvYDsGQ36HSGtEsAvR2QaTLSxWYcfk1\r\n" \
+"fbDn4jSWkb4yZy1r01UEigFQtONieGwRFaUqEcFJHJvEEGVgh9keaVlOj2vrwf5r\r\n" \
+"4mN4lW7gLdenN6g=\r\n"                                                 \
+"-----END CERTIFICATE-----\r\n";
+
+#if !defined(TEST_SRV_CRT_RSA_SOME)
+const char mbedtls_test_srv_crt_rsa[]     =  TEST_SRV_CRT_RSA_SHA1;
+const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
+#endif /* TEST_SRV_CRT_RSA_SOME */
+#endif /* !TEST_CA_CRT_RSA_SOME || MBEDTLS_SHA1_C */
 
 const char mbedtls_test_ca_key_rsa[] =
 "-----BEGIN RSA PRIVATE KEY-----\r\n"
@@ -218,31 +273,6 @@
 const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest";
 const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1;
 
-/* tests/data_files/server2.crt */
-const char mbedtls_test_srv_crt_rsa[] =
-"-----BEGIN CERTIFICATE-----\r\n"
-"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"
-"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
-"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"
-"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"
-"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n"
-"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n"
-"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n"
-"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n"
-"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n"
-"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n"
-"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n"
-"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAAFzC0rF\r\n"
-"y6De8WMcdgQrEw3AhBHFjzqnxZw1ene4IBSC7lTw8rBSy3jOWQdPUWn+0y/pCeeF\r\n"
-"kti6sevFdl1hLemGtd4q+T9TKEKGg3ND4ARfB5AUZZ9uEHq8WBkiwus5clGS17Qd\r\n"
-"dS/TOisB59tQruLx1E1bPLtBKyqk4koC5WAULJwfpswGSyWJTpYwIpxcWE3D2tBu\r\n"
-"UB6MZfXZFzWmWEOyKbeoXjXe8GBCGgHLywvYDsGQ36HSGtEsAvR2QaTLSxWYcfk1\r\n"
-"fbDn4jSWkb4yZy1r01UEigFQtONieGwRFaUqEcFJHJvEEGVgh9keaVlOj2vrwf5r\r\n"
-"4mN4lW7gLdenN6g=\r\n"
-"-----END CERTIFICATE-----\r\n";
-const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
-
-/* tests/data_files/server2.key */
 const char mbedtls_test_srv_key_rsa[] =
 "-----BEGIN RSA PRIVATE KEY-----\r\n"
 "MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n"
diff --git a/library/debug.c b/library/debug.c
index 6e1efbf..0c46c06 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -87,8 +87,13 @@
     char str[DEBUG_BUF_SIZE];
     int ret;
 
-    if( NULL == ssl || NULL == ssl->conf || NULL == ssl->conf->f_dbg || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     va_start( argp, format );
     ret = mbedtls_vsnprintf( str, DEBUG_BUF_SIZE, format, argp );
@@ -109,8 +114,13 @@
 {
     char str[DEBUG_BUF_SIZE];
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     /*
      * With non-blocking I/O and examples that just retry immediately,
@@ -134,8 +144,13 @@
     char txt[17];
     size_t i, idx = 0;
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n",
               text, (unsigned int) len );
@@ -187,8 +202,13 @@
 {
     char str[DEBUG_BUF_SIZE];
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     mbedtls_snprintf( str, sizeof( str ), "%s(X)", text );
     mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X );
@@ -207,8 +227,14 @@
     int j, k, zeros = 1;
     size_t i, n, idx = 0;
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        NULL == X                ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     for( n = X->n - 1; n > 0; n-- )
         if( X->p[n] != 0 )
@@ -333,8 +359,14 @@
     char str[DEBUG_BUF_SIZE];
     int i = 0;
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        NULL == crt              ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     while( crt != NULL )
     {
diff --git a/library/gcm.c b/library/gcm.c
index 675926a..5121a7a 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -175,7 +175,8 @@
     GCM_VALIDATE_RET( key != NULL );
     GCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 );
 
-    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
+    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
+                                                   MBEDTLS_MODE_ECB );
     if( cipher_info == NULL )
         return( MBEDTLS_ERR_GCM_BAD_INPUT );
 
@@ -335,8 +336,8 @@
         gcm_mult( ctx, ctx->y, ctx->y );
     }
 
-    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr,
-                             &olen ) ) != 0 )
+    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16,
+                                       ctx->base_ectr, &olen ) ) != 0 )
     {
         return( ret );
     }
@@ -557,10 +558,10 @@
  */
 #define MAX_TESTS   6
 
-static const int key_index[MAX_TESTS] =
+static const int key_index_test_data[MAX_TESTS] =
     { 0, 0, 1, 1, 1, 1 };
 
-static const unsigned char key[MAX_TESTS][32] =
+static const unsigned char key_test_data[MAX_TESTS][32] =
 {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -572,13 +573,13 @@
       0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
 };
 
-static const size_t iv_len[MAX_TESTS] =
+static const size_t iv_len_test_data[MAX_TESTS] =
     { 12, 12, 12, 12, 8, 60 };
 
-static const int iv_index[MAX_TESTS] =
+static const int iv_index_test_data[MAX_TESTS] =
     { 0, 0, 1, 1, 1, 2 };
 
-static const unsigned char iv[MAX_TESTS][64] =
+static const unsigned char iv_test_data[MAX_TESTS][64] =
 {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00 },
@@ -594,13 +595,13 @@
       0xa6, 0x37, 0xb3, 0x9b },
 };
 
-static const size_t add_len[MAX_TESTS] =
+static const size_t add_len_test_data[MAX_TESTS] =
     { 0, 0, 0, 20, 20, 20 };
 
-static const int add_index[MAX_TESTS] =
+static const int add_index_test_data[MAX_TESTS] =
     { 0, 0, 0, 1, 1, 1 };
 
-static const unsigned char additional[MAX_TESTS][64] =
+static const unsigned char additional_test_data[MAX_TESTS][64] =
 {
     { 0x00 },
     { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
@@ -608,13 +609,13 @@
       0xab, 0xad, 0xda, 0xd2 },
 };
 
-static const size_t pt_len[MAX_TESTS] =
+static const size_t pt_len_test_data[MAX_TESTS] =
     { 0, 16, 64, 60, 60, 60 };
 
-static const int pt_index[MAX_TESTS] =
+static const int pt_index_test_data[MAX_TESTS] =
     { 0, 0, 1, 1, 1, 1 };
 
-static const unsigned char pt[MAX_TESTS][64] =
+static const unsigned char pt_test_data[MAX_TESTS][64] =
 {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
@@ -628,7 +629,7 @@
       0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
 };
 
-static const unsigned char ct[MAX_TESTS * 3][64] =
+static const unsigned char ct_test_data[MAX_TESTS * 3][64] =
 {
     { 0x00 },
     { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
@@ -737,7 +738,7 @@
       0x44, 0xae, 0x7e, 0x3f },
 };
 
-static const unsigned char tag[MAX_TESTS * 3][16] =
+static const unsigned char tag_test_data[MAX_TESTS * 3][16] =
 {
     { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
       0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a },
@@ -797,7 +798,8 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d (%s): ",
                                 key_len, i, "enc" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             /*
              * AES-192 is an optional feature that may be unavailable when
@@ -815,15 +817,19 @@
             }
 
             ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT,
-                                        pt_len[i],
-                                        iv[iv_index[i]], iv_len[i],
-                                        additional[add_index[i]], add_len[i],
-                                        pt[pt_index[i]], buf, 16, tag_buf );
+                                pt_len_test_data[i],
+                                iv_test_data[iv_index_test_data[i]],
+                                iv_len_test_data[i],
+                                additional_test_data[add_index_test_data[i]],
+                                add_len_test_data[i],
+                                pt_test_data[pt_index_test_data[i]],
+                                buf, 16, tag_buf );
             if( ret != 0 )
                 goto exit;
 
-            if ( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
-                 memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if ( memcmp( buf, ct_test_data[j * 6 + i],
+                         pt_len_test_data[i] ) != 0 ||
+                 memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
@@ -840,22 +846,26 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d (%s): ",
                                 key_len, i, "dec" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             if( ret != 0 )
                 goto exit;
 
             ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT,
-                                        pt_len[i],
-                                        iv[iv_index[i]], iv_len[i],
-                                        additional[add_index[i]], add_len[i],
-                                        ct[j * 6 + i], buf, 16, tag_buf );
+                                pt_len_test_data[i],
+                                iv_test_data[iv_index_test_data[i]],
+                                iv_len_test_data[i],
+                                additional_test_data[add_index_test_data[i]],
+                                add_len_test_data[i],
+                                ct_test_data[j * 6 + i], buf, 16, tag_buf );
 
             if( ret != 0 )
                 goto exit;
 
-            if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if( memcmp( buf, pt_test_data[pt_index_test_data[i]],
+                        pt_len_test_data[i] ) != 0 ||
+                memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
@@ -872,32 +882,40 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d split (%s): ",
                                 key_len, i, "enc" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             if( ret != 0 )
                 goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT,
-                                      iv[iv_index[i]], iv_len[i],
-                                      additional[add_index[i]], add_len[i] );
+                                  iv_test_data[iv_index_test_data[i]],
+                                  iv_len_test_data[i],
+                                  additional_test_data[add_index_test_data[i]],
+                                  add_len_test_data[i] );
             if( ret != 0 )
                 goto exit;
 
-            if( pt_len[i] > 32 )
+            if( pt_len_test_data[i] > 32 )
             {
-                size_t rest_len = pt_len[i] - 32;
-                ret = mbedtls_gcm_update( &ctx, 32, pt[pt_index[i]], buf );
+                size_t rest_len = pt_len_test_data[i] - 32;
+                ret = mbedtls_gcm_update( &ctx, 32,
+                                          pt_test_data[pt_index_test_data[i]],
+                                          buf );
                 if( ret != 0 )
                     goto exit;
 
-                ret = mbedtls_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32,
-                                  buf + 32 );
+                ret = mbedtls_gcm_update( &ctx, rest_len,
+                                      pt_test_data[pt_index_test_data[i]] + 32,
+                                      buf + 32 );
                 if( ret != 0 )
                     goto exit;
             }
             else
             {
-                ret = mbedtls_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf );
+                ret = mbedtls_gcm_update( &ctx, pt_len_test_data[i],
+                                          pt_test_data[pt_index_test_data[i]],
+                                          buf );
                 if( ret != 0 )
                     goto exit;
             }
@@ -906,8 +924,9 @@
             if( ret != 0 )
                 goto exit;
 
-            if( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if( memcmp( buf, ct_test_data[j * 6 + i],
+                        pt_len_test_data[i] ) != 0 ||
+                memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
@@ -924,32 +943,38 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d split (%s): ",
                                 key_len, i, "dec" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             if( ret != 0 )
                 goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT,
-                              iv[iv_index[i]], iv_len[i],
-                              additional[add_index[i]], add_len[i] );
+                              iv_test_data[iv_index_test_data[i]],
+                              iv_len_test_data[i],
+                              additional_test_data[add_index_test_data[i]],
+                              add_len_test_data[i] );
             if( ret != 0 )
                 goto exit;
 
-            if( pt_len[i] > 32 )
+            if( pt_len_test_data[i] > 32 )
             {
-                size_t rest_len = pt_len[i] - 32;
-                ret = mbedtls_gcm_update( &ctx, 32, ct[j * 6 + i], buf );
+                size_t rest_len = pt_len_test_data[i] - 32;
+                ret = mbedtls_gcm_update( &ctx, 32, ct_test_data[j * 6 + i],
+                                          buf );
                 if( ret != 0 )
                     goto exit;
 
-                ret = mbedtls_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32,
+                ret = mbedtls_gcm_update( &ctx, rest_len,
+                                          ct_test_data[j * 6 + i] + 32,
                                           buf + 32 );
                 if( ret != 0 )
                     goto exit;
             }
             else
             {
-                ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i],
+                ret = mbedtls_gcm_update( &ctx, pt_len_test_data[i],
+                                          ct_test_data[j * 6 + i],
                                           buf );
                 if( ret != 0 )
                     goto exit;
@@ -959,8 +984,9 @@
             if( ret != 0 )
                 goto exit;
 
-            if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if( memcmp( buf, pt_test_data[pt_index_test_data[i]],
+                        pt_len_test_data[i] ) != 0 ||
+                memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
diff --git a/library/oid.c b/library/oid.c
index edea950..294bbd6 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -41,10 +41,6 @@
 #define mbedtls_snprintf snprintf
 #endif
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
-#include "mbedtls/x509.h"
-#endif
-
 /*
  * Macro to automatically add the size of #define'd OIDs
  */
@@ -152,7 +148,6 @@
     return( MBEDTLS_ERR_OID_NOT_FOUND );                                   \
 }
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
 /*
  * For X520 attribute types
  */
@@ -260,23 +255,23 @@
 {
     {
         { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ),    "id-ce-basicConstraints",   "Basic Constraints" },
-        MBEDTLS_X509_EXT_BASIC_CONSTRAINTS,
+        MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS,
     },
     {
         { ADD_LEN( MBEDTLS_OID_KEY_USAGE ),            "id-ce-keyUsage",           "Key Usage" },
-        MBEDTLS_X509_EXT_KEY_USAGE,
+        MBEDTLS_OID_X509_EXT_KEY_USAGE,
     },
     {
         { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ),   "id-ce-extKeyUsage",        "Extended Key Usage" },
-        MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE,
+        MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE,
     },
     {
         { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ),     "id-ce-subjectAltName",     "Subject Alt Name" },
-        MBEDTLS_X509_EXT_SUBJECT_ALT_NAME,
+        MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME,
     },
     {
         { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ),         "id-netscape-certtype",     "Netscape Certificate Type" },
-        MBEDTLS_X509_EXT_NS_CERT_TYPE,
+        MBEDTLS_OID_X509_EXT_NS_CERT_TYPE,
     },
     {
         { NULL, 0, NULL, NULL },
@@ -300,7 +295,6 @@
 
 FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage)
 FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description)
-#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
 
 #if defined(MBEDTLS_MD_C)
 /*
diff --git a/library/pkcs5.c b/library/pkcs5.c
index 5013343..e7d805c 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -76,7 +76,8 @@
      *  }
      *
      */
-    if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len,
+                                      MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
         return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
 
     salt->p = p;
@@ -141,7 +142,8 @@
         return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT +
                 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
 
-    if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 )
+    if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid,
+                                      &kdf_alg_params ) ) != 0 )
         return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
 
     // Only PBKDF2 supported at the moment
@@ -202,7 +204,8 @@
     if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 )
         goto exit;
 
-    if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 )
+    if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen,
+                                       (mbedtls_operation_t) mode ) ) != 0 )
         goto exit;
 
     if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len,
@@ -217,7 +220,8 @@
 }
 #endif /* MBEDTLS_ASN1_PARSE_C */
 
-int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password,
+int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx,
+                       const unsigned char *password,
                        size_t plen, const unsigned char *salt, size_t slen,
                        unsigned int iteration_count,
                        uint32_t key_length, unsigned char *output )
@@ -304,10 +308,10 @@
 
 #define MAX_TESTS   6
 
-static const size_t plen[MAX_TESTS] =
+static const size_t plen_test_data[MAX_TESTS] =
     { 8, 8, 8, 24, 9 };
 
-static const unsigned char password[MAX_TESTS][32] =
+static const unsigned char password_test_data[MAX_TESTS][32] =
 {
     "password",
     "password",
@@ -316,10 +320,10 @@
     "pass\0word",
 };
 
-static const size_t slen[MAX_TESTS] =
+static const size_t slen_test_data[MAX_TESTS] =
     { 4, 4, 4, 36, 5 };
 
-static const unsigned char salt[MAX_TESTS][40] =
+static const unsigned char salt_test_data[MAX_TESTS][40] =
 {
     "salt",
     "salt",
@@ -328,13 +332,13 @@
     "sa\0lt",
 };
 
-static const uint32_t it_cnt[MAX_TESTS] =
+static const uint32_t it_cnt_test_data[MAX_TESTS] =
     { 1, 2, 4096, 4096, 4096 };
 
-static const uint32_t key_len[MAX_TESTS] =
+static const uint32_t key_len_test_data[MAX_TESTS] =
     { 20, 20, 20, 25, 16 };
 
-static const unsigned char result_key[MAX_TESTS][32] =
+static const unsigned char result_key_test_data[MAX_TESTS][32] =
 {
     { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
       0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
@@ -380,10 +384,12 @@
         if( verbose != 0 )
             mbedtls_printf( "  PBKDF2 (SHA1) #%d: ", i );
 
-        ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i],
-                                  slen[i], it_cnt[i], key_len[i], key );
+        ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password_test_data[i],
+                                         plen_test_data[i], salt_test_data[i],
+                                         slen_test_data[i], it_cnt_test_data[i],
+                                         key_len_test_data[i], key );
         if( ret != 0 ||
-            memcmp( result_key[i], key, key_len[i] ) != 0 )
+            memcmp( result_key_test_data[i], key, key_len_test_data[i] ) != 0 )
         {
             if( verbose != 0 )
                 mbedtls_printf( "failed\n" );
diff --git a/library/ssl_cache.c b/library/ssl_cache.c
index 47867f1..62a0a29 100644
--- a/library/ssl_cache.c
+++ b/library/ssl_cache.c
@@ -40,6 +40,7 @@
 #endif
 
 #include "mbedtls/ssl_cache.h"
+#include "mbedtls/ssl_internal.h"
 
 #include <string.h>
 
@@ -92,16 +93,24 @@
                     entry->session.id_len ) != 0 )
             continue;
 
-        memcpy( session->master, entry->session.master, 48 );
+        ret = mbedtls_ssl_session_copy( session, &entry->session );
+        if( ret != 0 )
+        {
+            ret = 1;
+            goto exit;
+        }
 
-        session->verify_result = entry->session.verify_result;
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
         /*
          * Restore peer certificate (without rest of the original chain)
          */
         if( entry->peer_cert.p != NULL )
         {
+            /* `session->peer_cert` is NULL after the call to
+             * mbedtls_ssl_session_copy(), because cache entries
+             * have the `peer_cert` field set to NULL. */
+
             if( ( session->peer_cert = mbedtls_calloc( 1,
                                  sizeof(mbedtls_x509_crt) ) ) == NULL )
             {
@@ -119,7 +128,7 @@
                 goto exit;
             }
         }
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         ret = 0;
         goto exit;
@@ -239,9 +248,8 @@
 #endif
     }
 
-    memcpy( &cur->session, session, sizeof( mbedtls_ssl_session ) );
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     /*
      * If we're reusing an entry, free its certificate first
      */
@@ -250,26 +258,43 @@
         mbedtls_free( cur->peer_cert.p );
         memset( &cur->peer_cert, 0, sizeof(mbedtls_x509_buf) );
     }
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
-    /*
-     * Store peer certificate
-     */
-    if( session->peer_cert != NULL )
+    /* Copy the entire session; this temporarily makes a copy of the
+     * X.509 CRT structure even though we only want to store the raw CRT.
+     * This inefficiency will go away as soon as we implement on-demand
+     * parsing of CRTs, in which case there's no need for the `peer_cert`
+     * field anymore in the first place, and we're done after this call. */
+    ret = mbedtls_ssl_session_copy( &cur->session, session );
+    if( ret != 0 )
     {
-        cur->peer_cert.p = mbedtls_calloc( 1, session->peer_cert->raw.len );
+        ret = 1;
+        goto exit;
+    }
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* If present, free the X.509 structure and only store the raw CRT data. */
+    if( cur->session.peer_cert != NULL )
+    {
+        cur->peer_cert.p =
+            mbedtls_calloc( 1, cur->session.peer_cert->raw.len );
         if( cur->peer_cert.p == NULL )
         {
             ret = 1;
             goto exit;
         }
 
-        memcpy( cur->peer_cert.p, session->peer_cert->raw.p,
-                session->peer_cert->raw.len );
+        memcpy( cur->peer_cert.p,
+                cur->session.peer_cert->raw.p,
+                cur->session.peer_cert->raw.len );
         cur->peer_cert.len = session->peer_cert->raw.len;
 
+        mbedtls_x509_crt_free( cur->session.peer_cert );
+        mbedtls_free( cur->session.peer_cert );
         cur->session.peer_cert = NULL;
     }
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
     ret = 0;
 
@@ -311,9 +336,10 @@
 
         mbedtls_ssl_session_free( &prv->session );
 
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
         mbedtls_free( prv->peer_cert.p );
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         mbedtls_free( prv );
     }
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 745474e..518f7dd 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -43,11 +43,11 @@
 /*
  * Ordered from most preferred to least preferred in terms of security.
  *
- * Current rule (except rc4, weak and null which come last):
+ * Current rule (except RC4 and 3DES, weak and null which come last):
  * 1. By key exchange:
  *    Forward-secure non-PSK > forward-secure PSK > ECJPAKE > other non-PSK > other PSK
  * 2. By key length and cipher:
- *    ChaCha > AES-256 > Camellia-256 > ARIA-256 > AES-128 > Camellia-128 > ARIA-128 > 3DES
+ *    ChaCha > AES-256 > Camellia-256 > ARIA-256 > AES-128 > Camellia-128 > ARIA-128
  * 3. By cipher mode when relevant GCM > CCM > CBC > CCM_8
  * 4. By hash function used when relevant
  * 5. By key exchange/auth again: EC > non-EC
@@ -126,11 +126,6 @@
     MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
     MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
 
-    /* All remaining >= 128-bit ephemeral suites */
-    MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-
     /* The PSK ephemeral suites */
     MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
     MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
@@ -162,9 +157,6 @@
     MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
     MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
 
-    MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
-
     /* The ECJPAKE suite */
     MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8,
 
@@ -228,11 +220,6 @@
     MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
     MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
 
-    /* All remaining >= 128-bit suites */
-    MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
-
     /* The RSA PSK suites */
     MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
     MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
@@ -251,8 +238,6 @@
     MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
     MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
 
-    MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
-
     /* The PSK suites */
     MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
     MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
@@ -275,6 +260,16 @@
     MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
     MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
 
+    /* 3DES suites */
+    MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
     MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
 
     /* RC4 suites */
@@ -2187,6 +2182,26 @@
 static int supported_ciphersuites[MAX_CIPHERSUITES];
 static int supported_init = 0;
 
+static int ciphersuite_is_removed( const mbedtls_ssl_ciphersuite_t *cs_info )
+{
+    (void)cs_info;
+
+#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
+    if( cs_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+        return( 1 );
+#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
+
+#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
+    if( cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_ECB ||
+        cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_CBC )
+    {
+        return( 1 );
+    }
+#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
+
+    return( 0 );
+}
+
 const int *mbedtls_ssl_list_ciphersuites( void )
 {
     /*
@@ -2202,14 +2217,12 @@
              *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1;
              p++ )
         {
-#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
             const mbedtls_ssl_ciphersuite_t *cs_info;
             if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL &&
-                cs_info->cipher != MBEDTLS_CIPHER_ARC4_128 )
-#else
-            if( mbedtls_ssl_ciphersuite_from_id( *p ) != NULL )
-#endif
+                !ciphersuite_is_removed( cs_info ) )
+            {
                 *(q++) = *p;
+            }
         }
         *q = 0;
 
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 87fa1e0..4e5b3a6 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -2265,6 +2265,7 @@
     int ret;
     size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2;
     unsigned char *p = ssl->handshake->premaster + pms_offset;
+    mbedtls_pk_context * peer_pk;
 
     if( offset + len_bytes > MBEDTLS_SSL_OUT_CONTENT_LEN )
     {
@@ -2290,23 +2291,28 @@
 
     ssl->handshake->pmslen = 48;
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     if( ssl->session_negotiate->peer_cert == NULL )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
-        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+        /* Should never happen */
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
+    peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
     /*
      * Now write it out, encrypted
      */
-    if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
-                MBEDTLS_PK_RSA ) )
+    if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_RSA ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) );
         return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
     }
 
-    if( ( ret = mbedtls_pk_encrypt( &ssl->session_negotiate->peer_cert->pk,
+    if( ( ret = mbedtls_pk_encrypt( peer_pk,
                             p, ssl->handshake->pmslen,
                             ssl->out_msg + offset + len_bytes, olen,
                             MBEDTLS_SSL_OUT_CONTENT_LEN - offset - len_bytes,
@@ -2326,6 +2332,10 @@
     }
 #endif
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* We don't need the peer's public key anymore. Free it. */
+    mbedtls_pk_free( peer_pk );
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     return( 0 );
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED ||
@@ -2401,21 +2411,27 @@
 {
     int ret;
     const mbedtls_ecp_keypair *peer_key;
+    mbedtls_pk_context * peer_pk;
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     if( ssl->session_negotiate->peer_cert == NULL )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
-        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+        /* Should never happen */
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
+    peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
-    if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
-                     MBEDTLS_PK_ECKEY ) )
+    if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) );
         return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
     }
 
-    peer_key = mbedtls_pk_ec( ssl->session_negotiate->peer_cert->pk );
+    peer_key = mbedtls_pk_ec( *peer_pk );
 
     if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, peer_key,
                                  MBEDTLS_ECDH_THEIRS ) ) != 0 )
@@ -2430,6 +2446,13 @@
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* We don't need the peer's public key anymore. Free it,
+     * so that more RAM is available for upcoming expensive
+     * operations like ECDHE. */
+    mbedtls_pk_free( peer_pk );
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
     return( ret );
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
@@ -2640,6 +2663,8 @@
         size_t params_len = p - params;
         void *rs_ctx = NULL;
 
+        mbedtls_pk_context * peer_pk;
+
         /*
          * Handle the digitally-signed structure
          */
@@ -2742,18 +2767,22 @@
 
         MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
         if( ssl->session_negotiate->peer_cert == NULL )
         {
-            MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
-            return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+            /* Should never happen */
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+            return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
         }
+        peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         /*
          * Verify signature
          */
-        if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
+        if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
             mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
@@ -2766,8 +2795,7 @@
             rs_ctx = &ssl->handshake->ecrs_ctx.pk;
 #endif
 
-        if( ( ret = mbedtls_pk_verify_restartable(
-                        &ssl->session_negotiate->peer_cert->pk,
+        if( ( ret = mbedtls_pk_verify_restartable( peer_pk,
                         md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
         {
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
@@ -2782,6 +2810,13 @@
 #endif
             return( ret );
         }
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        /* We don't need the peer's public key anymore. Free it,
+         * so that more RAM is available for upcoming expensive
+         * operations like ECDHE. */
+        mbedtls_pk_free( peer_pk );
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     }
 #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
 
@@ -3456,12 +3491,7 @@
     return( 0 );
 }
 
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)       && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)  && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -3476,11 +3506,7 @@
         return( ret );
     }
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
         ssl->state++;
@@ -3490,7 +3516,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
-#else
+#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -3519,11 +3545,7 @@
         return( ret );
     }
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
         ssl->state++;
@@ -3666,12 +3688,7 @@
 
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl )
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 46e24e4..c969089 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -2680,12 +2680,7 @@
     return( ret );
 }
 
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)       && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)  && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -2693,11 +2688,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
         ssl->state++;
@@ -2707,7 +2698,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
-#else
+#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -2731,11 +2722,7 @@
 #endif
         authmode = ssl->conf->authmode;
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ||
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ||
         authmode == MBEDTLS_SSL_VERIFY_NONE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
@@ -2874,12 +2861,7 @@
 
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
@@ -4048,12 +4030,7 @@
     return( 0 );
 }
 
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)       && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)  && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -4061,11 +4038,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
         ssl->state++;
@@ -4075,7 +4048,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
-#else
+#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -4089,21 +4062,33 @@
     mbedtls_md_type_t md_alg;
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
         ssl->transform_negotiate->ciphersuite_info;
+    mbedtls_pk_context * peer_pk;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ||
-        ssl->session_negotiate->peer_cert == NULL )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
         ssl->state++;
         return( 0 );
     }
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( ssl->session_negotiate->peer_cert == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
+        ssl->state++;
+        return( 0 );
+    }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( ssl->session_negotiate->peer_cert_digest == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
+        ssl->state++;
+        return( 0 );
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
     /* Read the message without adding it to the checksum */
     ret = mbedtls_ssl_read_record( ssl, 0 /* no checksum update */ );
     if( 0 != ret )
@@ -4124,6 +4109,17 @@
 
     i = mbedtls_ssl_hs_hdr_len( ssl );
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( ssl->session_negotiate->peer_cert == NULL )
+    {
+        /* Should never happen */
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+    peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
     /*
      *  struct {
      *     SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only
@@ -4138,8 +4134,7 @@
         hashlen = 36;
 
         /* For ECDSA, use SHA-1, not MD-5 + SHA-1 */
-        if( mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
-                        MBEDTLS_PK_ECDSA ) )
+        if( mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECDSA ) )
         {
             hash_start += 16;
             hashlen -= 16;
@@ -4194,7 +4189,7 @@
         /*
          * Check the certificate's key type matches the signature alg
          */
-        if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
+        if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
@@ -4227,7 +4222,7 @@
     /* Calculate hash and verify signature */
     ssl->handshake->calc_verify( ssl, hash );
 
-    if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk,
+    if( ( ret = mbedtls_pk_verify( peer_pk,
                            md_alg, hash_start, hashlen,
                            ssl->in_msg + i, sig_len ) ) != 0 )
     {
@@ -4241,12 +4236,7 @@
 
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl )
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index 7de4e66..ed65bcd 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -187,9 +187,16 @@
 
 /*
  * Serialize a session in the following format:
- *  0   .   n-1     session structure, n = sizeof(mbedtls_ssl_session)
- *  n   .   n+2     peer_cert length = m (0 if no certificate)
- *  n+3 .   n+2+m   peer cert ASN.1
+ *
+ * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled:
+ *    0       .   n-1   session structure, n = sizeof(mbedtls_ssl_session)
+ *    n       .   n+2   peer_cert length = m (0 if no certificate)
+ *    n+3     .   n+2+m peer cert ASN.1
+ *
+ * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled:
+ *    0       .   n-1   session structure, n = sizeof(mbedtls_ssl_session)
+ *    n       .   n     length of peer certificate digest = k (0 if no digest)
+ *    n+1     .   n+k   peer certificate digest (digest type encoded in session)
  */
 static int ssl_save_session( const mbedtls_ssl_session *session,
                              unsigned char *buf, size_t buf_len,
@@ -198,17 +205,25 @@
     unsigned char *p = buf;
     size_t left = buf_len;
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     size_t cert_len;
+#else
+    size_t cert_digest_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( left < sizeof( mbedtls_ssl_session ) )
         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
 
+    /* This also copies the values of pointer fields in the
+     * session to be serialized, but they'll be ignored when
+     * loading the session through ssl_load_session(). */
     memcpy( p, session, sizeof( mbedtls_ssl_session ) );
     p += sizeof( mbedtls_ssl_session );
     left -= sizeof( mbedtls_ssl_session );
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     if( session->peer_cert == NULL )
         cert_len = 0;
     else
@@ -220,11 +235,31 @@
     *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
     *p++ = (unsigned char)( ( cert_len >>  8 ) & 0xFF );
     *p++ = (unsigned char)( ( cert_len       ) & 0xFF );
+    left -= 3;
 
     if( session->peer_cert != NULL )
         memcpy( p, session->peer_cert->raw.p, cert_len );
 
     p += cert_len;
+    left -= cert_len;
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( session->peer_cert_digest != NULL )
+        cert_digest_len = 0;
+    else
+        cert_digest_len = session->peer_cert_digest_len;
+
+    if( left < 1 + cert_digest_len )
+        return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+    *p++ = (unsigned char) cert_digest_len;
+    left--;
+
+    if( session->peer_cert_digest != NULL )
+        memcpy( p, session->peer_cert_digest, cert_digest_len );
+
+    p    += cert_digest_len;
+    left -= cert_digest_len;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     *olen = p - buf;
@@ -241,7 +276,11 @@
     const unsigned char *p = buf;
     const unsigned char * const end = buf + len;
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     size_t cert_len;
+#else
+    size_t cert_digest_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
@@ -250,18 +289,29 @@
     memcpy( session, p, sizeof( mbedtls_ssl_session ) );
     p += sizeof( mbedtls_ssl_session );
 
+    /* Non-NULL pointer fields of `session` are meaningless
+     * and potentially harmful. Zeroize them for safety. */
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    session->peer_cert = NULL;
+#else
+    session->peer_cert_digest = NULL;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+    session->ticket = NULL;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* Deserialize CRT from the end of the ticket. */
     if( 3 > (size_t)( end - p ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
     cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
     p += 3;
 
-    if( cert_len == 0 )
-    {
-        session->peer_cert = NULL;
-    }
-    else
+    if( cert_len != 0 )
     {
         int ret;
 
@@ -286,6 +336,30 @@
 
         p += cert_len;
     }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /* Deserialize CRT digest from the end of the ticket. */
+    if( 1 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    cert_digest_len = (size_t) p[0];
+    p++;
+
+    if( cert_digest_len != 0 )
+    {
+        if( cert_digest_len > (size_t)( end - p ) ||
+            cert_digest_len != session->peer_cert_digest_len )
+        {
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+        }
+
+        session->peer_cert_digest = mbedtls_calloc( 1, cert_digest_len );
+        if( session->peer_cert_digest == NULL )
+            return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+        memcpy( session->peer_cert_digest, p, cert_digest_len );
+        p += cert_digest_len;
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( p != end )
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 4c23f0e..660d548 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -279,13 +279,15 @@
 }
 #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
 
-#if defined(MBEDTLS_SSL_CLI_C)
-static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src )
+int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
+                              const mbedtls_ssl_session *src )
 {
     mbedtls_ssl_session_free( dst );
     memcpy( dst, src, sizeof( mbedtls_ssl_session ) );
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     if( src->peer_cert != NULL )
     {
         int ret;
@@ -304,6 +306,21 @@
             return( ret );
         }
     }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( src->peer_cert_digest != NULL )
+    {
+        dst->peer_cert_digest =
+            mbedtls_calloc( 1, src->peer_cert_digest_len );
+        if( dst->peer_cert_digest == NULL )
+            return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+        memcpy( dst->peer_cert_digest, src->peer_cert_digest,
+                src->peer_cert_digest_len );
+        dst->peer_cert_digest_type = src->peer_cert_digest_type;
+        dst->peer_cert_digest_len = src->peer_cert_digest_len;
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
@@ -319,7 +336,6 @@
 
     return( 0 );
 }
-#endif /* MBEDTLS_SSL_CLI_C */
 
 #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
 int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl,
@@ -5554,16 +5570,33 @@
     return( 0 );
 }
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+static void ssl_clear_peer_cert( mbedtls_ssl_session *session )
+{
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( session->peer_cert != NULL )
+    {
+        mbedtls_x509_crt_free( session->peer_cert );
+        mbedtls_free( session->peer_cert );
+        session->peer_cert = NULL;
+    }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( session->peer_cert_digest != NULL )
+    {
+        /* Zeroization is not necessary. */
+        mbedtls_free( session->peer_cert_digest );
+        session->peer_cert_digest      = NULL;
+        session->peer_cert_digest_type = MBEDTLS_MD_NONE;
+        session->peer_cert_digest_len  = 0;
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+}
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
 /*
  * Handshake functions
  */
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)         && \
-    !defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)     && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)     && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)    && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
 /* No certificate support -> dummy functions */
 int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
 {
@@ -5571,10 +5604,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
         ssl->state++;
@@ -5591,10 +5621,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
         ssl->state++;
@@ -5605,7 +5632,7 @@
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
 
-#else
+#else /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 /* Some certificate support -> implement write and parse */
 
 int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
@@ -5617,10 +5644,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
         ssl->state++;
@@ -5725,6 +5749,8 @@
 }
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
 static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
                                          unsigned char *crt_buf,
                                          size_t crt_buf_len )
@@ -5739,65 +5765,51 @@
 
     return( memcmp( peer_crt->raw.p, crt_buf, crt_buf_len ) );
 }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
+                                         unsigned char *crt_buf,
+                                         size_t crt_buf_len )
+{
+    int ret;
+    unsigned char const * const peer_cert_digest =
+        ssl->session->peer_cert_digest;
+    mbedtls_md_type_t const peer_cert_digest_type =
+        ssl->session->peer_cert_digest_type;
+    mbedtls_md_info_t const * const digest_info =
+        mbedtls_md_info_from_type( peer_cert_digest_type );
+    unsigned char tmp_digest[MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN];
+    size_t digest_len;
+
+    if( peer_cert_digest == NULL || digest_info == NULL )
+        return( -1 );
+
+    digest_len = mbedtls_md_get_size( digest_info );
+    if( digest_len > MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN )
+        return( -1 );
+
+    ret = mbedtls_md( digest_info, crt_buf, crt_buf_len, tmp_digest );
+    if( ret != 0 )
+        return( -1 );
+
+    return( memcmp( tmp_digest, peer_cert_digest, digest_len ) );
+}
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #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
  */
-static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
+static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl,
+                                        mbedtls_x509_crt *chain )
 {
     int ret;
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+    int crt_cnt=0;
+#endif
     size_t i, n;
     uint8_t alert;
 
-#if defined(MBEDTLS_SSL_SRV_C)
-#if defined(MBEDTLS_SSL_PROTO_SSL3)
-    /*
-     * Check if the client sent an empty certificate
-     */
-    if( ssl->conf->endpoint  == MBEDTLS_SSL_IS_SERVER &&
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
-    {
-        if( ssl->in_msglen  == 2                        &&
-            ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT            &&
-            ssl->in_msg[0]  == MBEDTLS_SSL_ALERT_LEVEL_WARNING  &&
-            ssl->in_msg[1]  == MBEDTLS_SSL_ALERT_MSG_NO_CERT )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) );
-
-            /* The client was asked for a certificate but didn't send
-               one. The client should know what's going on, so we
-               don't send an alert. */
-            ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
-            return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
-        }
-    }
-#endif /* MBEDTLS_SSL_PROTO_SSL3 */
-
-#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
-    defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if( ssl->conf->endpoint  == MBEDTLS_SSL_IS_SERVER &&
-        ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 )
-    {
-        if( ssl->in_hslen   == 3 + mbedtls_ssl_hs_hdr_len( ssl ) &&
-            ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE    &&
-            ssl->in_msg[0]  == MBEDTLS_SSL_HS_CERTIFICATE   &&
-            memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
-
-            /* The client was asked for a certificate but didn't send
-               one. The client should know what's going on, so we
-               don't send an alert. */
-            ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
-            return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
-        }
-    }
-#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
-          MBEDTLS_SSL_PROTO_TLS1_2 */
-#endif /* MBEDTLS_SSL_SRV_C */
-
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
@@ -5834,14 +5846,6 @@
     /* 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;
-    }
-
     /* Iterate through and parse the CRTs in the provided chain. */
     while( i < ssl->in_hslen )
     {
@@ -5879,66 +5883,40 @@
         }
 
         /* Check if we're handling the first CRT in the chain. */
-        if( ssl->session_negotiate->peer_cert == NULL )
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+        if( crt_cnt++ == 0 &&
+            ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
+            ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
         {
             /* 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( 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;
+                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 );
             }
+
+            /* Now we can safely free the original chain. */
+            ssl_clear_peer_cert( ssl->session );
+        }
 #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 );
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        ret = mbedtls_x509_crt_parse_der( chain, ssl->in_msg + i, n );
+#else
+        /* If we don't need to store the CRT chain permanently, parse
+         * it in-place from the input buffer instead of making a copy. */
+        ret = mbedtls_x509_crt_parse_der_nocopy( chain, ssl->in_msg + i, n );
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
         switch( ret )
         {
             case 0: /*ok*/
@@ -5966,15 +5944,291 @@
         i += n;
     }
 
-    MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert );
+    MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", chain );
     return( 0 );
 }
 
-int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
+#if defined(MBEDTLS_SSL_SRV_C)
+static int ssl_srv_check_client_no_crt_notification( mbedtls_ssl_context *ssl )
+{
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
+        return( -1 );
+
+#if defined(MBEDTLS_SSL_PROTO_SSL3)
+    /*
+     * Check if the client sent an empty certificate
+     */
+    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+    {
+        if( ssl->in_msglen  == 2                        &&
+            ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT            &&
+            ssl->in_msg[0]  == MBEDTLS_SSL_ALERT_LEVEL_WARNING  &&
+            ssl->in_msg[1]  == MBEDTLS_SSL_ALERT_MSG_NO_CERT )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) );
+            return( 0 );
+        }
+
+        return( -1 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_SSL3 */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
+    defined(MBEDTLS_SSL_PROTO_TLS1_2)
+    if( ssl->in_hslen   == 3 + mbedtls_ssl_hs_hdr_len( ssl ) &&
+        ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE    &&
+        ssl->in_msg[0]  == MBEDTLS_SSL_HS_CERTIFICATE   &&
+        memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
+        return( 0 );
+    }
+
+    return( -1 );
+#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
+          MBEDTLS_SSL_PROTO_TLS1_2 */
+}
+#endif /* MBEDTLS_SSL_SRV_C */
+
+/* Check if a certificate message is expected.
+ * Return either
+ * - SSL_CERTIFICATE_EXPECTED, or
+ * - SSL_CERTIFICATE_SKIP
+ * indicating whether a Certificate message is expected or not.
+ */
+#define SSL_CERTIFICATE_EXPECTED 0
+#define SSL_CERTIFICATE_SKIP     1
+static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl,
+                                             int authmode )
+{
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+        ssl->transform_negotiate->ciphersuite_info;
+
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
+        return( SSL_CERTIFICATE_SKIP );
+
+#if defined(MBEDTLS_SSL_SRV_C)
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
+    {
+        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+            return( SSL_CERTIFICATE_SKIP );
+
+        if( authmode == MBEDTLS_SSL_VERIFY_NONE )
+        {
+            ssl->session_negotiate->verify_result =
+                MBEDTLS_X509_BADCERT_SKIP_VERIFY;
+            return( SSL_CERTIFICATE_SKIP );
+        }
+    }
+#else
+    ((void) authmode);
+#endif /* MBEDTLS_SSL_SRV_C */
+
+    return( SSL_CERTIFICATE_EXPECTED );
+}
+
+static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
+                                         int authmode,
+                                         mbedtls_x509_crt *chain,
+                                         void *rs_ctx )
+{
+    int ret = 0;
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+        ssl->transform_negotiate->ciphersuite_info;
+    mbedtls_x509_crt *ca_chain;
+    mbedtls_x509_crl *ca_crl;
+
+    if( authmode == MBEDTLS_SSL_VERIFY_NONE )
+        return( 0 );
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+    if( ssl->handshake->sni_ca_chain != NULL )
+    {
+        ca_chain = ssl->handshake->sni_ca_chain;
+        ca_crl   = ssl->handshake->sni_ca_crl;
+    }
+    else
+#endif
+    {
+        ca_chain = ssl->conf->ca_chain;
+        ca_crl   = ssl->conf->ca_crl;
+    }
+
+    /*
+     * Main check: verify certificate
+     */
+    ret = mbedtls_x509_crt_verify_restartable(
+        chain,
+        ca_chain, ca_crl,
+        ssl->conf->cert_profile,
+        ssl->hostname,
+        &ssl->session_negotiate->verify_result,
+        ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
+
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
+    }
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+        return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
+#endif
+
+    /*
+     * Secondary checks: always done, but change 'ret' only if it was 0
+     */
+
+#if defined(MBEDTLS_ECP_C)
+    {
+        const mbedtls_pk_context *pk = &chain->pk;
+
+        /* If certificate uses an EC key, make sure the curve is OK */
+        if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
+            mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
+        {
+            ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
+
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
+            if( ret == 0 )
+                ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
+        }
+    }
+#endif /* MBEDTLS_ECP_C */
+
+    if( mbedtls_ssl_check_cert_usage( chain,
+                                      ciphersuite_info,
+                                      ! ssl->conf->endpoint,
+                                      &ssl->session_negotiate->verify_result ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) );
+        if( ret == 0 )
+            ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
+    }
+
+    /* mbedtls_x509_crt_verify_with_profile is supposed to report a
+     * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED,
+     * with details encoded in the verification flags. All other kinds
+     * of error codes, including those from the user provided f_vrfy
+     * functions, are treated as fatal and lead to a failure of
+     * ssl_parse_certificate even if verification was optional. */
+    if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL &&
+        ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
+          ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
+    {
+        ret = 0;
+    }
+
+    if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
+        ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
+    }
+
+    if( ret != 0 )
+    {
+        uint8_t alert;
+
+        /* The certificate may have been rejected for several reasons.
+           Pick one and send the corresponding alert. Which alert to send
+           may be a subject of debate in some cases. */
+        if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER )
+            alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH )
+            alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED )
+            alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED )
+            alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
+        else
+            alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
+        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                        alert );
+    }
+
+#if defined(MBEDTLS_DEBUG_C)
+    if( ssl->session_negotiate->verify_result != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x",
+                                    ssl->session_negotiate->verify_result ) );
+    }
+    else
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
+    }
+#endif /* MBEDTLS_DEBUG_C */
+
+    return( ret );
+}
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+static int ssl_remember_peer_crt_digest( mbedtls_ssl_context *ssl,
+                                         unsigned char *start, size_t len )
 {
     int ret;
-    const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
-          ssl->transform_negotiate->ciphersuite_info;
+    /* Remember digest of the peer's end-CRT. */
+    ssl->session_negotiate->peer_cert_digest =
+        mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN );
+    if( ssl->session_negotiate->peer_cert_digest == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
+                                    sizeof( MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) ) );
+        mbedtls_ssl_send_alert_message( ssl,
+                                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+
+        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+    }
+
+    ret = mbedtls_md( mbedtls_md_info_from_type(
+                          MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
+                      start, len,
+                      ssl->session_negotiate->peer_cert_digest );
+
+    ssl->session_negotiate->peer_cert_digest_type =
+        MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE;
+    ssl->session_negotiate->peer_cert_digest_len =
+        MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN;
+
+    return( ret );
+}
+
+static int ssl_remember_peer_pubkey( mbedtls_ssl_context *ssl,
+                                     unsigned char *start, size_t len )
+{
+    unsigned char *end = start + len;
+    int ret;
+
+    /* Make a copy of the peer's raw public key. */
+    mbedtls_pk_init( &ssl->handshake->peer_pubkey );
+    ret = mbedtls_pk_parse_subpubkey( &start, end,
+                                      &ssl->handshake->peer_pubkey );
+    if( ret != 0 )
+    {
+        /* We should have parsed the public key before. */
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+
+    return( 0 );
+}
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
+int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
+{
+    int ret = 0;
+    int crt_expected;
 #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
     const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET
                        ? ssl->handshake->sni_authmode
@@ -5983,43 +6237,23 @@
     const int authmode = ssl->conf->authmode;
 #endif
     void *rs_ctx = NULL;
+    mbedtls_x509_crt *chain = NULL;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    crt_expected = ssl_parse_certificate_coordinate( ssl, authmode );
+    if( crt_expected == SSL_CERTIFICATE_SKIP )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
+        goto exit;
     }
 
-#if defined(MBEDTLS_SSL_SRV_C)
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
-    }
-
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
-        authmode == MBEDTLS_SSL_VERIFY_NONE )
-    {
-        ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-
-        ssl->state++;
-        return( 0 );
-    }
-#endif
-
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
     if( ssl->handshake->ecrs_enabled &&
         ssl->handshake->ecrs_state == ssl_ecrs_crt_verify )
     {
+        chain = ssl->handshake->ecrs_peer_cert;
+        ssl->handshake->ecrs_peer_cert = NULL;
         goto crt_verify;
     }
 #endif
@@ -6029,22 +6263,44 @@
         /* mbedtls_ssl_read_record may have sent an alert already. We
            let it decide whether to alert. */
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
-        return( ret );
+        goto exit;
     }
 
-    if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 )
-    {
 #if defined(MBEDTLS_SSL_SRV_C)
-        if( ret == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE &&
-            authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
-        {
-            ret = 0;
-        }
-#endif
+    if( ssl_srv_check_client_no_crt_notification( ssl ) == 0 )
+    {
+        ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
 
-        ssl->state++;
-        return( ret );
+        if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
+            ret = 0;
+        else
+            ret = MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE;
+
+        goto exit;
     }
+#endif /* MBEDTLS_SSL_SRV_C */
+
+    /* Clear existing peer CRT structure in case we tried to
+     * reuse a session but it failed, and allocate a new one. */
+    ssl_clear_peer_cert( ssl->session_negotiate );
+
+    chain = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
+    if( chain == 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 );
+
+        ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        goto exit;
+    }
+    mbedtls_x509_crt_init( chain );
+
+    ret = ssl_parse_certificate_chain( ssl, chain );
+    if( ret != 0 )
+        goto exit;
 
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
     if( ssl->handshake->ecrs_enabled)
@@ -6055,154 +6311,71 @@
         rs_ctx = &ssl->handshake->ecrs_ctx;
 #endif
 
-    if( authmode != MBEDTLS_SSL_VERIFY_NONE )
+    ret = ssl_parse_certificate_verify( ssl, authmode,
+                                        chain, rs_ctx );
+    if( ret != 0 )
+        goto exit;
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     {
-        mbedtls_x509_crt *ca_chain;
-        mbedtls_x509_crl *ca_crl;
+        unsigned char *crt_start, *pk_start;
+        size_t crt_len, pk_len;
 
-#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-        if( ssl->handshake->sni_ca_chain != NULL )
-        {
-            ca_chain = ssl->handshake->sni_ca_chain;
-            ca_crl   = ssl->handshake->sni_ca_crl;
-        }
-        else
-#endif
-        {
-            ca_chain = ssl->conf->ca_chain;
-            ca_crl   = ssl->conf->ca_crl;
-        }
+        /* We parse the CRT chain without copying, so
+         * these pointers point into the input buffer,
+         * and are hence still valid after freeing the
+         * CRT chain. */
 
-        /*
-         * Main check: verify certificate
-         */
-        ret = mbedtls_x509_crt_verify_restartable(
-                                ssl->session_negotiate->peer_cert,
-                                ca_chain, ca_crl,
-                                ssl->conf->cert_profile,
-                                ssl->hostname,
-                               &ssl->session_negotiate->verify_result,
-                                ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
+        crt_start = chain->raw.p;
+        crt_len   = chain->raw.len;
 
+        pk_start = chain->pk_raw.p;
+        pk_len   = chain->pk_raw.len;
+
+        /* Free the CRT structures before computing
+         * digest and copying the peer's public key. */
+        mbedtls_x509_crt_free( chain );
+        mbedtls_free( chain );
+        chain = NULL;
+
+        ret = ssl_remember_peer_crt_digest( ssl, crt_start, crt_len );
         if( ret != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
-        }
+            goto exit;
 
-#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
-        if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
-            return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
-#endif
-
-        /*
-         * Secondary checks: always done, but change 'ret' only if it was 0
-         */
-
-#if defined(MBEDTLS_ECP_C)
-        {
-            const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->pk;
-
-            /* If certificate uses an EC key, make sure the curve is OK */
-            if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
-                mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
-            {
-                ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
-
-                MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
-                if( ret == 0 )
-                    ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
-            }
-        }
-#endif /* MBEDTLS_ECP_C */
-
-        if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert,
-                                 ciphersuite_info,
-                                 ! ssl->conf->endpoint,
-                                 &ssl->session_negotiate->verify_result ) != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) );
-            if( ret == 0 )
-                ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
-        }
-
-        /* mbedtls_x509_crt_verify_with_profile is supposed to report a
-         * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED,
-         * with details encoded in the verification flags. All other kinds
-         * of error codes, including those from the user provided f_vrfy
-         * functions, are treated as fatal and lead to a failure of
-         * ssl_parse_certificate even if verification was optional. */
-        if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL &&
-            ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
-              ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
-        {
-            ret = 0;
-        }
-
-        if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
-            ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
-        }
-
+        ret = ssl_remember_peer_pubkey( ssl, pk_start, pk_len );
         if( ret != 0 )
-        {
-            uint8_t alert;
-
-            /* The certificate may have been rejected for several reasons.
-               Pick one and send the corresponding alert. Which alert to send
-               may be a subject of debate in some cases. */
-            if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER )
-                alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH )
-                alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED )
-                alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED )
-                alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
-            else
-                alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            alert );
-        }
-
-#if defined(MBEDTLS_DEBUG_C)
-        if( ssl->session_negotiate->verify_result != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x",
-                                        ssl->session_negotiate->verify_result ) );
-        }
-        else
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
-        }
-#endif /* MBEDTLS_DEBUG_C */
+            goto exit;
     }
-
-    ssl->state++;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /* Pass ownership to session structure. */
+    ssl->session_negotiate->peer_cert = chain;
+    chain = NULL;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
 
+exit:
+
+    if( ret == 0 )
+        ssl->state++;
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
+    {
+        ssl->handshake->ecrs_peer_cert = chain;
+        chain = NULL;
+    }
+#endif
+
+    if( chain != NULL )
+    {
+        mbedtls_x509_crt_free( chain );
+        mbedtls_free( chain );
+    }
+
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 
 int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl )
 {
@@ -7065,6 +7238,11 @@
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
     handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET;
 #endif
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_pk_init( &handshake->peer_pubkey );
+#endif
 }
 
 static void ssl_transform_init( mbedtls_ssl_transform *transform )
@@ -7614,7 +7792,8 @@
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    if( ( ret = ssl_session_copy( ssl->session_negotiate, session ) ) != 0 )
+    if( ( ret = mbedtls_ssl_session_copy( ssl->session_negotiate,
+                                          session ) ) != 0 )
         return( ret );
 
     ssl->handshake->resume = 1;
@@ -8533,12 +8712,17 @@
     if( ssl == NULL || ssl->session == NULL )
         return( NULL );
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     return( ssl->session->peer_cert );
+#else
+    return( NULL );
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_CLI_C)
-int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *dst )
+int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl,
+                             mbedtls_ssl_session *dst )
 {
     if( ssl == NULL ||
         dst == NULL ||
@@ -8548,7 +8732,7 @@
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    return( ssl_session_copy( dst, ssl->session ) );
+    return( mbedtls_ssl_session_copy( dst, ssl->session ) );
 }
 #endif /* MBEDTLS_SSL_CLI_C */
 
@@ -9402,8 +9586,18 @@
 
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
     mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx );
+    if( handshake->ecrs_peer_cert != NULL )
+    {
+        mbedtls_x509_crt_free( handshake->ecrs_peer_cert );
+        mbedtls_free( handshake->ecrs_peer_cert );
+    }
 #endif
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C) &&        \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_pk_free( &handshake->peer_pubkey );
+#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     mbedtls_free( handshake->verify_cookie );
     ssl_flight_free( handshake->flight );
@@ -9425,11 +9619,7 @@
         return;
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
-    if( session->peer_cert != NULL )
-    {
-        mbedtls_x509_crt_free( session->peer_cert );
-        mbedtls_free( session->peer_cert );
-    }
+    ssl_clear_peer_cert( session );
 #endif
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
diff --git a/library/version_features.c b/library/version_features.c
index 2bfecf0..f01eace 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -303,6 +303,9 @@
 #if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
     "MBEDTLS_REMOVE_ARC4_CIPHERSUITES",
 #endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
+#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
+    "MBEDTLS_REMOVE_3DES_CIPHERSUITES",
+#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
 #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
     "MBEDTLS_ECP_DP_SECP192R1_ENABLED",
 #endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
@@ -462,6 +465,9 @@
 #if defined(MBEDTLS_SSL_FALLBACK_SCSV)
     "MBEDTLS_SSL_FALLBACK_SCSV",
 #endif /* MBEDTLS_SSL_FALLBACK_SCSV */
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE",
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
     "MBEDTLS_SSL_HW_RECORD_ACCEL",
 #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index e3f169f..5d82816 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -996,11 +996,13 @@
     /*
      * SubjectPublicKeyInfo
      */
+    crt->pk_raw.p = p;
     if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 )
     {
         mbedtls_x509_crt_free( crt );
         return( ret );
     }
+    crt->pk_raw.len = p - crt->pk_raw.p;
 
     /*
      *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index 500e258..b81530c 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -189,7 +189,7 @@
             return( ret );
 
         len = ret;
-        c = output_buf + sizeof(output_buf) - len - 1;
+        c = output_buf + sizeof(output_buf) - len;
     }
 
     if( ( f = fopen( output_file, "w" ) ) == NULL )
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index 828d75d..345d1ec 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -850,6 +850,14 @@
     }
 #endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
 
+#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
+    if( strcmp( "MBEDTLS_REMOVE_3DES_CIPHERSUITES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_REMOVE_3DES_CIPHERSUITES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
+
 #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
     if( strcmp( "MBEDTLS_ECP_DP_SECP192R1_ENABLED", config ) == 0 )
     {
@@ -1274,6 +1282,14 @@
     }
 #endif /* MBEDTLS_SSL_FALLBACK_SCSV */
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( strcmp( "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_KEEP_PEER_CERTIFICATE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
     if( strcmp( "MBEDTLS_SSL_HW_RECORD_ACCEL", config ) == 0 )
     {
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index c2a8d42..f7e2459 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -478,6 +478,8 @@
 }
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+static unsigned char peer_crt_info[1024];
+
 /*
  * Enabled if debug_level > 1 in code below
  */
@@ -487,8 +489,14 @@
     char buf[1024];
     ((void) data);
 
-    mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
     mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
+    if( depth == 0 )
+        memcpy( peer_crt_info, buf, sizeof( buf ) );
+
+    if( opt.debug_level == 0 )
+        return( 0 );
+
+    mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
     mbedtls_printf( "%s", buf );
 
     if ( ( *flags ) == 0 )
@@ -1503,8 +1511,8 @@
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
     }
 
-    if( opt.debug_level > 0 )
-        mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
+    mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
+    memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( opt.auth_mode != DFL_AUTH_MODE )
@@ -1833,13 +1841,8 @@
     else
         mbedtls_printf( " ok\n" );
 
-    if( mbedtls_ssl_get_peer_cert( &ssl ) != NULL )
-    {
-        mbedtls_printf( "  . Peer certificate information    ...\n" );
-        mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
-                       mbedtls_ssl_get_peer_cert( &ssl ) );
-        mbedtls_printf( "%s\n", buf );
-    }
+    mbedtls_printf( "  . Peer certificate information    ...\n" );
+    mbedtls_printf( "%s\n", peer_crt_info );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
@@ -2144,6 +2147,10 @@
         mbedtls_printf( "  . Restarting connection from same port..." );
         fflush( stdout );
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+        memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
         if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned -0x%x\n\n",
@@ -2215,6 +2222,10 @@
 
         mbedtls_printf( "  . Reconnecting with saved session..." );
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+        memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
         if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned -0x%x\n\n",
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index 626c4d1..38fbd51 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -467,9 +467,12 @@
         /*
          * 5. Print the certificate
          */
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        mbedtls_printf( "  . Peer certificate information    ... skipped\n" );
+#else
         mbedtls_printf( "  . Peer certificate information    ...\n" );
         ret = mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
-                             ssl.session->peer_cert );
+                                     mbedtls_ssl_get_peer_cert( &ssl ) );
         if( ret == -1 )
         {
             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_info returned %d\n\n", ret );
@@ -477,6 +480,7 @@
         }
 
         mbedtls_printf( "%s\n", buf );
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         mbedtls_ssl_close_notify( &ssl );
 
diff --git a/scripts/config.pl b/scripts/config.pl
index e141b41..624deca 100755
--- a/scripts/config.pl
+++ b/scripts/config.pl
@@ -29,6 +29,7 @@
 #   MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
 #   MBEDTLS_NO_PLATFORM_ENTROPY
 #   MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+#   MBEDTLS_REMOVE_3DES_CIPHERSUITES
 #   MBEDTLS_SSL_HW_RECORD_ACCEL
 #   MBEDTLS_RSA_NO_CRT
 #   MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
@@ -91,6 +92,7 @@
 MBEDTLS_NO_PLATFORM_ENTROPY
 MBEDTLS_RSA_NO_CRT
 MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+MBEDTLS_REMOVE_3DES_CIPHERSUITES
 MBEDTLS_SSL_HW_RECORD_ACCEL
 MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
 MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 0967341..4b46e3d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -20,6 +20,13 @@
 # on non-POSIX platforms.
 add_definitions("-D_POSIX_C_SOURCE=200809L")
 
+# Test suites caught by SKIP_TEST_SUITES are built but not executed.
+# "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
+# but not "test_suite_foobar".
+string(REGEX REPLACE "[ ,;]" "|" SKIP_TEST_SUITES_REGEX "${SKIP_TEST_SUITES}")
+string(REPLACE "." "\\." SKIP_TEST_SUITES_REGEX "${SKIP_TEST_SUITES_REGEX}")
+set(SKIP_TEST_SUITES_REGEX "^(${SKIP_TEST_SUITES_REGEX})(\$|\\.)")
+
 function(add_test_suite suite_name)
     if(ARGV1)
         set(data_name ${ARGV1})
@@ -36,7 +43,11 @@
     include_directories(${CMAKE_CURRENT_SOURCE_DIR})
     add_executable(test_suite_${data_name} test_suite_${data_name}.c)
     target_link_libraries(test_suite_${data_name} ${libs})
-    add_test(${data_name}-suite test_suite_${data_name} --verbose)
+    if(${data_name} MATCHES ${SKIP_TEST_SUITES_REGEX})
+        message(STATUS "The test suite ${data_name} will not be executed.")
+    else()
+        add_test(${data_name}-suite test_suite_${data_name} --verbose)
+    endif()
 endfunction(add_test_suite)
 
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
@@ -52,6 +63,7 @@
 add_test_suite(aes aes.ecb)
 add_test_suite(aes aes.cbc)
 add_test_suite(aes aes.cfb)
+add_test_suite(aes aes.ofb)
 add_test_suite(aes aes.rest)
 add_test_suite(aes aes.xts)
 add_test_suite(arc4)
diff --git a/tests/Makefile b/tests/Makefile
index f5cafe5..1512fa7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -115,8 +115,9 @@
 endif
 endif
 
+# Test suites caught by SKIP_TEST_SUITES are built but not executed.
 check: $(BINARIES)
-	perl scripts/run-test-suites.pl
+	perl scripts/run-test-suites.pl --skip=$(SKIP_TEST_SUITES)
 
 test: check
 
diff --git a/tests/compat.sh b/tests/compat.sh
index 1814528..0eae1ea 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -62,7 +62,8 @@
 #   avoid plain DES but keep 3DES-EDE-CBC (mbedTLS), DES-CBC3 (OpenSSL)
 # - ARIA: not in default config.h + requires OpenSSL >= 1.1.1
 # - ChachaPoly: requires OpenSSL >= 1.1.0
-EXCLUDE='NULL\|DES-CBC-\|RC4\|ARCFOUR\|ARIA\|CHACHA20-POLY1305'
+# - 3DES: not in default config
+EXCLUDE='NULL\|DES\|RC4\|ARCFOUR\|ARIA\|CHACHA20-POLY1305'
 VERBOSE=""
 MEMCHECK=0
 PEERS="OpenSSL$PEER_GNUTLS mbedTLS"
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 9b5623a..0f3d3ec 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -723,8 +723,8 @@
     msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s
     if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private'
 
-    msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
-    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
+    msg "test: compat.sh RC4, DES, 3DES & NULL (full config)" # ~ 2 min
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '^$' -f 'NULL\|DES\|RC4\|ARCFOUR'
 
     msg "test: compat.sh ARIA + ChachaPoly"
     if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
@@ -903,6 +903,22 @@
     if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
 }
 
+component_test_asan_remove_peer_certificate () {
+    msg "build: default config with MBEDTLS_SSL_KEEP_PEER_CERTIFICATE disabled (ASan build)"
+    scripts/config.pl unset MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
+    make test
+
+    msg "test: ssl-opt.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
+    if_build_succeeded tests/ssl-opt.sh
+
+    msg "test: compat.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
+    if_build_succeeded tests/compat.sh
+}
+
 component_test_no_max_fragment_length_small_ssl_out_content_len () {
     msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
     scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
@@ -1019,6 +1035,16 @@
     esac
 }
 
+component_test_min_mpi_window_size () {
+    msg "build: Default + MBEDTLS_MPI_WINDOW_SIZE=1 (ASan build)" # ~ 10s
+    scripts/config.pl set MBEDTLS_MPI_WINDOW_SIZE 1
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: MBEDTLS_MPI_WINDOW_SIZE=1 - main suites (inc. selftests) (ASan build)" # ~ 10s
+    make test
+}
+
 component_test_have_int32 () {
     msg "build: gcc, force 32-bit bignum limbs"
     scripts/config.pl unset MBEDTLS_HAVE_ASM
diff --git a/tests/scripts/basic-build-test.sh b/tests/scripts/basic-build-test.sh
index 28fc687..ab95e22 100755
--- a/tests/scripts/basic-build-test.sh
+++ b/tests/scripts/basic-build-test.sh
@@ -91,7 +91,7 @@
 OPENSSL_CMD="$OPENSSL_LEGACY"                                       \
     GNUTLS_CLI="$GNUTLS_LEGACY_CLI"                                 \
     GNUTLS_SERV="$GNUTLS_LEGACY_SERV"                               \
-    sh compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR' | \
+    sh compat.sh -e '^$' -f 'NULL\|DES\|RC4\|ARCFOUR' |             \
     tee -a compat-test-$TEST_OUTPUT
 OPENSSL_CMD="$OPENSSL_NEXT"                     \
     sh compat.sh -e '^$' -f 'ARIA\|CHACHA' |    \
diff --git a/tests/scripts/run-test-suites.pl b/tests/scripts/run-test-suites.pl
index d0d4046..1c9dc1d 100755
--- a/tests/scripts/run-test-suites.pl
+++ b/tests/scripts/run-test-suites.pl
@@ -4,19 +4,24 @@
 #
 # This file is part of mbed TLS (https://tls.mbed.org)
 #
-# Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
-#
-# Purpose
-#
-# Executes all the available test suites, and provides a basic summary of the
-# results.
-#
-# Usage: run-test-suites.pl [-v]
-#
-# Options :
-#   -v|--verbose    - Provide a pass/fail/skip breakdown per test suite and
-#                     in total
-#
+# Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
+
+=head1 SYNOPSIS
+
+Execute all the test suites and print a summary of the results.
+
+ run-test-suites.pl [[-v|--verbose] [VERBOSITY]] [--skip=SUITE[...]]
+
+Options:
+
+  -v|--verbose        Print detailed failure information.
+  -v 2|--verbose=2    Print detailed failure information and summary messages.
+  -v 3|--verbose=3    Print detailed information about every test case.
+  --skip=SUITE[,SUITE...]
+                      Skip the specified SUITE(s). This option can be used
+                      multiple times.
+
+=cut
 
 use warnings;
 use strict;
@@ -24,10 +29,15 @@
 use utf8;
 use open qw(:std utf8);
 
-use Getopt::Long;
+use Getopt::Long qw(:config auto_help gnu_compat);
+use Pod::Usage;
 
 my $verbose = 0;
-GetOptions( "verbose|v:1" => \$verbose );
+my @skip_patterns = ();
+GetOptions(
+           'skip=s' => \@skip_patterns,
+           'verbose|v:1' => \$verbose,
+          ) or die;
 
 # All test suites = executable files, excluding source files, debug
 # and profiling information, etc. We can't just grep {! /\./} because
@@ -36,6 +46,17 @@
 @suites = grep { !/\.c$/ && !/\.data$/ && -f } @suites;
 die "$0: no test suite found\n" unless @suites;
 
+# "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
+# but not "test_suite_foobar".
+my $skip_re =
+    ( '\Atest_suite_(' .
+      join('|', map {
+          s/[ ,;]/|/g; # allow any of " ,;|" as separators
+          s/\./\./g; # "." in the input means ".", not "any character"
+          $_
+      } @skip_patterns) .
+      ')(\z|\.)' );
+
 # in case test suites are linked dynamically
 $ENV{'LD_LIBRARY_PATH'} = '../library';
 $ENV{'DYLD_LIBRARY_PATH'} = '../library';
@@ -45,6 +66,7 @@
 my ($failed_suites, $total_tests_run, $failed, $suite_cases_passed,
     $suite_cases_failed, $suite_cases_skipped, $total_cases_passed,
     $total_cases_failed, $total_cases_skipped );
+my $suites_skipped = 0;
 
 sub pad_print_center {
     my( $width, $padchar, $string ) = @_;
@@ -55,6 +77,12 @@
 for my $suite (@suites)
 {
     print "$suite ", "." x ( 72 - length($suite) - 2 - 4 ), " ";
+    if( $suite =~ /$skip_re/o ) {
+        print "SKIP\n";
+        ++$suites_skipped;
+        next;
+    }
+
     my $command = "$prefix$suite";
     if( $verbose ) {
         $command .= ' -v';
@@ -101,7 +129,10 @@
 
 print "-" x 72, "\n";
 print $failed_suites ? "FAILED" : "PASSED";
-printf " (%d suites, %d tests run)\n", scalar @suites, $total_tests_run;
+printf( " (%d suites, %d tests run%s)\n",
+        scalar(@suites) - $suites_skipped,
+        $total_tests_run,
+        $suites_skipped ? ", $suites_skipped suites skipped" : "" );
 
 if( $verbose > 1 ) {
     print "  test cases passed :", $total_cases_passed, "\n";
@@ -111,8 +142,11 @@
             "\n";
     print " of available tests :",
             ( $total_cases_passed + $total_cases_failed + $total_cases_skipped ),
-            "\n"
+            "\n";
+    if( $suites_skipped != 0 ) {
+        print "Note: $suites_skipped suites were skipped.\n";
     }
+}
 
 exit( $failed_suites ? 1 : 0 );
 
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index ff05f64..d952f33 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -4341,26 +4341,37 @@
 # Tests for ciphersuites per version
 
 requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: SSL3" \
-            "$P_SRV min_version=ssl3 version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV min_version=ssl3 version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=ssl3" \
             0 \
-            -c "Ciphersuite is TLS-RSA-WITH-3DES-EDE-CBC-SHA"
+            -c "Ciphersuite is TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: TLS 1.0" \
-            "$P_SRV arc4=1 version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=tls1 arc4=1" \
             0 \
             -c "Ciphersuite is TLS-RSA-WITH-AES-256-CBC-SHA"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: TLS 1.1" \
-            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=tls1_1" \
             0 \
             -c "Ciphersuite is TLS-RSA-WITH-AES-128-CBC-SHA"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: TLS 1.2" \
-            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=tls1_2" \
             0 \
             -c "Ciphersuite is TLS-RSA-WITH-AES-128-GCM-SHA256"
@@ -4369,7 +4380,7 @@
 
 requires_gnutls
 run_test    "ClientHello without extensions, SHA-1 allowed" \
-            "$P_SRV debug_level=3" \
+            "$P_SRV debug_level=3 key_file=data_files/server2.key crt_file=data_files/server2.crt" \
             "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \
             0 \
             -s "dumping 'client hello extensions' (0 bytes)"
@@ -7061,13 +7072,7 @@
             -c "fragmenting handshake message" \
             -C "error"
 
-## The two tests below are disabled due to a bug in GnuTLS client that causes
-## handshake failures when the NewSessionTicket message is lost, see
-## https://gitlab.com/gnutls/gnutls/issues/543
-## We can re-enable them when a fixed version fo GnuTLS is available
-## and installed in our CI system.
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -7079,12 +7084,11 @@
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
              hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
-           "$G_CLI -u --insecure 127.0.0.1" \
+           "$G_NEXT_CLI -u --insecure 127.0.0.1" \
             0 \
             -s "fragmenting handshake message"
 
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -7096,7 +7100,7 @@
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
              hs_timeout=250-60000 mtu=512 force_version=dtls1" \
-           "$G_CLI -u --insecure 127.0.0.1" \
+           "$G_NEXT_CLI -u --insecure 127.0.0.1" \
             0 \
             -s "fragmenting handshake message"
 
@@ -7666,29 +7670,23 @@
             -s "Extra-header:" \
             -c "Extra-header:"
 
-# The next two test are disabled because they tend to trigger a bug in the
-# version of GnuTLS that's currently installed on our CI. The bug occurs when
-# different fragments of the same handshake message are received out-of-order
-# by GnuTLS and results in a timeout. It's been fixed in GnuTLS 3.5.2.
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 client_needs_more_time 8
 not_with_valgrind # risk of non-mbedtls peer timing out
 run_test    "DTLS proxy: 3d, gnutls server, fragmentation" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$G_SRV -u --mtu 512" \
+            "$G_NEXT_SRV -u --mtu 512" \
             "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000" \
             0 \
             -s "Extra-header:" \
             -c "Extra-header:"
 
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 client_needs_more_time 8
 not_with_valgrind # risk of non-mbedtls peer timing out
 run_test    "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$G_SRV -u --mtu 512" \
+            "$G_NEXT_SRV -u --mtu 512" \
             "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000 nbio=2" \
             0 \
             -s "Extra-header:" \
diff --git a/tests/suites/test_suite_pkcs1_v15.data b/tests/suites/test_suite_pkcs1_v15.data
index a4d6eb5..b4cf09a 100644
--- a/tests/suites/test_suite_pkcs1_v15.data
+++ b/tests/suites/test_suite_pkcs1_v15.data
@@ -1,3 +1,9 @@
+RSAES-V15 Encryption input=NULL with length=0
+pkcs1_rsaes_v15_encrypt:1024:16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_NONE:"":"aafd12f659cae63489b479e5076ddec2f06cb58f67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb3267c6697351ff4aec29cdbaabf2fbe34676cac0":"42c6fce63a3b858ba89fe83004cac3651d1497c15090bf0086b9a4b9ff3bd451502838a413095aefe231832ba10bb467ae3f95c889cd8e9a6e32b4df633b2170d07a2168c086745f0017cf1d9facff2eee55af2fcb03730209173b2a0bbfb2d4c34d7ea93b3b0cb84a8a7b6371670e14482e6dcedbdd9efe66d906e0238586fe":0
+
+RSAES-V15 Decryption empty output with NULL buffer
+pkcs1_rsaes_v15_decrypt:1024:16:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":16:"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_NONE:"":"aafd12f659cae63489b479e5076ddec2f06cb58f":"42c6fce63a3b858ba89fe83004cac3651d1497c15090bf0086b9a4b9ff3bd451502838a413095aefe231832ba10bb467ae3f95c889cd8e9a6e32b4df633b2170d07a2168c086745f0017cf1d9facff2eee55af2fcb03730209173b2a0bbfb2d4c34d7ea93b3b0cb84a8a7b6371670e14482e6dcedbdd9efe66d906e0238586fe":0
+
 RSAES-V15 Encryption Test Vector Int
 pkcs1_rsaes_v15_encrypt:1024:16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_SHA1:"d436e99569fd32a7c8a05bbc90d32c49":"aafd12f659cae63489b479e5076ddec2f06cb58f67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32":"6c5ebca6116b1e91316613fbb5e93197270a849122d549122d05815e2626f80d20f7f3f038c98295203c0f7f6bb8c3568455c67dec82bca86be86eff43b56b7ba2d15375f9a42454c2a2c709953a6e4a977462e35fd21a9c2fb3c0ad2a370f7655267bf6f04814784982988e663b869fc8588475af860d499e5a6ffdfc2c6bfd":0
 
diff --git a/tests/suites/test_suite_pkcs1_v15.function b/tests/suites/test_suite_pkcs1_v15.function
index 0723623..3ef4e2c 100644
--- a/tests/suites/test_suite_pkcs1_v15.function
+++ b/tests/suites/test_suite_pkcs1_v15.function
@@ -32,11 +32,11 @@
     TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( ( mod + 7 ) / 8 ) );
     TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 );
 
-
+    if( message_str->len == 0 )
+        message_str->x = NULL;
     TEST_ASSERT( mbedtls_rsa_pkcs1_encrypt( &ctx, &rnd_buffer_rand, &info, MBEDTLS_RSA_PUBLIC, message_str->len, message_str->x, output ) == result );
     if( result == 0 )
     {
-
         TEST_ASSERT( hexcmp( output, result_hex_str->x, ctx.len, result_hex_str->len ) == 0 );
     }
 
@@ -78,12 +78,17 @@
     TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 );
     TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 );
 
-
-    TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
-    if( result == 0 )
+    if( result_hex_str->len == 0 )
     {
-
-        TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len) == 0 );
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, NULL, 0 ) == result );
+    }
+    else
+    {
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
+        if( result == 0 )
+        {
+            TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len) == 0 );
+        }
     }
 
 exit:
diff --git a/tests/suites/test_suite_pkcs1_v21.data b/tests/suites/test_suite_pkcs1_v21.data
index 291c305..012867c 100644
--- a/tests/suites/test_suite_pkcs1_v21.data
+++ b/tests/suites/test_suite_pkcs1_v21.data
@@ -187,6 +187,10 @@
 RSAES-OAEP Encryption Example 10_6
 pkcs1_rsaes_oaep_encrypt:2048:16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46":0
 
+RSAES-OAEP Encryption input=NULL with length=0
+depends_on:MBEDTLS_SHA1_C
+pkcs1_rsaes_oaep_encrypt:2048:16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"32b75304e631e94d4b02819642c7ffa66116af504cb3c4687420cc4b7f069fc6cc3b1a254611995ce2914a9e88152d38bbf87ccedcad9b9890341284e56e802a1b1f8f6bd3d5c991bd92eb8a8ea0a1d8bae141088ff8dceaebdb73515cf06ce33baa37c53093f1d1edc3502818cc70edcfddb41646374beb5b4f67f7f773e43778d4d31012e5a207c474e762ac3251ea6ede9018ad6e8e9ea65a3528a62b694eb9d8becff220a7c6c70d33eaafa52cf67a8090f67b6f9c43c6fe0b0f2375cbb9e611c0fcfef5312feb5e53d4a89d3d7e06c966e0c92ab9e5838239f390bcfd918d94c224df8e8ccb57ee364389908b6a0e550133f7565016804fbd6cb338314a":0
+
 RSAES-OAEP Decryption Test Vector Int
 pkcs1_rsaes_oaep_decrypt:1024:16:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":16:"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_SHA1:"d436e99569fd32a7c8a05bbc90d32c49":"aafd12f659cae63489b479e5076ddec2f06cb58f":"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955":0
 
@@ -370,6 +374,10 @@
 RSAES-OAEP Decryption Example 10_6
 pkcs1_rsaes_oaep_decrypt:2048:16:"ecf5aecd1e5515fffacbd75a2816c6ebf49018cdfb4638e185d66a7396b6f8090f8018c7fd95cc34b857dc17f0cc6516bb1346ab4d582cadad7b4103352387b70338d084047c9d9539b6496204b3dd6ea442499207bec01f964287ff6336c3984658336846f56e46861881c10233d2176bf15a5e96ddc780bc868aa77d3ce769":16:"bc46c464fc6ac4ca783b0eb08a3c841b772f7e9b2f28babd588ae885e1a0c61e4858a0fb25ac299990f35be85164c259ba1175cdd7192707135184992b6c29b746dd0d2cabe142835f7d148cc161524b4a09946d48b828473f1ce76b6cb6886c345c03e05f41d51b5c3a90a3f24073c7d74a4fe25d9cf21c75960f3fc3863183":16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46":0
 
+RSAES-OAEP Decryption empty output with NULL buffer
+depends_on:MBEDTLS_SHA1_C
+pkcs1_rsaes_oaep_decrypt:2048:16:"ecf5aecd1e5515fffacbd75a2816c6ebf49018cdfb4638e185d66a7396b6f8090f8018c7fd95cc34b857dc17f0cc6516bb1346ab4d582cadad7b4103352387b70338d084047c9d9539b6496204b3dd6ea442499207bec01f964287ff6336c3984658336846f56e46861881c10233d2176bf15a5e96ddc780bc868aa77d3ce769":16:"bc46c464fc6ac4ca783b0eb08a3c841b772f7e9b2f28babd588ae885e1a0c61e4858a0fb25ac299990f35be85164c259ba1175cdd7192707135184992b6c29b746dd0d2cabe142835f7d148cc161524b4a09946d48b828473f1ce76b6cb6886c345c03e05f41d51b5c3a90a3f24073c7d74a4fe25d9cf21c75960f3fc3863183":16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"32b75304e631e94d4b02819642c7ffa66116af504cb3c4687420cc4b7f069fc6cc3b1a254611995ce2914a9e88152d38bbf87ccedcad9b9890341284e56e802a1b1f8f6bd3d5c991bd92eb8a8ea0a1d8bae141088ff8dceaebdb73515cf06ce33baa37c53093f1d1edc3502818cc70edcfddb41646374beb5b4f67f7f773e43778d4d31012e5a207c474e762ac3251ea6ede9018ad6e8e9ea65a3528a62b694eb9d8becff220a7c6c70d33eaafa52cf67a8090f67b6f9c43c6fe0b0f2375cbb9e611c0fcfef5312feb5e53d4a89d3d7e06c966e0c92ab9e5838239f390bcfd918d94c224df8e8ccb57ee364389908b6a0e550133f7565016804fbd6cb338314a":0
+
 RSASSA-PSS Signing Test Vector Int
 pkcs1_rsassa_pss_sign:1024:16:"d17f655bf27c8b16d35462c905cc04a26f37e2a67fa9c0ce0dced472394a0df743fe7f929e378efdb368eddff453cf007af6d948e0ade757371f8a711e278f6b":16:"c6d92b6fee7414d1358ce1546fb62987530b90bd15e0f14963a5e2635adb69347ec0c01b2ab1763fd8ac1a592fb22757463a982425bb97a3a437c5bf86d03f2f":16:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":16:"010001":MBEDTLS_MD_SHA1:MBEDTLS_MD_SHA1:"859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc":"e3b5d5d002c1bce50c2b65ef88a188d83bce7e61":"8daa627d3de7595d63056c7ec659e54406f10610128baae821c8b2a0f3936d54dc3bdce46689f6b7951bb18e840542769718d5715d210d85efbb596192032c42be4c29972c856275eb6d5a45f05f51876fc6743deddd28caec9bb30ea99e02c3488269604fe497f74ccd7c7fca1671897123cbd30def5d54a2b5536ad90a747e":0
 
diff --git a/tests/suites/test_suite_pkcs1_v21.function b/tests/suites/test_suite_pkcs1_v21.function
index 99be08a..180bc4a 100644
--- a/tests/suites/test_suite_pkcs1_v21.function
+++ b/tests/suites/test_suite_pkcs1_v21.function
@@ -32,11 +32,11 @@
     TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( ( mod + 7 ) / 8 ) );
     TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 );
 
-
+    if( message_str->len == 0 )
+        message_str->x = NULL;
     TEST_ASSERT( mbedtls_rsa_pkcs1_encrypt( &ctx, &rnd_buffer_rand, &info, MBEDTLS_RSA_PUBLIC, message_str->len, message_str->x, output ) == result );
     if( result == 0 )
     {
-
         TEST_ASSERT( hexcmp( output, result_hex_str->x, ctx.len, result_hex_str->len ) == 0 );
     }
 
@@ -79,12 +79,17 @@
     TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 );
     TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 );
 
-
-    TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
-    if( result == 0 )
+    if( result_hex_str->len == 0 )
     {
-
-        TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len ) == 0 );
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, NULL, 0 ) == result );
+    }
+    else
+    {
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
+        if( result == 0 )
+        {
+            TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len ) == 0 );
+        }
     }
 
 exit:
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index 62bb782..7165f36 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compiletime library version
-check_compiletime_version:"2.16.0"
+check_compiletime_version:"0.0.0"
 
 Check runtime library version
-check_runtime_version:"2.16.0"
+check_runtime_version:"0.0.0"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0