Merge pull request #955 from Mbed-TLS/mbedtls-2.28.1rc0-pr

Mbed TLS 2.28.1rc0 pr
diff --git a/ChangeLog b/ChangeLog
index 021012a..54217fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,98 @@
-mbed TLS ChangeLog (Sorted per branch, date)
+Mbed TLS ChangeLog (Sorted per branch, date)
+
+= Mbed TLS 2.28.1 branch released 2022-07-11
+
+Default behavior changes
+   * mbedtls_cipher_set_iv will now fail with ChaCha20 and ChaCha20+Poly1305
+     for IV lengths other than 12. The library was silently overwriting this
+     length with 12, but did not inform the caller about it. Fixes #4301.
+
+Features
+   * When MBEDTLS_PSA_CRYPTO_CONFIG is enabled, you may list the PSA crypto
+     feature requirements in the file named by the new macro
+     MBEDTLS_PSA_CRYPTO_CONFIG_FILE instead of the default psa/crypto_config.h.
+     Furthermore you may name an additional file to include after the main
+     file with the macro MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE.
+
+Security
+   * Zeroize dynamically-allocated buffers used by the PSA Crypto key storage
+     module before freeing them. These buffers contain secret key material, and
+     could thus potentially leak the key through freed heap.
+   * Fix a potential heap buffer overread in TLS 1.2 server-side when
+     MBEDTLS_USE_PSA_CRYPTO is enabled, an opaque key (created with
+     mbedtls_pk_setup_opaque()) is provisioned, and a static ECDH ciphersuite
+     is selected. This may result in an application crash or potentially an
+     information leak.
+   * Fix a buffer overread in DTLS ClientHello parsing in servers with
+     MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE enabled. An unauthenticated client
+     or a man-in-the-middle could cause a DTLS server to read up to 255 bytes
+     after the end of the SSL input buffer. The buffer overread only happens
+     when MBEDTLS_SSL_IN_CONTENT_LEN is less than a threshold that depends on
+     the exact configuration: 258 bytes if using mbedtls_ssl_cookie_check(),
+     and possibly up to 571 bytes with a custom cookie check function.
+     Reported by the Cybeats PSI Team.
+
+Bugfix
+   * Fix a memory leak if mbedtls_ssl_config_defaults() is called twice.
+   * Fix several bugs (warnings, compiler and linker errors, test failures)
+     in reduced configurations when MBEDTLS_USE_PSA_CRYPTO is enabled.
+   * Fix a bug in (D)TLS curve negotiation: when MBEDTLS_USE_PSA_CRYPTO was
+     enabled and an ECDHE-ECDSA or ECDHE-RSA key exchange was used, the
+     client would fail to check that the curve selected by the server for
+     ECDHE was indeed one that was offered. As a result, the client would
+     accept any curve that it supported, even if that curve was not allowed
+     according to its configuration. Fixes #5291.
+   * Fix unit tests that used 0 as the file UID. This failed on some
+     implementations of PSA ITS. Fixes #3838.
+   * Fix API violation in mbedtls_md_process() test by adding a call to
+     mbedtls_md_starts(). Fixes #2227.
+   * Fix compile errors when MBEDTLS_HAVE_TIME is not defined. Add tests
+     to catch bad uses of time.h.
+   * Fix the library search path when building a shared library with CMake
+     on Windows.
+   * Fix bug in the alert sending function mbedtls_ssl_send_alert_message()
+     potentially leading to corrupted alert messages being sent in case
+     the function needs to be re-called after initially returning
+     MBEDTLS_SSL_WANT_WRITE. Fixes #1916.
+   * In configurations with MBEDTLS_SSL_DTLS_CONNECTION_ID enabled but none of
+     MBEDTLS_SSL_HW_RECORD_ACCEL, MBEDTLS_SSL_EXPORT_KEYS or MBEDTLS_DEBUG_C,
+     DTLS handshakes using CID would crash due to a null pointer dereference.
+     Fix this. Fixes #3998.
+   * Fix incorrect documentation of mbedtls_x509_crt_profile. The previous
+     documentation stated that the `allowed_pks` field applies to signatures
+     only, but in fact it does apply to the public key type of the end entity
+     certificate, too. Fixes #1992.
+   * Fix PSA cipher multipart operations using ARC4. Previously, an IV was
+     required but discarded. Now, an IV is rejected, as it should be.
+   * Fix undefined behavior in mbedtls_asn1_find_named_data(), where val is
+     not NULL and val_len is zero.
+   * psa_raw_key_agreement() now returns PSA_ERROR_BUFFER_TOO_SMALL when
+     applicable. Fixes #5735.
+   * Fix a bug in the x25519 example program where the removal of
+     MBEDTLS_ECDH_LEGACY_CONTEXT caused the program not to run. Fixes #4901 and
+     #3191.
+   * Encode X.509 dates before 1/1/2000 as UTCTime rather than
+     GeneralizedTime. Fixes #5465.
+   * Fix order value of curve x448.
+   * Fix string representation of DNs when outputting values containing commas
+     and other special characters, conforming to RFC 1779. Fixes #769.
+   * Silence a warning from GCC 12 in the selftest program. Fixes #5974.
+   * Fix mbedtls_asn1_write_mpi() writing an incorrect encoding of 0.
+   * Fix resource leaks in mbedtls_pk_parse_public_key() in low
+     memory conditions.
+   * Fix server connection identifier setting for outgoing encrypted records
+     on DTLS 1.2 session resumption. After DTLS 1.2 session resumption with
+     connection identifier, the Mbed TLS client now properly sends the server
+     connection identifier in encrypted record headers. Fix #5872.
+   * Fix a null pointer dereference when performing some operations on zero
+     represented with 0 limbs (specifically mbedtls_mpi_mod_int() dividing
+     by 2, and mbedtls_mpi_write_string() in base 2).
+   * Fix record sizes larger than 16384 being sometimes accepted despite being
+     non-compliant. This could not lead to a buffer overflow. In particular,
+     application data size was already checked correctly.
+
+Changes
+   * Assume source files are in UTF-8 when using MSVC with CMake.
 
 = mbed TLS 2.28.0 branch released 2021-12-17
 
diff --git a/ChangeLog.d/PSA-test-suites-NOT-using-UID-0.txt b/ChangeLog.d/PSA-test-suites-NOT-using-UID-0.txt
deleted file mode 100644
index 9acbb0a..0000000
--- a/ChangeLog.d/PSA-test-suites-NOT-using-UID-0.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix unit tests that used 0 as the file UID. This failed on some
-     implementations of PSA ITS. Fixes #3838.
diff --git a/ChangeLog.d/add-mbedtls_md_starts-to-mbedtls_md_process-test.txt b/ChangeLog.d/add-mbedtls_md_starts-to-mbedtls_md_process-test.txt
deleted file mode 100644
index 57c7561..0000000
--- a/ChangeLog.d/add-mbedtls_md_starts-to-mbedtls_md_process-test.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix API violation in mbedtls_md_process() test by adding a call to
-     mbedtls_md_starts(). Fixes #2227.
diff --git a/ChangeLog.d/alert_reentrant.txt b/ChangeLog.d/alert_reentrant.txt
deleted file mode 100644
index 691d64c..0000000
--- a/ChangeLog.d/alert_reentrant.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix bug in the alert sending function mbedtls_ssl_send_alert_message()
-     potentially leading to corrupted alert messages being sent in case
-     the function needs to be re-called after initially returning
-     MBEDTLS_SSL_WANT_WRITE. Fixes #1916.
diff --git a/ChangeLog.d/asn1write-0-fix b/ChangeLog.d/asn1write-0-fix
deleted file mode 100644
index 2e01244..0000000
--- a/ChangeLog.d/asn1write-0-fix
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-   * Fix mbedtls_asn1_write_mpi() writing an incorrect encoding of 0.
diff --git a/ChangeLog.d/bug_x448.txt b/ChangeLog.d/bug_x448.txt
deleted file mode 100644
index cebefc4..0000000
--- a/ChangeLog.d/bug_x448.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-    * Fix order value of curve x448.
diff --git a/ChangeLog.d/chacha20_invalid_iv_len_fix.txt b/ChangeLog.d/chacha20_invalid_iv_len_fix.txt
deleted file mode 100644
index af35e2a..0000000
--- a/ChangeLog.d/chacha20_invalid_iv_len_fix.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Default behavior changes
-   * mbedtls_cipher_set_iv will now fail with ChaCha20 and ChaCha20+Poly1305
-     for IV lengths other than 12. The library was silently overwriting this
-     length with 12, but did not inform the caller about it. Fixes #4301.
diff --git a/ChangeLog.d/cmake_msvc_utf8.txt b/ChangeLog.d/cmake_msvc_utf8.txt
deleted file mode 100644
index 552eec7..0000000
--- a/ChangeLog.d/cmake_msvc_utf8.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Changes
-   * Assume source files are in UTF-8 when using MSVC with CMake.
diff --git a/ChangeLog.d/doc-x509-profile-pk.txt b/ChangeLog.d/doc-x509-profile-pk.txt
deleted file mode 100644
index 35625fe..0000000
--- a/ChangeLog.d/doc-x509-profile-pk.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix incorrect documentation of mbedtls_x509_crt_profile. The previous
-     documentation stated that the `allowed_pks` field applies to signatures
-     only, but in fact it does apply to the public key type of the end entity
-     certificate, too. Fixes #1992.
diff --git a/ChangeLog.d/dtls-cid-null.txt b/ChangeLog.d/dtls-cid-null.txt
deleted file mode 100644
index f6f4c54..0000000
--- a/ChangeLog.d/dtls-cid-null.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * In configurations with MBEDTLS_SSL_DTLS_CONNECTION_ID enabled but none of
-     MBEDTLS_SSL_HW_RECORD_ACCEL, MBEDTLS_SSL_EXPORT_KEYS or MBEDTLS_DEBUG_C,
-     DTLS handshakes using CID would crash due to a null pointer dereference.
-     Fix this. Fixes #3998.
diff --git a/ChangeLog.d/fix-csr_subject_commas.txt b/ChangeLog.d/fix-csr_subject_commas.txt
deleted file mode 100644
index e01c9a8..0000000
--- a/ChangeLog.d/fix-csr_subject_commas.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix string representation of DNs when outputting values containing commas
-     and other special characters, conforming to RFC 1779. Fixes #769.
diff --git a/ChangeLog.d/fix-time-format-pre-2000.txt b/ChangeLog.d/fix-time-format-pre-2000.txt
deleted file mode 100644
index 414201e..0000000
--- a/ChangeLog.d/fix-time-format-pre-2000.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Encode X.509 dates before 1/1/2000 as UTCTime rather than
-     GeneralizedTime. Fixes #5465.
diff --git a/ChangeLog.d/fix-undefined-memcpy-mbedtls_asn1_named_data.txt b/ChangeLog.d/fix-undefined-memcpy-mbedtls_asn1_named_data.txt
deleted file mode 100644
index b30f7fa..0000000
--- a/ChangeLog.d/fix-undefined-memcpy-mbedtls_asn1_named_data.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix undefined behavior in mbedtls_asn1_find_named_data(), where val is
-     not NULL and val_len is zero.
diff --git a/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt b/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt
deleted file mode 100644
index a6540a1..0000000
--- a/ChangeLog.d/fix-windows-cmake-build-with-shared-libraries.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix the library search path when building a shared library with CMake
-     on Windows.
diff --git a/ChangeLog.d/fix-x25519-program.txt b/ChangeLog.d/fix-x25519-program.txt
deleted file mode 100644
index bf5d6ac..0000000
--- a/ChangeLog.d/fix-x25519-program.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix a bug in the x25519 example program where the removal of
-     MBEDTLS_ECDH_LEGACY_CONTEXT caused the program not to run. Fixes #4901 and
-     #3191.
diff --git a/ChangeLog.d/fix_some_resource_leaks.txt b/ChangeLog.d/fix_some_resource_leaks.txt
deleted file mode 100644
index f8db3f2..0000000
--- a/ChangeLog.d/fix_some_resource_leaks.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix resource leaks in mbedtls_pk_parse_public_key() in low
-     memory conditions.
-
diff --git a/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt b/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt
deleted file mode 100644
index 043b273..0000000
--- a/ChangeLog.d/mbedtls_ssl_config_defaults-memleak.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-   * Fix a memory leak if mbedtls_ssl_config_defaults() is called twice.
diff --git a/ChangeLog.d/psa-rc4.txt b/ChangeLog.d/psa-rc4.txt
deleted file mode 100644
index c255413..0000000
--- a/ChangeLog.d/psa-rc4.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix PSA cipher multipart operations using ARC4. Previously, an IV was
-     required but discarded. Now, an IV is rejected, as it should be.
diff --git a/ChangeLog.d/psa_crypto_config_file.txt b/ChangeLog.d/psa_crypto_config_file.txt
deleted file mode 100644
index d42651d..0000000
--- a/ChangeLog.d/psa_crypto_config_file.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * When MBEDTLS_PSA_CRYPTO_CONFIG is enabled, you may list the PSA crypto
-     feature requirements in the file named by the new macro
-     MBEDTLS_PSA_CRYPTO_CONFIG_FILE instead of the default psa/crypto_config.h.
-     Furthermore you may name an additional file to include after the main
-     file with the macro MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE.
diff --git a/ChangeLog.d/psa_crypto_reduced_configs_bugs.txt b/ChangeLog.d/psa_crypto_reduced_configs_bugs.txt
deleted file mode 100644
index 0d61cb7..0000000
--- a/ChangeLog.d/psa_crypto_reduced_configs_bugs.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix several bugs (warnings, compiler and linker errors, test failures)
-     in reduced configurations when MBEDTLS_USE_PSA_CRYPTO is enabled.
diff --git a/ChangeLog.d/psa_raw_key_agreement-buffer_too_small.txt b/ChangeLog.d/psa_raw_key_agreement-buffer_too_small.txt
deleted file mode 100644
index 415c849..0000000
--- a/ChangeLog.d/psa_raw_key_agreement-buffer_too_small.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * psa_raw_key_agreement() now returns PSA_ERROR_BUFFER_TOO_SMALL when
-     applicable. Fixes #5735.
diff --git a/ChangeLog.d/resumption_cid.txt b/ChangeLog.d/resumption_cid.txt
deleted file mode 100644
index 5c237aa..0000000
--- a/ChangeLog.d/resumption_cid.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix server connection identifier setting for outgoing encrypted records
-     on DTLS 1.2 session resumption. After DTLS 1.2 session resumption with
-     connection identifier, the Mbed TLS client now properly sends the server
-     connection identifier in encrypted record headers. Fix #5872.
diff --git a/ChangeLog.d/selftest-gcc12.txt b/ChangeLog.d/selftest-gcc12.txt
deleted file mode 100644
index aafa256..0000000
--- a/ChangeLog.d/selftest-gcc12.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-   * Silence a warning from GCC 12 in the selftest program. Fixes #5974.
diff --git a/ChangeLog.d/timeless.txt b/ChangeLog.d/timeless.txt
deleted file mode 100644
index 84f07d6..0000000
--- a/ChangeLog.d/timeless.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix compile errors when MBEDTLS_HAVE_TIME is not defined. Add tests
-     to catch bad uses of time.h.
diff --git a/ChangeLog.d/use-psa-ecdhe-curve.txt b/ChangeLog.d/use-psa-ecdhe-curve.txt
deleted file mode 100644
index 658f88f..0000000
--- a/ChangeLog.d/use-psa-ecdhe-curve.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Bugfix
-   * Fix a bug in (D)TLS curve negotiation: when MBEDTLS_USE_PSA_CRYPTO was
-     enabled and an ECDHE-ECDSA or ECDHE-RSA key exchange was used, the
-     client would fail to check that the curve selected by the server for
-     ECDHE was indeed one that was offered. As a result, the client would
-     accept any curve that it supported, even if that curve was not allowed
-     according to its configuration. Fixes #5291.
diff --git a/ChangeLog.d/zeroize_key_buffers_before_free.txt b/ChangeLog.d/zeroize_key_buffers_before_free.txt
deleted file mode 100644
index ba5bae1..0000000
--- a/ChangeLog.d/zeroize_key_buffers_before_free.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Security
-   * Zeroize dynamically-allocated buffers used by the PSA Crypto key storage
-     module before freeing them. These buffers contain secret key material, and
-     could thus potentially leak the key through freed heap.
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index 5a0f3ec..e454a19 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -22,7 +22,7 @@
  */
 
 /**
- * @mainpage mbed TLS v2.28.0 source code documentation
+ * @mainpage mbed TLS v2.28.1 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 b4f255e..f180081 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -1,4 +1,4 @@
-PROJECT_NAME           = "mbed TLS v2.28.0"
+PROJECT_NAME           = "mbed TLS v2.28.1"
 OUTPUT_DIRECTORY       = ../apidoc/
 FULL_PATH_NAMES        = NO
 OPTIMIZE_OUTPUT_FOR_C  = YES
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index 8f2abf2..c9a13f4 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -217,32 +217,6 @@
 typedef void mbedtls_pk_restart_ctx;
 #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
 
-#if defined(MBEDTLS_RSA_C)
-/**
- * Quick access to an RSA context inside a PK context.
- *
- * \warning You must make sure the PK context actually holds an RSA context
- * before using this function!
- */
-static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk )
-{
-    return( (mbedtls_rsa_context *) (pk).pk_ctx );
-}
-#endif /* MBEDTLS_RSA_C */
-
-#if defined(MBEDTLS_ECP_C)
-/**
- * Quick access to an EC context inside a PK context.
- *
- * \warning You must make sure the PK context actually holds an EC context
- * before using this function!
- */
-static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk )
-{
-    return( (mbedtls_ecp_keypair *) (pk).pk_ctx );
-}
-#endif /* MBEDTLS_ECP_C */
-
 #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
 /**
  * \brief           Types for RSA-alt abstraction
@@ -656,6 +630,55 @@
  */
 mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx );
 
+#if defined(MBEDTLS_RSA_C)
+/**
+ * Quick access to an RSA context inside a PK context.
+ *
+ * \warning This function can only be used when the type of the context, as
+ * returned by mbedtls_pk_get_type(), is #MBEDTLS_PK_RSA.
+ * Ensuring that is the caller's responsibility.
+ * Alternatively, you can check whether this function returns NULL.
+ *
+ * \return The internal RSA context held by the PK context, or NULL.
+ */
+static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk )
+{
+    switch( mbedtls_pk_get_type( &pk ) )
+    {
+        case MBEDTLS_PK_RSA:
+            return( (mbedtls_rsa_context *) (pk).pk_ctx );
+        default:
+            return( NULL );
+    }
+}
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_ECP_C)
+/**
+ * Quick access to an EC context inside a PK context.
+ *
+ * \warning This function can only be used when the type of the context, as
+ * returned by mbedtls_pk_get_type(), is #MBEDTLS_PK_ECKEY,
+ * #MBEDTLS_PK_ECKEY_DH, or #MBEDTLS_PK_ECDSA.
+ * Ensuring that is the caller's responsibility.
+ * Alternatively, you can check whether this function returns NULL.
+ *
+ * \return The internal EC context held by the PK context, or NULL.
+ */
+static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk )
+{
+    switch( mbedtls_pk_get_type( &pk ) )
+    {
+        case MBEDTLS_PK_ECKEY:
+        case MBEDTLS_PK_ECKEY_DH:
+        case MBEDTLS_PK_ECDSA:
+            return( (mbedtls_ecp_keypair *) (pk).pk_ctx );
+        default:
+            return( NULL );
+    }
+}
+#endif /* MBEDTLS_ECP_C */
+
 #if defined(MBEDTLS_PK_PARSE_C)
 /** \ingroup pk_module */
 /**
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index f50cf9f..46ade67 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -934,16 +934,22 @@
  */
 void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl );
 void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl );
 
 void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl );
 void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl );
 
@@ -1023,27 +1029,39 @@
  *              following the above definition.
  *
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
                              unsigned update_hs_digest );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl );
 
 void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl,
                             const mbedtls_ssl_ciphersuite_t *ciphersuite_info );
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex );
 
 /**
@@ -1108,14 +1126,18 @@
 
 mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash );
 unsigned char mbedtls_ssl_hash_from_md_alg( int md );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md );
 
 #if defined(MBEDTLS_ECP_C)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_check_curve_tls_id( const mbedtls_ssl_context *ssl, uint16_t tls_id );
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl,
                                 mbedtls_md_type_t md );
 #endif
@@ -1171,6 +1193,7 @@
  *
  * Return 0 if everything is OK, -1 if not.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert,
                           const mbedtls_ssl_ciphersuite_t *ciphersuite,
                           int cert_endpoint,
@@ -1219,21 +1242,26 @@
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl );
 void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_resend( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl );
 #endif
 
 /* Visible for testing purposes only */
 #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context const *ssl );
 void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl );
 #endif
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
                               const mbedtls_ssl_session *src );
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl,
                                         unsigned char *output,
                                         unsigned char *data, size_t data_len );
@@ -1243,6 +1271,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
 /* The hash buffer must have at least MBEDTLS_MD_MAX_SIZE bytes of length. */
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
                                             unsigned char *hash, size_t *hashlen,
                                             unsigned char *data, size_t data_len,
@@ -1255,11 +1284,13 @@
 #endif
 
 void mbedtls_ssl_transform_init( mbedtls_ssl_transform *transform );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl,
                              mbedtls_ssl_transform *transform,
                              mbedtls_record *rec,
                              int (*f_rng)(void *, unsigned char *, size_t),
                              void *p_rng );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl,
                              mbedtls_ssl_transform *transform,
                              mbedtls_record *rec );
@@ -1277,10 +1308,12 @@
 }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_resend_hello_request( mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 void mbedtls_ssl_set_timer( mbedtls_ssl_context *ssl, uint32_t millisecs );
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_check_timer( mbedtls_ssl_context *ssl );
 
 void mbedtls_ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl );
@@ -1288,6 +1321,7 @@
                               mbedtls_ssl_transform *transform );
 void mbedtls_ssl_update_in_pointers( mbedtls_ssl_context *ssl );
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial );
 
 #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
@@ -1297,6 +1331,7 @@
 void mbedtls_ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl );
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
+MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_start_renegotiation( mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
@@ -1306,4 +1341,12 @@
 void mbedtls_ssl_flight_free( mbedtls_ssl_flight_item *flight );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+#if defined(MBEDTLS_TEST_HOOKS)
+int mbedtls_ssl_check_dtls_clihlo_cookie(
+                          mbedtls_ssl_context *ssl,
+                          const unsigned char *cli_id, size_t cli_id_len,
+                          const unsigned char *in, size_t in_len,
+                          unsigned char *obuf, size_t buf_len, size_t *olen );
+#endif
+
 #endif /* ssl_internal.h */
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index b1a92b2..44adcbf 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -38,16 +38,16 @@
  */
 #define MBEDTLS_VERSION_MAJOR  2
 #define MBEDTLS_VERSION_MINOR  28
-#define MBEDTLS_VERSION_PATCH  0
+#define MBEDTLS_VERSION_PATCH  1
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x021C0000
-#define MBEDTLS_VERSION_STRING         "2.28.0"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.28.0"
+#define MBEDTLS_VERSION_NUMBER         0x021C0100
+#define MBEDTLS_VERSION_STRING         "2.28.1"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.28.1"
 
 #if defined(MBEDTLS_VERSION_C)
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index cde9cf4..fb0b5e1 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -204,15 +204,15 @@
 if(USE_SHARED_MBEDTLS_LIBRARY)
     set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
     add_library(${mbedcrypto_target} SHARED ${src_crypto})
-    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 2.28.0 SOVERSION 7)
+    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 2.28.1 SOVERSION 7)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
     add_library(${mbedx509_target} SHARED ${src_x509})
-    set_target_properties(${mbedx509_target} PROPERTIES VERSION 2.28.0 SOVERSION 1)
+    set_target_properties(${mbedx509_target} PROPERTIES VERSION 2.28.1 SOVERSION 1)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
 
     add_library(${mbedtls_target} SHARED ${src_tls})
-    set_target_properties(${mbedtls_target} PROPERTIES VERSION 2.28.0 SOVERSION 14)
+    set_target_properties(${mbedtls_target} PROPERTIES VERSION 2.28.1 SOVERSION 14)
     target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
 endif(USE_SHARED_MBEDTLS_LIBRARY)
 
diff --git a/library/bignum.c b/library/bignum.c
index db29ae5..32578e2 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -1829,7 +1829,7 @@
     /*
      * handle trivial cases
      */
-    if( b == 1 )
+    if( b == 1 || A->n == 0 )
     {
         *r = 0;
         return( 0 );
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 3826ad2..ceec77e 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -2181,6 +2181,7 @@
 static int supported_ciphersuites[MAX_CIPHERSUITES];
 static int supported_init = 0;
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ciphersuite_is_removed( const mbedtls_ssl_ciphersuite_t *cs_info )
 {
     (void)cs_info;
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index f0f3d5c..72351c9 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -53,6 +53,7 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_conf_has_static_psk( mbedtls_ssl_config const *conf )
 {
     if( conf->psk_identity     == NULL ||
@@ -73,6 +74,7 @@
 }
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_conf_has_static_raw_psk( mbedtls_ssl_config const *conf )
 {
     if( conf->psk_identity     == NULL ||
@@ -91,6 +93,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_hostname_ext( mbedtls_ssl_context *ssl,
                                    unsigned char *buf,
                                    const unsigned char *end,
@@ -161,6 +164,7 @@
 #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl,
                                         unsigned char *buf,
                                         const unsigned char *end,
@@ -204,6 +208,7 @@
  */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \
     defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl,
                                                unsigned char *buf,
                                                const unsigned char *end,
@@ -302,6 +307,7 @@
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_supported_elliptic_curves_ext( mbedtls_ssl_context *ssl,
                                                     unsigned char *buf,
                                                     const unsigned char *end,
@@ -373,6 +379,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl,
                                                   unsigned char *buf,
                                                   const unsigned char *end,
@@ -404,6 +411,7 @@
           MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl,
                                        unsigned char *buf,
                                        const unsigned char *end,
@@ -477,6 +485,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_cid_ext( mbedtls_ssl_context *ssl,
                               unsigned char *buf,
                               const unsigned char *end,
@@ -523,6 +532,7 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl,
                                               unsigned char *buf,
                                               const unsigned char *end,
@@ -555,6 +565,7 @@
 #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
 
 #if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl,
                                          unsigned char *buf,
                                          const unsigned char *end,
@@ -585,6 +596,7 @@
 #endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
 
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl,
                                            unsigned char *buf,
                                            const unsigned char *end,
@@ -616,6 +628,7 @@
 #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
 
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl,
                                       unsigned char *buf,
                                       const unsigned char *end,
@@ -647,6 +660,7 @@
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl,
                                          unsigned char *buf,
                                          const unsigned char *end,
@@ -689,6 +703,7 @@
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
 #if defined(MBEDTLS_SSL_ALPN)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_alpn_ext( mbedtls_ssl_context *ssl,
                                unsigned char *buf,
                                const unsigned char *end,
@@ -748,6 +763,7 @@
 #endif /* MBEDTLS_SSL_ALPN */
 
 #if defined(MBEDTLS_SSL_DTLS_SRTP)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_use_srtp_ext( mbedtls_ssl_context *ssl,
                                    unsigned char *buf,
                                    const unsigned char *end,
@@ -868,6 +884,7 @@
 /*
  * Generate random bytes for ClientHello
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_generate_random( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -917,6 +934,7 @@
  *
  * \return          0 if valid, else 1
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_validate_ciphersuite(
     const mbedtls_ssl_ciphersuite_t * suite_info,
     const mbedtls_ssl_context * ssl,
@@ -960,6 +978,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_client_hello( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -1450,6 +1469,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -1494,6 +1514,7 @@
 }
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl,
                                               const unsigned char *buf,
                                               size_t len )
@@ -1520,6 +1541,7 @@
 #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
 
 #if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -1545,6 +1567,7 @@
 #endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
 
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_cid_ext( mbedtls_ssl_context *ssl,
                               const unsigned char *buf,
                               size_t len )
@@ -1601,6 +1624,7 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -1627,6 +1651,7 @@
 #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
 
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -1653,6 +1678,7 @@
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -1679,6 +1705,7 @@
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_supported_point_formats_ext( mbedtls_ssl_context *ssl,
                                                   const unsigned char *buf,
                                                   size_t len )
@@ -1724,6 +1751,7 @@
           MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl,
                                    const unsigned char *buf,
                                    size_t len )
@@ -1758,6 +1786,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_ALPN)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl,
                                const unsigned char *buf, size_t len )
 {
@@ -1828,6 +1857,7 @@
 #endif /* MBEDTLS_SSL_ALPN */
 
 #if defined(MBEDTLS_SSL_DTLS_SRTP)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_use_srtp_ext( mbedtls_ssl_context *ssl,
                                    const unsigned char *buf,
                                    size_t len )
@@ -1948,6 +1978,7 @@
  * Parse HelloVerifyRequest.  Only called after verifying the HS type.
  */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_hello_verify_request( mbedtls_ssl_context *ssl )
 {
     const unsigned char *p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
@@ -2031,6 +2062,7 @@
 }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
 {
     int ret, i;
@@ -2599,6 +2631,7 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) ||                       \
     defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_dh_params( mbedtls_ssl_context *ssl,
                                        unsigned char **p,
                                        unsigned char *end )
@@ -2645,6 +2678,7 @@
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||                      \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl )
 {
     const mbedtls_ecp_curve_info *curve_info;
@@ -2686,6 +2720,7 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO) &&                           \
         ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
           defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) )
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_ecdh_params_psa( mbedtls_ssl_context *ssl,
                                              unsigned char **p,
                                              unsigned char *end )
@@ -2752,6 +2787,7 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||                   \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl,
                                          unsigned char **p,
                                          unsigned char *end )
@@ -2791,6 +2827,7 @@
           MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl,
                                       unsigned char **p,
                                       unsigned char *end )
@@ -2837,6 +2874,7 @@
 /*
  * Generate a pre-master secret and encrypt it with the server's RSA key
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl,
                                     size_t offset, size_t *olen,
                                     size_t pms_offset )
@@ -2924,6 +2962,7 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) ||                       \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_signature_algorithm( mbedtls_ssl_context *ssl,
                                           unsigned char **p,
                                           unsigned char *end,
@@ -2990,6 +3029,7 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3008,6 +3048,8 @@
     peer_pk = &ssl->session_negotiate->peer_cert->pk;
 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
+    /* This is a public key, so it can't be opaque, so can_do() is a good
+     * enough check to ensure pk_ec() is safe to use below. */
     if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) );
@@ -3041,6 +3083,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
           MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3447,6 +3490,7 @@
 }
 
 #if ! defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -3465,6 +3509,7 @@
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
 #else /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3636,6 +3681,7 @@
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_hello_done( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3675,6 +3721,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3936,7 +3983,10 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
             /* Opaque PSKs are currently only supported for PSK-only suites. */
             if( ssl_conf_has_static_raw_psk( ssl->conf ) == 0 )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "opaque PSK not supported with RSA-PSK" ) );
                 return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+            }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
             if( ( ret = ssl_write_encrypted_pms( ssl, header_len,
@@ -3951,7 +4001,10 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
             /* Opaque PSKs are currently only supported for PSK-only suites. */
             if( ssl_conf_has_static_raw_psk( ssl->conf ) == 0 )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "opaque PSK not supported with DHE-PSK" ) );
                 return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+            }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
             /*
@@ -3988,7 +4041,10 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
             /* Opaque PSKs are currently only supported for PSK-only suites. */
             if( ssl_conf_has_static_raw_psk( ssl->conf ) == 0 )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "opaque PSK not supported with ECDHE-PSK" ) );
                 return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+            }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
             /*
@@ -4098,6 +4154,7 @@
 }
 
 #if !defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -4123,6 +4180,7 @@
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
 #else /* !MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -4295,6 +4353,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c
index 519d6d7..3781796 100644
--- a/library/ssl_cookie.c
+++ b/library/ssl_cookie.c
@@ -122,6 +122,7 @@
 /*
  * Generate the HMAC part of a cookie
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_cookie_hmac( mbedtls_md_context_t *hmac_ctx,
                             const unsigned char time[4],
                             unsigned char **p, unsigned char *end,
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index 5a4574d..e47c538 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -91,6 +91,7 @@
 }
 
 #if defined(MBEDTLS_SSL_RECORD_CHECKING)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_record_header( mbedtls_ssl_context const *ssl,
                                     unsigned char *buf,
                                     size_t len,
@@ -165,11 +166,16 @@
 static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
                                      uint8_t slot );
 static void ssl_free_buffered_record( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_load_buffered_message( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_load_buffered_record( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_buffer_message( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_buffer_future_record( mbedtls_ssl_context *ssl,
                                      mbedtls_record const *rec );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl );
 
 static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl )
@@ -187,6 +193,7 @@
     return( out_buf_len );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl )
 {
     size_t const bytes_written = ssl->out_left;
@@ -203,6 +210,7 @@
     return( (int) ( mtu - bytes_written ) );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -254,6 +262,7 @@
  * Double the retransmit timeout value, within the allowed range,
  * returning -1 if the maximum value has already been reached.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl )
 {
     uint32_t new_timeout;
@@ -353,6 +362,7 @@
  *  - A negative error code if `max_len` didn't offer enough space
  *    for the expansion.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_build_inner_plaintext( unsigned char *content,
                                       size_t *content_size,
                                       size_t remaining,
@@ -380,6 +390,7 @@
 
 /* This function parses a (D)TLSInnerPlaintext structure.
  * See ssl_build_inner_plaintext() for details. */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_inner_plaintext( unsigned char const *content,
                                           size_t *content_size,
                                           uint8_t *rec_type )
@@ -474,6 +485,7 @@
 /*
  * SSLv3.0 MAC functions
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_mac( mbedtls_md_context_t *md_ctx,
                     const unsigned char *secret,
                     const unsigned char *buf, size_t len,
@@ -541,6 +553,7 @@
 #if defined(MBEDTLS_GCM_C) || \
     defined(MBEDTLS_CCM_C) || \
     defined(MBEDTLS_CHACHAPOLY_C)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_transform_aead_dynamic_iv_is_explicit(
                                 mbedtls_ssl_transform const *transform )
 {
@@ -1738,6 +1751,7 @@
 /*
  * Compression/decompression functions
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_compress_buf( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -1790,6 +1804,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_decompress_buf( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -2149,6 +2164,7 @@
 /*
  * Append current handshake message to current outgoing flight
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_flight_append( mbedtls_ssl_context *ssl )
 {
     mbedtls_ssl_flight_item *msg;
@@ -2215,6 +2231,7 @@
 /*
  * Swap transform_out and out_ctr with the alternative ones
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_swap_epochs( mbedtls_ssl_context *ssl )
 {
     mbedtls_ssl_transform *tmp_transform;
@@ -2857,6 +2874,7 @@
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_hs_is_proper_fragment( mbedtls_ssl_context *ssl )
 {
     if( ssl->in_msglen < ssl->in_hslen ||
@@ -2882,6 +2900,7 @@
               ssl->in_msg[8] );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_hs_header( mbedtls_ssl_context const *ssl )
 {
     uint32_t msg_len, frag_off, frag_len;
@@ -2948,6 +2967,7 @@
 /*
  * Check that bitmask is full
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_bitmask_check( unsigned char *mask, size_t len )
 {
     size_t i;
@@ -3147,6 +3167,7 @@
             ( (uint64_t) buf[5]       ) );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int mbedtls_ssl_dtls_record_replay_check( mbedtls_ssl_context *ssl, uint8_t *record_in_ctr )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3229,8 +3250,8 @@
 
 #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
 /*
- * Without any SSL context, check if a datagram looks like a ClientHello with
- * a valid cookie, and if it doesn't, generate a HelloVerifyRequest message.
+ * Check if a datagram looks like a ClientHello with a valid cookie,
+ * and if it doesn't, generate a HelloVerifyRequest message.
  * Both input and output include full DTLS headers.
  *
  * - if cookie is valid, return 0
@@ -3239,10 +3260,10 @@
  *   return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED
  * - otherwise return a specific error code
  */
-static int ssl_check_dtls_clihlo_cookie(
-                           mbedtls_ssl_cookie_write_t *f_cookie_write,
-                           mbedtls_ssl_cookie_check_t *f_cookie_check,
-                           void *p_cookie,
+MBEDTLS_CHECK_RETURN_CRITICAL
+MBEDTLS_STATIC_TESTABLE
+int mbedtls_ssl_check_dtls_clihlo_cookie(
+                           mbedtls_ssl_context *ssl,
                            const unsigned char *cli_id, size_t cli_id_len,
                            const unsigned char *in, size_t in_len,
                            unsigned char *obuf, size_t buf_len, size_t *olen )
@@ -3276,26 +3297,53 @@
      *
      * Minimum length is 61 bytes.
      */
-    if( in_len < 61 ||
-        in[0] != MBEDTLS_SSL_MSG_HANDSHAKE ||
+    MBEDTLS_SSL_DEBUG_MSG( 4, ( "check cookie: in_len=%u",
+                                (unsigned) in_len ) );
+    MBEDTLS_SSL_DEBUG_BUF( 4, "cli_id", cli_id, cli_id_len );
+    if( in_len < 61 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 4, ( "check cookie: record too short" ) );
+        return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+    if( in[0] != MBEDTLS_SSL_MSG_HANDSHAKE ||
         in[3] != 0 || in[4] != 0 ||
         in[19] != 0 || in[20] != 0 || in[21] != 0 )
     {
+        MBEDTLS_SSL_DEBUG_MSG( 4, ( "check cookie: not a good ClientHello" ) );
+        MBEDTLS_SSL_DEBUG_MSG( 4, ( "    type=%u epoch=%u fragment_offset=%u",
+                                    in[0],
+                                    (unsigned) in[3] << 8 | in[4],
+                                    (unsigned) in[19] << 16 | in[20] << 8 | in[21] ) );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
     sid_len = in[59];
-    if( sid_len > in_len - 61 )
+    if( 59 + 1 + sid_len + 1 > in_len )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 4, ( "check cookie: sid_len=%u > %u",
+                                    (unsigned) sid_len,
+                                    (unsigned) in_len - 61 ) );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+    MBEDTLS_SSL_DEBUG_BUF( 4, "sid received from network",
+                           in + 60, sid_len );
 
     cookie_len = in[60 + sid_len];
-    if( cookie_len > in_len - 60 )
-        return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
-
-    if( f_cookie_check( p_cookie, in + sid_len + 61, cookie_len,
-                        cli_id, cli_id_len ) == 0 )
+    if( 59 + 1 + sid_len + 1 + cookie_len > in_len )
     {
-        /* Valid cookie */
+        MBEDTLS_SSL_DEBUG_MSG( 4, ( "check cookie: cookie_len=%u > %u",
+                                    (unsigned) cookie_len,
+                                    (unsigned) ( in_len - sid_len - 61 ) ) );
+        return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+
+    MBEDTLS_SSL_DEBUG_BUF( 4, "cookie received from network",
+                           in + sid_len + 61, cookie_len );
+    if( ssl->conf->f_cookie_check( ssl->conf->p_cookie,
+                                   in + sid_len + 61, cookie_len,
+                                   cli_id, cli_id_len ) == 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 4, ( "check cookie: valid" ) );
         return( 0 );
     }
 
@@ -3330,8 +3378,9 @@
 
     /* Generate and write actual cookie */
     p = obuf + 28;
-    if( f_cookie_write( p_cookie,
-                        &p, obuf + buf_len, cli_id, cli_id_len ) != 0 )
+    if( ssl->conf->f_cookie_write( ssl->conf->p_cookie,
+                                   &p, obuf + buf_len,
+                                   cli_id, cli_id_len ) != 0 )
     {
         return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
@@ -3370,6 +3419,7 @@
  * includes the case of MBEDTLS_ERR_SSL_CLIENT_RECONNECT and of unexpected
  * errors, and is the right thing to do in both cases).
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3385,15 +3435,13 @@
         return( 0 );
     }
 
-    ret = ssl_check_dtls_clihlo_cookie(
-            ssl->conf->f_cookie_write,
-            ssl->conf->f_cookie_check,
-            ssl->conf->p_cookie,
+    ret = mbedtls_ssl_check_dtls_clihlo_cookie(
+            ssl,
             ssl->cli_id, ssl->cli_id_len,
             ssl->in_buf, ssl->in_left,
             ssl->out_buf, MBEDTLS_SSL_OUT_CONTENT_LEN, &len );
 
-    MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret );
+    MBEDTLS_SSL_DEBUG_RET( 2, "mbedtls_ssl_check_dtls_clihlo_cookie", ret );
 
     if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
     {
@@ -3427,6 +3475,7 @@
 }
 #endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_record_type( uint8_t record_type )
 {
     if( record_type != MBEDTLS_SSL_MSG_HANDSHAKE &&
@@ -3459,6 +3508,7 @@
  * Point 2 is needed when the peer is resending, and we have already received
  * the first record from a datagram but are still waiting for the others.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_record_header( mbedtls_ssl_context const *ssl,
                                     unsigned char *buf,
                                     size_t len,
@@ -3571,7 +3621,6 @@
     /*
      * Parse and validate record version
      */
-
     rec->ver[0] = buf[ rec_hdr_version_offset + 0 ];
     rec->ver[1] = buf[ rec_hdr_version_offset + 1 ];
     mbedtls_ssl_read_version( &major_ver, &minor_ver,
@@ -3580,16 +3629,19 @@
 
     if( major_ver != ssl->major_ver )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "major version mismatch" ) );
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "major version mismatch: got %u, expected %u",
+                                    (unsigned) major_ver,
+                                    (unsigned) ssl->major_ver ) );
         return( MBEDTLS_ERR_SSL_INVALID_RECORD );
     }
 
     if( minor_ver > ssl->conf->max_minor_ver )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) );
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "minor version mismatch: got %u, expected max %u",
+                                    (unsigned) minor_ver,
+                                    (unsigned) ssl->conf->max_minor_ver ) );
         return( MBEDTLS_ERR_SSL_INVALID_RECORD );
     }
-
     /*
      * Parse/Copy record sequence number.
      */
@@ -3692,6 +3744,7 @@
 
 
 #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_client_reconnect( mbedtls_ssl_context *ssl )
 {
     unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1];
@@ -3721,6 +3774,7 @@
 /*
  * If applicable, decrypt record content
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_prepare_record_content( mbedtls_ssl_context *ssl,
                                        mbedtls_record *rec )
 {
@@ -3854,7 +3908,7 @@
 
     /* Check actual (decrypted) record content length against
      * configured maximum. */
-    if( ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN )
+    if( rec->data_len > MBEDTLS_SSL_IN_CONTENT_LEN )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
         return( MBEDTLS_ERR_SSL_INVALID_RECORD );
@@ -3872,8 +3926,11 @@
  */
 
 /* Helper functions for mbedtls_ssl_read_record(). */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_consume_current_message( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_get_next_record( mbedtls_ssl_context *ssl );
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl );
 
 int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
@@ -3961,6 +4018,7 @@
 }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl )
 {
     if( ssl->in_left > ssl->next_record_offset )
@@ -3969,6 +4027,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_load_buffered_message( mbedtls_ssl_context *ssl )
 {
     mbedtls_ssl_handshake_params * const hs = ssl->handshake;
@@ -4066,6 +4125,7 @@
     return( ret );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_buffer_make_space( mbedtls_ssl_context *ssl,
                                   size_t desired )
 {
@@ -4108,6 +4168,7 @@
     return( -1 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_buffer_message( mbedtls_ssl_context *ssl )
 {
     int ret = 0;
@@ -4312,6 +4373,7 @@
 }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_consume_current_message( mbedtls_ssl_context *ssl )
 {
     /*
@@ -4399,6 +4461,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl )
 {
     if( ssl->in_msglen > 0 )
@@ -4425,6 +4488,7 @@
     }
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_load_buffered_record( mbedtls_ssl_context *ssl )
 {
     mbedtls_ssl_handshake_params * const hs = ssl->handshake;
@@ -4482,6 +4546,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_buffer_future_record( mbedtls_ssl_context *ssl,
                                      mbedtls_record const *rec )
 {
@@ -4540,6 +4605,7 @@
 
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_get_next_record( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -5290,6 +5356,7 @@
 /*
  * Check record counters and renegotiate if they're above the limit.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl )
 {
     size_t ep_len = mbedtls_ssl_ep_len( ssl );
@@ -5640,6 +5707,7 @@
  * Therefore, it is possible that the input message length is 0 and the
  * corresponding return code is 0 on success.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_real( mbedtls_ssl_context *ssl,
                            const unsigned char *buf, size_t len )
 {
@@ -5711,6 +5779,7 @@
  * remember whether we already did the split or not.
  */
 #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_split( mbedtls_ssl_context *ssl,
                             const unsigned char *buf, size_t len )
 {
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index bce51cd..2efb13c 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -78,6 +78,7 @@
 #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
 
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl,
                                      const unsigned char *buf,
                                      size_t len )
@@ -147,6 +148,7 @@
 #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_conf_has_psk_or_cb( mbedtls_ssl_config const *conf )
 {
     if( conf->f_psk != NULL )
@@ -167,6 +169,7 @@
 }
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl )
 {
     if( ssl->conf->f_psk != NULL )
@@ -188,6 +191,7 @@
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -239,6 +243,7 @@
  * This needs to be done at a later stage.
  *
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_signature_algorithms_ext( mbedtls_ssl_context *ssl,
                                                const unsigned char *buf,
                                                size_t len )
@@ -317,6 +322,7 @@
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_supported_elliptic_curves( mbedtls_ssl_context *ssl,
                                                 const unsigned char *buf,
                                                 size_t len )
@@ -383,6 +389,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_supported_point_formats( mbedtls_ssl_context *ssl,
                                               const unsigned char *buf,
                                               size_t len )
@@ -425,6 +432,7 @@
           MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl,
                                    const unsigned char *buf,
                                    size_t len )
@@ -454,6 +462,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl,
                                               const unsigned char *buf,
                                               size_t len )
@@ -473,6 +482,7 @@
 #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
 
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_cid_ext( mbedtls_ssl_context *ssl,
                               const unsigned char *buf,
                               size_t len )
@@ -545,6 +555,7 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
 #if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl,
                                          const unsigned char *buf,
                                          size_t len )
@@ -567,6 +578,7 @@
 #endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
 
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl,
                                       const unsigned char *buf,
                                       size_t len )
@@ -592,6 +604,7 @@
 #endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
 
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl,
                                       const unsigned char *buf,
                                       size_t len )
@@ -617,6 +630,7 @@
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl,
                                          unsigned char *buf,
                                          size_t len )
@@ -691,6 +705,7 @@
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
 #if defined(MBEDTLS_SSL_ALPN)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl,
                                const unsigned char *buf, size_t len )
 {
@@ -779,6 +794,7 @@
 #endif /* MBEDTLS_SSL_ALPN */
 
 #if defined(MBEDTLS_SSL_DTLS_SRTP)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_use_srtp_ext( mbedtls_ssl_context *ssl,
                                    const unsigned char *buf,
                                    size_t len )
@@ -907,6 +923,7 @@
  * Return 0 if the given key uses one of the acceptable curves, -1 otherwise
  */
 #if defined(MBEDTLS_ECDSA_C)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_key_curve( mbedtls_pk_context *pk,
                                 const mbedtls_ecp_curve_info **curves )
 {
@@ -928,6 +945,7 @@
  * Try picking a certificate for this ciphersuite,
  * return 0 on success and -1 on failure.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_pick_cert( mbedtls_ssl_context *ssl,
                           const mbedtls_ssl_ciphersuite_t * ciphersuite_info )
 {
@@ -1032,6 +1050,7 @@
  * Check if a given ciphersuite is suitable for use with our config/keys/etc
  * Sets ciphersuite_info only if the suite matches.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_ciphersuite_match( mbedtls_ssl_context *ssl, int suite_id,
                                   const mbedtls_ssl_ciphersuite_t **ciphersuite_info )
 {
@@ -1147,6 +1166,7 @@
 }
 
 #if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl )
 {
     int ret, got_common_suite;
@@ -1410,6 +1430,7 @@
 /* This function doesn't alert on errors that happen early during
    ClientHello parsing because they might indicate that the client is
    not talking SSL/TLS at all and would not understand our alert. */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_client_hello( mbedtls_ssl_context *ssl )
 {
     int ret, got_common_suite;
@@ -1604,11 +1625,19 @@
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d",
                    ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) );
 
-    /* We don't support fragmentation of ClientHello (yet?) */
-    if( buf[1] != 0 ||
-        msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) )
+    if( buf[1] != 0 )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message: %u != 0",
+                                    (unsigned) buf[1] ) );
+        return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
+    }
+    /* We don't support fragmentation of ClientHello (yet?) */
+    if( msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message: %u != %u + %u",
+                                    (unsigned) msg_len,
+                                    (unsigned) mbedtls_ssl_hs_hdr_len( ssl ),
+                                    (unsigned) ( buf[2] << 8 ) | buf[3] ) );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1649,6 +1678,11 @@
          * For now we don't support fragmentation, so make sure
          * fragment_offset == 0 and fragment_length == length
          */
+        MBEDTLS_SSL_DEBUG_MSG(
+            4, ( "fragment_offset=%u fragment_length=%u length=%u",
+                 (unsigned) ( ssl->in_msg[6] << 16 | ssl->in_msg[7] << 8 | ssl->in_msg[8] ),
+                 (unsigned) ( ssl->in_msg[9] << 16 | ssl->in_msg[10] << 8 | ssl->in_msg[11] ),
+                 (unsigned) ( ssl->in_msg[1] << 16 | ssl->in_msg[2] << 8 | ssl->in_msg[3] ) ) );
         if( ssl->in_msg[6] != 0 || ssl->in_msg[7] != 0 || ssl->in_msg[8] != 0 ||
             memcmp( ssl->in_msg + 1, ssl->in_msg + 9, 3 ) != 0 )
         {
@@ -2686,6 +2720,7 @@
 #endif /* MBEDTLS_SSL_DTLS_SRTP */
 
 #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -2806,6 +2841,7 @@
     mbedtls_ssl_session_free( &session_tmp );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_server_hello( mbedtls_ssl_context *ssl )
 {
 #if defined(MBEDTLS_HAVE_TIME)
@@ -3036,6 +3072,7 @@
 }
 
 #if !defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -3054,6 +3091,7 @@
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
 #else /* !MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -3223,18 +3261,23 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    mbedtls_pk_context *own_key = mbedtls_ssl_own_key( ssl );
 
-    if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECKEY ) )
+    /* Check if the key is a transparent ECDH key.
+     * This also ensures that it is safe to call mbedtls_pk_ec(). */
+    if( mbedtls_pk_get_type( own_key ) != MBEDTLS_PK_ECKEY &&
+        mbedtls_pk_get_type( own_key ) != MBEDTLS_PK_ECKEY_DH )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) );
         return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
     }
 
     if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx,
-                                 mbedtls_pk_ec( *mbedtls_ssl_own_key( ssl ) ),
+                                 mbedtls_pk_ec( *own_key ),
                                  MBEDTLS_ECDH_OURS ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret );
@@ -3248,6 +3291,7 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED) && \
     defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl,
                                            size_t *signature_len )
 {
@@ -3275,6 +3319,7 @@
 /* Prepare the ServerKeyExchange message, up to and including
  * calculating the signature if any, but excluding formatting the
  * signature and sending the message. */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl,
                                             size_t *signature_len )
 {
@@ -3644,6 +3689,7 @@
  * that do not include a ServerKeyExchange message, do nothing. Either
  * way, if successful, move on to the next step in the SSL state
  * machine. */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3665,7 +3711,12 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_ENABLED)
         if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) )
         {
-            ssl_get_ecdh_params_from_cert( ssl );
+            ret = ssl_get_ecdh_params_from_cert( ssl );
+            if( ret != 0 )
+            {
+                MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret );
+                return( ret );
+            }
         }
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_ENABLED */
 
@@ -3741,6 +3792,7 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_server_hello_done( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3780,6 +3832,7 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) ||                       \
     defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char **p,
                                        const unsigned char *end )
 {
@@ -3823,6 +3876,7 @@
     defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
 
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl,
                                    unsigned char *peer_pms,
                                    size_t *peer_pmslen,
@@ -3840,6 +3894,7 @@
 }
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
                                       const unsigned char *p,
                                       const unsigned char *end,
@@ -3932,6 +3987,7 @@
     return( ret );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
                                     const unsigned char *p,
                                     const unsigned char *end,
@@ -4021,6 +4077,7 @@
           MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned char **p,
                                           const unsigned char *end )
 {
@@ -4081,6 +4138,7 @@
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -4248,7 +4306,10 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         /* Opaque PSKs are currently only supported for PSK-only. */
         if( ssl_use_opaque_psk( ssl ) == 1 )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "opaque PSK not supported with RSA-PSK" ) );
             return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
 #endif
 
         if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 2 ) ) != 0 )
@@ -4283,7 +4344,10 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         /* Opaque PSKs are currently only supported for PSK-only. */
         if( ssl_use_opaque_psk( ssl ) == 1 )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "opaque PSK not supported with DHE-PSK" ) );
             return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
 #endif
 
         if( p != end )
@@ -4320,7 +4384,10 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         /* Opaque PSKs are currently only supported for PSK-only. */
         if( ssl_use_opaque_psk( ssl ) == 1 )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "opaque PSK not supported with ECDHE-PSK" ) );
             return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
 #endif
 
         MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx,
@@ -4387,6 +4454,7 @@
 }
 
 #if !defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -4405,6 +4473,7 @@
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
 #else /* !MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -4598,6 +4667,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index 5680a0b..e0126cc 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -66,6 +66,7 @@
 /*
  * Generate/update a key
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
                                unsigned char index )
 {
@@ -96,6 +97,7 @@
 /*
  * Rotate/generate keys if necessary
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
 {
 #if !defined(MBEDTLS_HAVE_TIME)
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index b0379cd..7badec5 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -245,6 +245,7 @@
 }
 
 #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int resize_buffer( unsigned char **buffer, size_t len_new, size_t *len_old )
 {
     unsigned char* resized_buffer = mbedtls_calloc( 1, len_new );
@@ -337,6 +338,7 @@
  * Key material generation
  */
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl3_prf( const unsigned char *secret, size_t slen,
                      const char *label,
                      const unsigned char *random, size_t rlen,
@@ -398,6 +400,7 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls1_prf( const unsigned char *secret, size_t slen,
                      const char *label,
                      const unsigned char *random, size_t rlen,
@@ -605,6 +608,7 @@
     return( PSA_SUCCESS );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls_prf_generic( mbedtls_md_type_t md_type,
                             const unsigned char *secret, size_t slen,
                             const char *label,
@@ -679,6 +683,7 @@
 
 #else /* MBEDTLS_USE_PSA_CRYPTO */
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls_prf_generic( mbedtls_md_type_t md_type,
                             const unsigned char *secret, size_t slen,
                             const char *label,
@@ -770,6 +775,7 @@
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_SHA256_C)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls_prf_sha256( const unsigned char *secret, size_t slen,
                            const char *label,
                            const unsigned char *random, size_t rlen,
@@ -781,6 +787,7 @@
 #endif /* MBEDTLS_SHA256_C */
 
 #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls_prf_sha384( const unsigned char *secret, size_t slen,
                            const char *label,
                            const unsigned char *random, size_t rlen,
@@ -825,6 +832,7 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \
     defined(MBEDTLS_USE_PSA_CRYPTO)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl )
 {
     if( ssl->conf->f_psk != NULL )
@@ -949,6 +957,7 @@
  *        - MBEDTLS_SSL_EXPORT_KEYS: ssl->conf->{f,p}_export_keys
  *        - MBEDTLS_DEBUG_C: ssl->conf->{f,p}_dbg
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_populate_transform( mbedtls_ssl_transform *transform,
                                    int ciphersuite,
                                    const unsigned char master[48],
@@ -1512,6 +1521,7 @@
  * Outputs:
  * - the tls_prf, calc_verify and calc_finished members of handshake structure
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_set_handshake_prfs( mbedtls_ssl_handshake_params *handshake,
                                    int minor_ver,
                                    mbedtls_md_type_t hash )
@@ -1581,6 +1591,7 @@
  *      EMS: passed to calc_verify (debug + (SSL3) session_negotiate)
  *      PSA-PSA: minor_ver, conf
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_compute_master( mbedtls_ssl_handshake_params *handshake,
                                unsigned char *master,
                                const mbedtls_ssl_context *ssl )
@@ -2109,6 +2120,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */
 
 #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_hello_request( mbedtls_ssl_context *ssl );
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
@@ -2324,6 +2336,7 @@
 #if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
 
 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
                                          unsigned char *crt_buf,
                                          size_t crt_buf_len )
@@ -2339,6 +2352,7 @@
     return( memcmp( peer_crt->raw.p, crt_buf, peer_crt->raw.len ) );
 }
 #else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
                                          unsigned char *crt_buf,
                                          size_t crt_buf_len )
@@ -2373,6 +2387,7 @@
  * Once the certificate message is read, parse it into a cert chain and
  * perform basic checks, but leave actual verification to the caller
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl,
                                         mbedtls_x509_crt *chain )
 {
@@ -2522,6 +2537,7 @@
 }
 
 #if defined(MBEDTLS_SSL_SRV_C)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_srv_check_client_no_crt_notification( mbedtls_ssl_context *ssl )
 {
     if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
@@ -2571,6 +2587,7 @@
  */
 #define SSL_CERTIFICATE_EXPECTED 0
 #define SSL_CERTIFICATE_SKIP     1
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl,
                                              int authmode )
 {
@@ -2600,6 +2617,7 @@
     return( SSL_CERTIFICATE_EXPECTED );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
                                          int authmode,
                                          mbedtls_x509_crt *chain,
@@ -2697,7 +2715,9 @@
     {
         const mbedtls_pk_context *pk = &chain->pk;
 
-        /* If certificate uses an EC key, make sure the curve is OK */
+        /* If certificate uses an EC key, make sure the curve is OK.
+         * This is a public key, so it can't be opaque, so can_do() is a good
+         * enough check to ensure pk_ec() is safe to use here. */
         if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
             mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
         {
@@ -2788,6 +2808,7 @@
 }
 
 #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_remember_peer_crt_digest( mbedtls_ssl_context *ssl,
                                          unsigned char *start, size_t len )
 {
@@ -2819,6 +2840,7 @@
     return( ret );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_remember_peer_pubkey( mbedtls_ssl_context *ssl,
                                      unsigned char *start, size_t len )
 {
@@ -3797,6 +3819,7 @@
     memset( session, 0, sizeof(mbedtls_ssl_session) );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_handshake_init( mbedtls_ssl_context *ssl )
 {
     /* Clear old handshake information if present */
@@ -3874,6 +3897,7 @@
 
 #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
 /* Dummy cookie callbacks for defaults */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_cookie_write_dummy( void *ctx,
                       unsigned char **p, unsigned char *end,
                       const unsigned char *cli_id, size_t cli_id_len )
@@ -3887,6 +3911,7 @@
     return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_cookie_check_dummy( void *ctx,
                       const unsigned char *cookie, size_t cookie_len,
                       const unsigned char *cli_id, size_t cli_id_len )
@@ -4304,6 +4329,7 @@
 }
 
 /* Append a new keycert entry to a (possibly empty) list */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_append_key_cert( mbedtls_ssl_key_cert **head,
                                 mbedtls_x509_crt *cert,
                                 mbedtls_pk_context *key )
@@ -4472,6 +4498,7 @@
  * It checks that the provided identity is well-formed and attempts
  * to make a copy of it in the SSL config.
  * On failure, the PSK identity in the config remains unset. */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_conf_set_psk_identity( mbedtls_ssl_config *conf,
                                       unsigned char const *psk_identity,
                                       size_t psk_identity_len )
@@ -5391,6 +5418,7 @@
  * verify_result is put before peer_cert so that all mandatory fields come
  * together in one block.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_session_save( const mbedtls_ssl_session *session,
                              unsigned char omit_header,
                              unsigned char *buf,
@@ -5590,6 +5618,7 @@
  * This internal version is wrapped by a public function that cleans up in
  * case of error, and has an extra option omit_header.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_session_load( mbedtls_ssl_session *session,
                              unsigned char omit_header,
                              const unsigned char *buf,
@@ -5893,6 +5922,7 @@
 /*
  * Write HelloRequest to request renegotiation on server
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_write_hello_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -6504,6 +6534,7 @@
  * This internal version is wrapped by a public function that cleans up in
  * case of error.
  */
+MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_context_load( mbedtls_ssl_context *ssl,
                              const unsigned char *buf,
                              size_t len )
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index e08bde6..4f07660 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -1420,17 +1420,6 @@
 #if defined (MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
         if( opt.psk_opaque != 0 )
         {
-            /* Ensure that the chosen ciphersuite is PSK-only; we must know
-             * the ciphersuite in advance to set the correct policy for the
-             * PSK key slot. This limitation might go away in the future. */
-            if( ciphersuite_info->key_exchange != MBEDTLS_KEY_EXCHANGE_PSK ||
-                opt.min_version != MBEDTLS_SSL_MINOR_VERSION_3 )
-            {
-                mbedtls_printf( "opaque PSKs are only supported in conjunction with forcing TLS 1.2 and a PSK-only ciphersuite through the 'force_ciphersuite' option.\n" );
-                ret = 2;
-                goto usage;
-            }
-
             /* Determine KDF algorithm the opaque PSK will be used in. */
 #if defined(MBEDTLS_SHA512_C)
             if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
@@ -1672,7 +1661,7 @@
     if( opt.key_opaque != 0 )
     {
         if( ( ret = mbedtls_pk_wrap_as_opaque( &pkey, &key_slot,
-                                               PSA_ALG_SHA_256 ) ) != 0 )
+                                               PSA_ALG_ANY_HASH ) ) != 0 )
         {
             mbedtls_printf( " failed\n  !  "
                             "mbedtls_pk_wrap_as_opaque returned -0x%x\n\n", (unsigned int)  -ret );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index cc1751d..6169a37 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -82,6 +82,7 @@
 #define DFL_CA_PATH             ""
 #define DFL_CRT_FILE            ""
 #define DFL_KEY_FILE            ""
+#define DFL_KEY_OPAQUE          0
 #define DFL_KEY_PWD             ""
 #define DFL_CRT_FILE2           ""
 #define DFL_KEY_FILE2           ""
@@ -199,6 +200,13 @@
 #else
 #define USAGE_IO ""
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_X509_CRT_PARSE_C)
+#define USAGE_KEY_OPAQUE \
+    "    key_opaque=%%d       Handle your private keys as if they were opaque\n" \
+    "                        default: 0 (disabled)\n"
+#else
+#define USAGE_KEY_OPAQUE ""
+#endif
 
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
 #define USAGE_SSL_ASYNC \
@@ -481,6 +489,7 @@
     "    cert_req_ca_list=%%d default: 1 (send ca list)\n"  \
     "                        options: 1 (send ca list), 0 (don't send)\n" \
     USAGE_IO                                                \
+    USAGE_KEY_OPAQUE                                        \
     "\n"                                                    \
     USAGE_PSK                                               \
     USAGE_CA_CALLBACK                                       \
@@ -559,6 +568,7 @@
     const char *ca_path;        /* the path with the CA certificate(s) reside */
     const char *crt_file;       /* the file with the server certificate     */
     const char *key_file;       /* the file with the server key             */
+    int key_opaque;             /* handle private key as if it were opaque  */
     const char *key_pwd;        /* the password for the server key          */
     const char *crt_file2;      /* the file with the 2nd server certificate */
     const char *key_file2;      /* the file with the 2nd server key         */
@@ -1310,6 +1320,10 @@
     mbedtls_pk_context pkey;
     mbedtls_x509_crt srvcert2;
     mbedtls_pk_context pkey2;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_key_id_t key_slot = 0; /* invalid key slot */
+    psa_key_id_t key_slot2 = 0; /* invalid key slot */
+#endif
     int key_cert_init = 0, key_cert_init2 = 0;
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
     ssl_async_key_context_t ssl_async_keys;
@@ -1480,6 +1494,7 @@
     opt.ca_path             = DFL_CA_PATH;
     opt.crt_file            = DFL_CRT_FILE;
     opt.key_file            = DFL_KEY_FILE;
+    opt.key_opaque          = DFL_KEY_OPAQUE;
     opt.key_pwd             = DFL_KEY_PWD;
     opt.crt_file2           = DFL_CRT_FILE2;
     opt.key_file2           = DFL_KEY_FILE2;
@@ -1611,6 +1626,10 @@
             opt.key_file = q;
         else if( strcmp( p, "key_pwd" ) == 0 )
             opt.key_pwd = q;
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_X509_CRT_PARSE_C)
+        else if( strcmp( p, "key_opaque" ) == 0 )
+            opt.key_opaque = atoi( q );
+#endif
         else if( strcmp( p, "crt_file2" ) == 0 )
             opt.crt_file2 = q;
         else if( strcmp( p, "key_file2" ) == 0 )
@@ -2143,17 +2162,6 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
         if( opt.psk_opaque != 0 || opt.psk_list_opaque != 0 )
         {
-            /* Ensure that the chosen ciphersuite is PSK-only; we must know
-             * the ciphersuite in advance to set the correct policy for the
-             * PSK key slot. This limitation might go away in the future. */
-            if( ciphersuite_info->key_exchange != MBEDTLS_KEY_EXCHANGE_PSK ||
-                opt.min_version != MBEDTLS_SSL_MINOR_VERSION_3 )
-            {
-                mbedtls_printf( "opaque PSKs are only supported in conjunction with forcing TLS 1.2 and a PSK-only ciphersuite through the 'force_ciphersuite' option.\n" );
-                ret = 2;
-                goto usage;
-            }
-
             /* Determine KDF algorithm the opaque PSK will be used in. */
 #if defined(MBEDTLS_SHA512_C)
             if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
@@ -2503,10 +2511,37 @@
         }
         key_cert_init2 = 2;
 #endif /* MBEDTLS_ECDSA_C */
-#endif /* MBEDTLS_CERTS_C */
     }
 
-    mbedtls_printf( " ok\n" );
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( opt.key_opaque != 0 )
+    {
+        if ( mbedtls_pk_get_type( &pkey ) == MBEDTLS_PK_ECKEY )
+        {
+            if( ( ret = mbedtls_pk_wrap_as_opaque( &pkey, &key_slot,
+                                                PSA_ALG_ANY_HASH ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  !  "
+                                "mbedtls_pk_wrap_as_opaque returned -0x%x\n\n", (unsigned int)  -ret );
+                goto exit;
+            }
+        }
+
+        if ( mbedtls_pk_get_type( &pkey2 ) == MBEDTLS_PK_ECKEY )
+        {
+            if( ( ret = mbedtls_pk_wrap_as_opaque( &pkey2, &key_slot2,
+                                                PSA_ALG_ANY_HASH ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  !  "
+                                "mbedtls_pk_wrap_as_opaque returned -0x%x\n\n", (unsigned int)  -ret );
+                goto exit;
+            }
+        }
+    }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#endif /* MBEDTLS_CERTS_C */
+
+    mbedtls_printf( " ok (key types: %s - %s)\n", mbedtls_pk_get_name( &pkey ), mbedtls_pk_get_name( &pkey2 ) );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
@@ -4001,6 +4036,10 @@
     mbedtls_pk_free( &pkey );
     mbedtls_x509_crt_free( &srvcert2 );
     mbedtls_pk_free( &pkey2 );
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_destroy_key( key_slot );
+    psa_destroy_key( key_slot2 );
+#endif
 #endif
 
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 7289acf..7199462 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1623,15 +1623,150 @@
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SHA256_C
 run_test    "Opaque key for client authentication" \
-            "$P_SRV auth_mode=required" \
+            "$P_SRV auth_mode=required crt_file=data_files/server5.crt \
+             key_file=data_files/server5.key" \
             "$P_CLI key_opaque=1 crt_file=data_files/server5.crt \
              key_file=data_files/server5.key" \
             0 \
             -c "key type: Opaque" \
+            -c "Ciphersuite is TLS-ECDHE-ECDSA" \
             -s "Verifying peer X.509 certificate... ok" \
+            -s "Ciphersuite is TLS-ECDHE-ECDSA" \
             -S "error" \
             -C "error"
 
+# Test using an opaque private key for server authentication
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_X509_CRT_PARSE_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+run_test    "Opaque key for server authentication" \
+            "$P_SRV auth_mode=required key_opaque=1 crt_file=data_files/server5.crt \
+             key_file=data_files/server5.key" \
+            "$P_CLI crt_file=data_files/server5.crt \
+             key_file=data_files/server5.key" \
+            0 \
+            -c "Verifying peer X.509 certificate... ok" \
+            -c "Ciphersuite is TLS-ECDHE-ECDSA" \
+            -s "key types: Opaque - invalid PK" \
+            -s "Ciphersuite is TLS-ECDHE-ECDSA" \
+            -S "error" \
+            -C "error"
+
+# Test using an opaque private key for client/server authentication
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_X509_CRT_PARSE_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+run_test    "Opaque key for client/server authentication" \
+            "$P_SRV auth_mode=required key_opaque=1 crt_file=data_files/server5.crt \
+             key_file=data_files/server5.key" \
+            "$P_CLI key_opaque=1 crt_file=data_files/server5.crt \
+             key_file=data_files/server5.key" \
+            0 \
+            -c "key type: Opaque" \
+            -c "Verifying peer X.509 certificate... ok" \
+            -c "Ciphersuite is TLS-ECDHE-ECDSA" \
+            -s "key types: Opaque - invalid PK" \
+            -s "Verifying peer X.509 certificate... ok" \
+            -s "Ciphersuite is TLS-ECDHE-ECDSA" \
+            -S "error" \
+            -C "error"
+
+# Opaque keys not supported for static ECDH
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_X509_CRT_PARSE_C
+run_test    "Opaque key: server: ECDH-ECDSA not supported" \
+            "$P_SRV debug_level=1 key_opaque=1
+             crt_file=data_files/server5.crt key_file=data_files/server5.key" \
+            "$P_CLI force_ciphersuite=TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256" \
+            1 \
+            -s "server key not ECDH capable" \
+            -s "ssl_get_ecdh_params_from_cert() returned" \
+            -s "error" \
+            -c "error"
+
+# Opaque keys not supported for static ECDH
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_X509_CRT_PARSE_C
+run_test    "Opaque key: server: ECDH-RSA not supported" \
+            "$P_SRV debug_level=1 key_opaque=1
+             crt_file=data_files/server5.crt key_file=data_files/server5.key" \
+            "$P_CLI force_ciphersuite=TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256" \
+            1 \
+            -s "server key not ECDH capable" \
+            -s "ssl_get_ecdh_params_from_cert() returned" \
+            -s "error" \
+            -c "error"
+
+# Opaque PSKs not supported for mixed PSK
+
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "Opaque psk: client: ECDHE-PSK not supported" \
+            "$P_SRV debug_level=1 psk=abc123 psk_identity=foo" \
+            "$P_CLI debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 \
+            force_version=tls12 \
+            force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA" \
+            1 \
+            -c "opaque PSK not supported with ECDHE-PSK" \
+            -s "error" \
+            -c "error"
+
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "Opaque psk: client: DHE-PSK not supported" \
+            "$P_SRV debug_level=1 psk=abc123 psk_identity=foo" \
+            "$P_CLI debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 \
+            force_version=tls12 \
+            force_ciphersuite=TLS-DHE-PSK-WITH-AES-128-CBC-SHA" \
+            1 \
+            -c "opaque PSK not supported with DHE-PSK" \
+            -s "error" \
+            -c "error"
+
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "Opaque psk: client: RSA-PSK not supported" \
+            "$P_SRV debug_level=1 psk=abc123 psk_identity=foo" \
+            "$P_CLI debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 \
+            force_version=tls12 \
+            force_ciphersuite=TLS-RSA-PSK-WITH-AES-128-CBC-SHA" \
+            1 \
+            -c "opaque PSK not supported with RSA-PSK" \
+            -s "error" \
+            -c "error"
+
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "Opaque psk: server: ECDHE-PSK not supported" \
+            "$P_SRV debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 \
+            force_version=tls12 \
+            force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA" \
+            "$P_CLI debug_level=1 psk=abc123 psk_identity=foo" \
+            1 \
+            -s "opaque PSK not supported with ECDHE-PSK" \
+            -s "error" \
+            -c "error"
+
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "Opaque psk: server: DHE-PSK not supported" \
+            "$P_SRV debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 \
+            force_version=tls12 \
+            force_ciphersuite=TLS-DHE-PSK-WITH-AES-128-CBC-SHA" \
+            "$P_CLI debug_level=1 psk=abc123 psk_identity=foo" \
+            1 \
+            -s "opaque PSK not supported with DHE-PSK" \
+            -s "error" \
+            -c "error"
+
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "Opaque psk: server: RSA-PSK not supported" \
+            "$P_SRV debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 \
+            force_version=tls12 \
+            force_ciphersuite=TLS-RSA-PSK-WITH-AES-128-CBC-SHA" \
+            "$P_CLI debug_level=1 psk=abc123 psk_identity=foo" \
+            1 \
+            -s "opaque PSK not supported with RSA-PSK" \
+            -s "error" \
+            -c "error"
+
 # Test ciphersuites which we expect to be fully supported by PSA Crypto
 # and check that we don't fall back to Mbed TLS' internal crypto primitives.
 run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CCM
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 2addd23..f2a8656 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -73,12 +73,18 @@
 Test mpi_read_write_string #9 (Empty MPI hex -> dec)
 mpi_read_write_string:16:"":10:"0":4:0:0
 
+Test mpi_read_write_string #9 (Empty MPI hex -> base 2)
+mpi_read_write_string:16:"":2:"0":4:0:0
+
 Test mpi_read_write_string #8 (Empty MPI dec -> hex)
 mpi_read_write_string:10:"":16:"":4:0:0
 
 Test mpi_read_write_string #9 (Empty MPI dec -> dec)
 mpi_read_write_string:10:"":10:"0":4:0:0
 
+Test mpi_read_write_string #9 (Empty MPI dec -> base 2)
+mpi_read_write_string:16:"":2:"0":4:0:0
+
 Test mpi_write_string #10 (Negative hex with odd number of digits)
 mpi_read_write_string:16:"-1":16:"":3:0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
 
@@ -1222,9 +1228,15 @@
 Test mbedtls_mpi_mod_int: 0 (null) % 1
 mbedtls_mpi_mod_int:16:"":1:0:0
 
+Test mbedtls_mpi_mod_int: 0 (null) % 2
+mbedtls_mpi_mod_int:16:"":2:0:0
+
 Test mbedtls_mpi_mod_int: 0 (null) % -1
 mbedtls_mpi_mod_int:16:"":-1:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
+Test mbedtls_mpi_mod_int: 0 (null) % -2
+mbedtls_mpi_mod_int:16:"":-2:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
 Base test mbedtls_mpi_exp_mod #1
 mbedtls_mpi_exp_mod:10:"23":10:"13":10:"29":10:"24":0
 
diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data
index 0f32671..0e97e6f 100644
--- a/tests/suites/test_suite_ssl.data
+++ b/tests/suites/test_suite_ssl.data
@@ -10689,3 +10689,21 @@
 
 Raw key agreement: bad server key
 raw_key_agreement_fail:1
+
+Cookie parsing: nominal run
+cookie_parsing:"16fefd0000000000000000002F010000de000000000000011efefd7b7272727272727272727272727272727272727272727272727272727272727d00200000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_ERR_SSL_INTERNAL_ERROR
+
+Cookie parsing: cookie_len overflow
+cookie_parsing:"16fefd000000000000000000ea010000de000000000000011efefd7b7272727272727272727272727272727272727272727272727272727272727db97b7373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737db963":MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
+
+Cookie parsing: non-zero fragment offset
+cookie_parsing:"16fefd00000000000000000032010000de000072000000011efefd7b7272727272727272727272727272727272727272727272727272727272727d01730143":MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
+
+Cookie parsing: sid_len overflow
+cookie_parsing:"16fefd00000000000000000032010000de000000000000011efefd7b7272727272727272727272727272727272727272727272727272727272727dFF730143":MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
+
+Cookie parsing: record too short
+cookie_parsing:"16fefd0000000000000000002f010000de000000000000011efefd7b7272727272727272727272727272727272727272727272727272727272727dFF":MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
+
+Cookie parsing: one byte overread
+cookie_parsing:"16fefd0000000000000000002F010000de000000000000011efefd7b7272727272727272727272727272727272727272727272727272727272727d0001":MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 8318df0..a1e660f 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -4624,3 +4624,31 @@
     USE_PSA_DONE( );
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE:MBEDTLS_TEST_HOOKS */
+void cookie_parsing( data_t *cookie, int exp_ret )
+{
+    mbedtls_ssl_context ssl;
+    mbedtls_ssl_config conf;
+    size_t len;
+
+    mbedtls_ssl_init( &ssl );
+    mbedtls_ssl_config_init( &conf );
+    TEST_EQUAL( mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_SERVER,
+                                             MBEDTLS_SSL_TRANSPORT_DATAGRAM,
+                                             MBEDTLS_SSL_PRESET_DEFAULT ),
+                0 );
+
+    TEST_EQUAL( mbedtls_ssl_setup( &ssl, &conf ), 0 );
+    TEST_EQUAL( mbedtls_ssl_check_dtls_clihlo_cookie( &ssl, ssl.cli_id,
+                                                  ssl.cli_id_len,
+                                                  cookie->x, cookie->len,
+                                                  ssl.out_buf,
+                                                  MBEDTLS_SSL_OUT_CONTENT_LEN,
+                                                  &len ),
+                exp_ret );
+
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_config_free( &conf );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index f216edc..b0a20b5 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compile time library version
-check_compiletime_version:"2.28.0"
+check_compiletime_version:"2.28.1"
 
 Check runtime library version
-check_runtime_version:"2.28.0"
+check_runtime_version:"2.28.1"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0