You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ut...@apache.org on 2019/01/04 14:08:42 UTC

[mynewt-core] branch master updated: Update mbedTLS to 2.14.1

This is an automated email from the ASF dual-hosted git repository.

utzig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git


The following commit(s) were added to refs/heads/master by this push:
     new 3f7decc  Update mbedTLS to 2.14.1
3f7decc is described below

commit 3f7decc303d72f8f2821884f99f4e0fb8982afff
Author: Fabio Utzig <ut...@apache.org>
AuthorDate: Tue Dec 18 12:58:21 2018 -0200

    Update mbedTLS to 2.14.1
    
    https://tls.mbed.org/tech-updates/releases/mbedtls-2.14.1-2.7.8-and-2.1.17-released
---
 crypto/mbedtls/include/mbedtls/aes.h           |    4 +
 crypto/mbedtls/include/mbedtls/arc4.h          |    1 +
 crypto/mbedtls/include/mbedtls/aria.h          |    5 +
 crypto/mbedtls/include/mbedtls/asn1write.h     |  310 +++++---
 crypto/mbedtls/include/mbedtls/bignum.h        |   61 +-
 crypto/mbedtls/include/mbedtls/blowfish.h      |    4 +
 crypto/mbedtls/include/mbedtls/bn_mul.h        |   22 +-
 crypto/mbedtls/include/mbedtls/camellia.h      |    3 +
 crypto/mbedtls/include/mbedtls/ccm.h           |    2 +
 crypto/mbedtls/include/mbedtls/chacha20.h      |    6 +
 crypto/mbedtls/include/mbedtls/check_config.h  |   10 +
 crypto/mbedtls/include/mbedtls/cipher.h        |    2 +
 crypto/mbedtls/include/mbedtls/cmac.h          |    1 +
 crypto/mbedtls/include/mbedtls/config.h        |   80 +-
 crypto/mbedtls/include/mbedtls/ctr_drbg.h      |   54 +-
 crypto/mbedtls/include/mbedtls/des.h           |    2 +
 crypto/mbedtls/include/mbedtls/dhm.h           |    3 +
 crypto/mbedtls/include/mbedtls/ecdh.h          |   43 +-
 crypto/mbedtls/include/mbedtls/ecdsa.h         |  131 ++-
 crypto/mbedtls/include/mbedtls/ecp.h           |  229 ++++++
 crypto/mbedtls/include/mbedtls/error.h         |    7 +-
 crypto/mbedtls/include/mbedtls/gcm.h           |   14 +-
 crypto/mbedtls/include/mbedtls/hmac_drbg.h     |   22 +-
 crypto/mbedtls/include/mbedtls/md.h            |    2 +
 crypto/mbedtls/include/mbedtls/md2.h           |    1 +
 crypto/mbedtls/include/mbedtls/md4.h           |    1 +
 crypto/mbedtls/include/mbedtls/md5.h           |    1 +
 crypto/mbedtls/include/mbedtls/pk.h            |   85 +-
 crypto/mbedtls/include/mbedtls/pk_internal.h   |   23 +
 crypto/mbedtls/include/mbedtls/platform.h      |    5 +-
 crypto/mbedtls/include/mbedtls/platform_util.h |   41 +
 crypto/mbedtls/include/mbedtls/poly1305.h      |    6 +
 crypto/mbedtls/include/mbedtls/ripemd160.h     |    2 +
 crypto/mbedtls/include/mbedtls/rsa.h           |   47 +-
 crypto/mbedtls/include/mbedtls/sha1.h          |    1 +
 crypto/mbedtls/include/mbedtls/sha256.h        |    1 +
 crypto/mbedtls/include/mbedtls/sha512.h        |    1 +
 crypto/mbedtls/include/mbedtls/ssl.h           |  209 +++--
 crypto/mbedtls/include/mbedtls/ssl_internal.h  |   21 +-
 crypto/mbedtls/include/mbedtls/threading.h     |   14 +
 crypto/mbedtls/include/mbedtls/version.h       |   10 +-
 crypto/mbedtls/include/mbedtls/x509_crt.h      |  100 +++
 crypto/mbedtls/include/mbedtls/xtea.h          |    2 +
 crypto/mbedtls/src/aes.c                       |   13 +-
 crypto/mbedtls/src/asn1write.c                 |   31 +-
 crypto/mbedtls/src/bignum.c                    |  133 +++-
 crypto/mbedtls/src/certs.c                     |   43 +-
 crypto/mbedtls/src/cipher.c                    |   15 +-
 crypto/mbedtls/src/cipher_wrap.c               |    6 +-
 crypto/mbedtls/src/ctr_drbg.c                  |  145 +++-
 crypto/mbedtls/src/ecdh.c                      |  156 +++-
 crypto/mbedtls/src/ecdsa.c                     |  500 ++++++++++--
 crypto/mbedtls/src/ecp.c                       | 1009 +++++++++++++++++++-----
 crypto/mbedtls/src/error.c                     |   15 +
 crypto/mbedtls/src/gcm.c                       |    5 +-
 crypto/mbedtls/src/hmac_drbg.c                 |   93 ++-
 crypto/mbedtls/src/pk.c                        |  137 +++-
 crypto/mbedtls/src/pk_wrap.c                   |  200 ++++-
 crypto/mbedtls/src/pkparse.c                   |   36 +-
 crypto/mbedtls/src/platform.c                  |   13 +-
 crypto/mbedtls/src/platform_util.c             |   68 ++
 crypto/mbedtls/src/rsa.c                       |  282 +++++--
 crypto/mbedtls/src/rsa_internal.c              |    9 +-
 crypto/mbedtls/src/ssl_cli.c                   |  113 ++-
 crypto/mbedtls/src/ssl_ticket.c                |    2 +-
 crypto/mbedtls/src/ssl_tls.c                   |  199 +++--
 crypto/mbedtls/src/threading.c                 |   47 ++
 crypto/mbedtls/src/timing.c                    |   12 +-
 crypto/mbedtls/src/version_features.c          |    3 +
 crypto/mbedtls/src/x509.c                      |   11 +-
 crypto/mbedtls/src/x509_create.c               |  171 ++--
 crypto/mbedtls/src/x509_crt.c                  |  677 +++++++++++-----
 72 files changed, 4577 insertions(+), 1156 deletions(-)

diff --git a/crypto/mbedtls/include/mbedtls/aes.h b/crypto/mbedtls/include/mbedtls/aes.h
index 4c8dab3..cfb20c4 100644
--- a/crypto/mbedtls/include/mbedtls/aes.h
+++ b/crypto/mbedtls/include/mbedtls/aes.h
@@ -60,7 +60,11 @@
 
 /* Error codes in range 0x0021-0x0025 */
 #define MBEDTLS_ERR_AES_BAD_INPUT_DATA                    -0x0021  /**< Invalid input data. */
+
+/* MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE is deprecated and should not be used. */
 #define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE               -0x0023  /**< Feature not available. For example, an unsupported AES key size. */
+
+/* MBEDTLS_ERR_AES_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_AES_HW_ACCEL_FAILED                   -0x0025  /**< AES hardware accelerator failed. */
 
 #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
diff --git a/crypto/mbedtls/include/mbedtls/arc4.h b/crypto/mbedtls/include/mbedtls/arc4.h
index 83a7461..c43f406 100644
--- a/crypto/mbedtls/include/mbedtls/arc4.h
+++ b/crypto/mbedtls/include/mbedtls/arc4.h
@@ -36,6 +36,7 @@
 
 #include <stddef.h>
 
+/* MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED                  -0x0019  /**< ARC4 hardware accelerator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/aria.h b/crypto/mbedtls/include/mbedtls/aria.h
index 4a79c13..483d4c2 100644
--- a/crypto/mbedtls/include/mbedtls/aria.h
+++ b/crypto/mbedtls/include/mbedtls/aria.h
@@ -48,7 +48,12 @@
 
 #define MBEDTLS_ERR_ARIA_INVALID_KEY_LENGTH   -0x005C  /**< Invalid key length. */
 #define MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH -0x005E  /**< Invalid data input length. */
+
+/* MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE  -0x005A  /**< Feature not available. For example, an unsupported ARIA key size. */
+
+/* MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED      -0x0058  /**< ARIA hardware accelerator failed. */
 
 #if !defined(MBEDTLS_ARIA_ALT)
diff --git a/crypto/mbedtls/include/mbedtls/asn1write.h b/crypto/mbedtls/include/mbedtls/asn1write.h
index f76fc80..76c1780 100644
--- a/crypto/mbedtls/include/mbedtls/asn1write.h
+++ b/crypto/mbedtls/include/mbedtls/asn1write.h
@@ -26,191 +26,272 @@
 
 #include "asn1.h"
 
-#define MBEDTLS_ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else   \
-                                g += ret; } while( 0 )
+#define MBEDTLS_ASN1_CHK_ADD(g, f)                      \
+    do {                                                \
+        if( ( ret = f ) < 0 )                           \
+            return( ret );                              \
+        else                                            \
+            g += ret;                                   \
+    } while( 0 )
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * \brief           Write a length field in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a length field in ASN.1 format.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param len       the length to write
+ * \note            This function works backwards in data buffer.
  *
- * \return          the length written or a negative error code
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param len       The length value to write.
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
-int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len );
-
+int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start,
+                            size_t len );
 /**
- * \brief           Write a ASN.1 tag in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write an ASN.1 tag in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param tag       the tag to write
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param tag       The tag to write.
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
 int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start,
-                    unsigned char tag );
+                            unsigned char tag );
 
 /**
- * \brief           Write raw buffer data
- *                  Note: function works backwards in data buffer
+ * \brief           Write raw buffer data.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param buf       data buffer to write
- * \param size      length of the data buffer
+ * \note            This function works backwards in data buffer.
  *
- * \return          the length written or a negative error code
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param buf       The data buffer to write.
+ * \param size      The length of the data buffer.
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
 int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
-                           const unsigned char *buf, size_t size );
+                                   const unsigned char *buf, size_t size );
 
 #if defined(MBEDTLS_BIGNUM_C)
 /**
- * \brief           Write a big number (MBEDTLS_ASN1_INTEGER) in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a arbitrary-precision number (#MBEDTLS_ASN1_INTEGER)
+ *                  in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param X         the MPI to write
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param X         The MPI to write.
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
-int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X );
+int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start,
+                            const mbedtls_mpi *X );
 #endif /* MBEDTLS_BIGNUM_C */
 
 /**
- * \brief           Write a NULL tag (MBEDTLS_ASN1_NULL) with zero data in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a NULL tag (#MBEDTLS_ASN1_NULL) with zero data
+ *                  in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
 int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start );
 
 /**
- * \brief           Write an OID tag (MBEDTLS_ASN1_OID) and data in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write an OID tag (#MBEDTLS_ASN1_OID) and data
+ *                  in ASN.1 format.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param oid       the OID to write
- * \param oid_len   length of the OID
+ * \note            This function works backwards in data buffer.
  *
- * \return          the length written or a negative error code
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param oid       The OID to write.
+ * \param oid_len   The length of the OID.
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
 int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start,
-                    const char *oid, size_t oid_len );
+                            const char *oid, size_t oid_len );
 
 /**
- * \brief           Write an AlgorithmIdentifier sequence in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write an AlgorithmIdentifier sequence in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param oid       the OID of the algorithm
- * \param oid_len   length of the OID
- * \param par_len   length of parameters, which must be already written.
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param oid       The OID of the algorithm to write.
+ * \param oid_len   The length of the algorithm's OID.
+ * \param par_len   The length of the parameters, which must be already written.
  *                  If 0, NULL parameters are added
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
-int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
-                                     const char *oid, size_t oid_len,
-                                     size_t par_len );
+int mbedtls_asn1_write_algorithm_identifier( unsigned char **p,
+                                             unsigned char *start,
+                                             const char *oid, size_t oid_len,
+                                             size_t par_len );
 
 /**
- * \brief           Write a boolean tag (MBEDTLS_ASN1_BOOLEAN) and value in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a boolean tag (#MBEDTLS_ASN1_BOOLEAN) and value
+ *                  in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param boolean   0 or 1
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param boolean   The boolean value to write, either \c 0 or \c 1.
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
-int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean );
+int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start,
+                             int boolean );
 
 /**
- * \brief           Write an int tag (MBEDTLS_ASN1_INTEGER) and value in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write an int tag (#MBEDTLS_ASN1_INTEGER) and value
+ *                  in ASN.1 format.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param val       the integer value
+ * \note            This function works backwards in data buffer.
  *
- * \return          the length written or a negative error code
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param val       The integer value to write.
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
  */
 int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val );
 
 /**
- * \brief           Write a printable string tag (MBEDTLS_ASN1_PRINTABLE_STRING) and
- *                  value in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a string in ASN.1 format using a specific
+ *                  string encoding tag.
+
+ * \note            This function works backwards in data buffer.
+ *
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param tag       The string encoding tag to write, e.g.
+ *                  #MBEDTLS_ASN1_UTF8_STRING.
+ * \param text      The string to write.
+ * \param text_len  The length of \p text in bytes (which might
+ *                  be strictly larger than the number of characters).
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
+ */
+int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start,
+                                      int tag, const char *text,
+                                      size_t text_len );
+
+/**
+ * \brief           Write a string in ASN.1 format using the PrintableString
+ *                  string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING).
+ *
+ * \note            This function works backwards in data buffer.
+ *
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param text      The string to write.
+ * \param text_len  The length of \p text in bytes (which might
+ *                  be strictly larger than the number of characters).
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
+ */
+int mbedtls_asn1_write_printable_string( unsigned char **p,
+                                         unsigned char *start,
+                                         const char *text, size_t text_len );
+
+/**
+ * \brief           Write a UTF8 string in ASN.1 format using the UTF8String
+ *                  string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING).
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param text      the text to write
- * \param text_len  length of the text
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param text      The string to write.
+ * \param text_len  The length of \p text in bytes (which might
+ *                  be strictly larger than the number of characters).
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
  */
-int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
-                                 const char *text, size_t text_len );
+int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start,
+                                    const char *text, size_t text_len );
 
 /**
- * \brief           Write an IA5 string tag (MBEDTLS_ASN1_IA5_STRING) and
- *                  value in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a string in ASN.1 format using the IA5String
+ *                  string encoding tag (#MBEDTLS_ASN1_IA5_STRING).
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param text      the text to write
- * \param text_len  length of the text
+ * \note            This function works backwards in data buffer.
  *
- * \return          the length written or a negative error code
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param text      The string to write.
+ * \param text_len  The length of \p text in bytes (which might
+ *                  be strictly larger than the number of characters).
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
  */
 int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
-                           const char *text, size_t text_len );
+                                   const char *text, size_t text_len );
 
 /**
- * \brief           Write a bitstring tag (MBEDTLS_ASN1_BIT_STRING) and
- *                  value in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write a bitstring tag (#MBEDTLS_ASN1_BIT_STRING) and
+ *                  value in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param buf       the bitstring
- * \param bits      the total number of bits in the bitstring
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param buf       The bitstring to write.
+ * \param bits      The total number of bits in the bitstring.
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
  */
 int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
-                          const unsigned char *buf, size_t bits );
+                                  const unsigned char *buf, size_t bits );
 
 /**
- * \brief           Write an octet string tag (MBEDTLS_ASN1_OCTET_STRING) and
- *                  value in ASN.1 format
- *                  Note: function works backwards in data buffer
+ * \brief           Write an octet string tag (#MBEDTLS_ASN1_OCTET_STRING)
+ *                  and value in ASN.1 format.
+ *
+ * \note            This function works backwards in data buffer.
  *
- * \param p         reference to current position pointer
- * \param start     start of the buffer (for bounds-checking)
- * \param buf       data buffer to write
- * \param size      length of the data buffer
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer, for bounds-checking.
+ * \param buf       The buffer holding the data to write.
+ * \param size      The length of the data buffer \p buf.
  *
- * \return          the length written or a negative error code
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
  */
 int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
-                             const unsigned char *buf, size_t size );
+                                     const unsigned char *buf, size_t size );
 
 /**
  * \brief           Create or find a specific named_data entry for writing in a
@@ -218,15 +299,16 @@ int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
  *                  a new entry is added to the head of the list.
  *                  Warning: Destructive behaviour for the val data!
  *
- * \param list      Pointer to the location of the head of the list to seek
- *                  through (will be updated in case of a new entry)
- * \param oid       The OID to look for
- * \param oid_len   Size of the OID
- * \param val       Data to store (can be NULL if you want to fill it by hand)
- * \param val_len   Minimum length of the data buffer needed
+ * \param list      The pointer to the location of the head of the list to seek
+ *                  through (will be updated in case of a new entry).
+ * \param oid       The OID to look for.
+ * \param oid_len   The size of the OID.
+ * \param val       The data to store (can be \c NULL if you want to fill
+ *                  it by hand).
+ * \param val_len   The minimum length of the data buffer needed.
  *
- * \return      NULL if if there was a memory allocation error, or a pointer
- *              to the new / existing entry.
+ * \return          A pointer to the new / existing entry on success.
+ * \return          \c NULL if if there was a memory allocation error.
  */
 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list,
                                         const char *oid, size_t oid_len,
diff --git a/crypto/mbedtls/include/mbedtls/bignum.h b/crypto/mbedtls/include/mbedtls/bignum.h
index 732ecbe..40cfab4 100644
--- a/crypto/mbedtls/include/mbedtls/bignum.h
+++ b/crypto/mbedtls/include/mbedtls/bignum.h
@@ -725,10 +725,49 @@ int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B
  */
 int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N );
 
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED      __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief          Miller-Rabin primality test with error probability of
+ *                 2<sup>-80</sup>
+ *
+ * \deprecated     Superseded by mbedtls_mpi_is_prime_ext() which allows
+ *                 specifying the number of Miller-Rabin rounds.
+ *
+ * \param X        MPI to check
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ *                 MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime
+ */
+MBEDTLS_DEPRECATED int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
+                          int (*f_rng)(void *, unsigned char *, size_t),
+                          void *p_rng );
+#undef MBEDTLS_DEPRECATED
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+
 /**
- * \brief          Miller-Rabin primality test
+ * \brief          Miller-Rabin primality test.
+ *
+ * \warning        If \p X is potentially generated by an adversary, for example
+ *                 when validating cryptographic parameters that you didn't
+ *                 generate yourself and that are supposed to be prime, then
+ *                 \p rounds should be at least the half of the security
+ *                 strength of the cryptographic algorithm. On the other hand,
+ *                 if \p X is chosen uniformly or non-adversially (as is the
+ *                 case when mbedtls_mpi_gen_prime calls this function), then
+ *                 \p rounds can be much lower.
  *
  * \param X        MPI to check
+ * \param rounds   Number of bases to perform Miller-Rabin primality test for.
+ *                 The probability of returning 0 on a composite is at most
+ *                 2<sup>-2*\p rounds</sup>.
  * \param f_rng    RNG function
  * \param p_rng    RNG parameter
  *
@@ -736,9 +775,19 @@ int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
  *                 MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
  *                 MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime
  */
-int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
-                  int (*f_rng)(void *, unsigned char *, size_t),
-                  void *p_rng );
+int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds,
+                              int (*f_rng)(void *, unsigned char *, size_t),
+                              void *p_rng );
+/**
+ * \brief Flags for mbedtls_mpi_gen_prime()
+ *
+ * Each of these flags is a constraint on the result X returned by
+ * mbedtls_mpi_gen_prime().
+ */
+typedef enum {
+    MBEDTLS_MPI_GEN_PRIME_FLAG_DH =      0x0001, /**< (X-1)/2 is prime too */
+    MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR = 0x0002, /**< lower error rate from 2<sup>-80</sup> to 2<sup>-128</sup> */
+} mbedtls_mpi_gen_prime_flag_t;
 
 /**
  * \brief          Prime number generation
@@ -746,7 +795,7 @@ int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
  * \param X        Destination MPI
  * \param nbits    Required size of X in bits
  *                 ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS )
- * \param dh_flag  If 1, then (X-1)/2 will be prime too
+ * \param flags    Mask of flags of type #mbedtls_mpi_gen_prime_flag_t
  * \param f_rng    RNG function
  * \param p_rng    RNG parameter
  *
@@ -754,7 +803,7 @@ int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
  *                 MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
  *                 MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
  */
-int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
+int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
                    int (*f_rng)(void *, unsigned char *, size_t),
                    void *p_rng );
 
diff --git a/crypto/mbedtls/include/mbedtls/blowfish.h b/crypto/mbedtls/include/mbedtls/blowfish.h
index eea6882..82b772a 100644
--- a/crypto/mbedtls/include/mbedtls/blowfish.h
+++ b/crypto/mbedtls/include/mbedtls/blowfish.h
@@ -41,7 +41,11 @@
 #define MBEDTLS_BLOWFISH_BLOCKSIZE   8          /* Blowfish uses 64 bit blocks */
 
 #define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH                -0x0016  /**< Invalid key length. */
+
+/* MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED                   -0x0017  /**< Blowfish hardware accelerator failed. */
+
 #define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH              -0x0018  /**< Invalid data input length. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/bn_mul.h b/crypto/mbedtls/include/mbedtls/bn_mul.h
index b587317..0af694c 100644
--- a/crypto/mbedtls/include/mbedtls/bn_mul.h
+++ b/crypto/mbedtls/include/mbedtls/bn_mul.h
@@ -565,9 +565,8 @@
 #endif /* TriCore */
 
 /*
- * gcc -O0 by default uses r7 for the frame pointer, so it complains about our
- * use of r7 below, unless -fomit-frame-pointer is passed. Unfortunately,
- * passing that option is not easy when building with yotta.
+ * Note, gcc -O0 by default uses r7 for the frame pointer, so it complains about
+ * our use of r7 below, unless -fomit-frame-pointer is passed.
  *
  * On the other hand, -fomit-frame-pointer is implied by any -Ox options with
  * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by
@@ -637,6 +636,23 @@
            "r6", "r7", "r8", "r9", "cc"         \
          );
 
+#elif defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)
+
+#define MULADDC_INIT                            \
+    asm(
+
+#define MULADDC_CORE                            \
+            "ldr    r0, [%0], #4        \n\t"   \
+            "ldr    r1, [%1]            \n\t"   \
+            "umaal  r1, %2, %3, r0      \n\t"   \
+            "str    r1, [%1], #4        \n\t"
+
+#define MULADDC_STOP                            \
+         : "=r" (s),  "=r" (d), "=r" (c)        \
+         : "r" (b), "0" (s), "1" (d), "2" (c)   \
+         : "r0", "r1", "memory"                 \
+         );
+
 #else
 
 #define MULADDC_INIT                                    \
diff --git a/crypto/mbedtls/include/mbedtls/camellia.h b/crypto/mbedtls/include/mbedtls/camellia.h
index fa1e05e..1555867 100644
--- a/crypto/mbedtls/include/mbedtls/camellia.h
+++ b/crypto/mbedtls/include/mbedtls/camellia.h
@@ -38,6 +38,9 @@
 
 #define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH           -0x0024  /**< Invalid key length. */
 #define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH         -0x0026  /**< Invalid data input length. */
+
+/* MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED              -0x0027  /**< Camellia hardware accelerator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/ccm.h b/crypto/mbedtls/include/mbedtls/ccm.h
index e1dc124..dfb1b5e 100644
--- a/crypto/mbedtls/include/mbedtls/ccm.h
+++ b/crypto/mbedtls/include/mbedtls/ccm.h
@@ -53,6 +53,8 @@
 
 #define MBEDTLS_ERR_CCM_BAD_INPUT       -0x000D /**< Bad input parameters to the function. */
 #define MBEDTLS_ERR_CCM_AUTH_FAILED     -0x000F /**< Authenticated decryption failed. */
+
+/* MBEDTLS_ERR_CCM_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_CCM_HW_ACCEL_FAILED -0x0011 /**< CCM hardware accelerator failed. */
 
 
diff --git a/crypto/mbedtls/include/mbedtls/chacha20.h b/crypto/mbedtls/include/mbedtls/chacha20.h
index cfea40a..529f22d 100644
--- a/crypto/mbedtls/include/mbedtls/chacha20.h
+++ b/crypto/mbedtls/include/mbedtls/chacha20.h
@@ -43,7 +43,13 @@
 #include <stddef.h>
 
 #define MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA         -0x0051 /**< Invalid input parameter(s). */
+
+/* MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE is deprecated and should not be
+ * used. */
 #define MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE    -0x0053 /**< Feature not available. For example, s part of the API is not implemented. */
+
+/* MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED        -0x0055  /**< Chacha20 hardware accelerator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/check_config.h b/crypto/mbedtls/include/mbedtls/check_config.h
index 9e6bb8a..425e3ea 100644
--- a/crypto/mbedtls/include/mbedtls/check_config.h
+++ b/crypto/mbedtls/include/mbedtls/check_config.h
@@ -108,6 +108,16 @@
 #error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)           && \
+    ( defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
+      defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)     || \
+      defined(MBEDTLS_ECDSA_SIGN_ALT)          || \
+      defined(MBEDTLS_ECDSA_VERIFY_ALT)        || \
+      defined(MBEDTLS_ECDSA_GENKEY_ALT)        || \
+      defined(MBEDTLS_ECP_ALT) )
+#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation"
+#endif
+
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
 #error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites"
 #endif
diff --git a/crypto/mbedtls/include/mbedtls/cipher.h b/crypto/mbedtls/include/mbedtls/cipher.h
index dfb1541..58a5d63 100644
--- a/crypto/mbedtls/include/mbedtls/cipher.h
+++ b/crypto/mbedtls/include/mbedtls/cipher.h
@@ -62,6 +62,8 @@
 #define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED  -0x6280  /**< Decryption of block requires a full block. */
 #define MBEDTLS_ERR_CIPHER_AUTH_FAILED          -0x6300  /**< Authentication failed (for AEAD modes). */
 #define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT      -0x6380  /**< The context is invalid. For example, because it was freed. */
+
+/* MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED      -0x6400  /**< Cipher hardware accelerator failed. */
 
 #define MBEDTLS_CIPHER_VARIABLE_IV_LEN     0x01    /**< Cipher accepts IVs of variable length. */
diff --git a/crypto/mbedtls/include/mbedtls/cmac.h b/crypto/mbedtls/include/mbedtls/cmac.h
index 913c05f..462e565 100644
--- a/crypto/mbedtls/include/mbedtls/cmac.h
+++ b/crypto/mbedtls/include/mbedtls/cmac.h
@@ -34,6 +34,7 @@
 extern "C" {
 #endif
 
+/* MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED -0x007A  /**< CMAC hardware accelerator failed. */
 
 #define MBEDTLS_AES_BLOCK_SIZE          16
diff --git a/crypto/mbedtls/include/mbedtls/config.h b/crypto/mbedtls/include/mbedtls/config.h
index 5bb4774..0849d4a 100644
--- a/crypto/mbedtls/include/mbedtls/config.h
+++ b/crypto/mbedtls/include/mbedtls/config.h
@@ -137,12 +137,21 @@
 /**
  * \def MBEDTLS_HAVE_TIME_DATE
  *
- * System has time.h and time(), gmtime() and the clock is correct.
+ * System has time.h, time(), and an implementation for
+ * mbedtls_platform_gmtime_r() (see below).
  * The time needs to be correct (not necesarily very accurate, but at least
  * the date should be correct). This is used to verify the validity period of
  * X.509 certificates.
  *
  * Comment if your system does not have a correct clock.
+ *
+ * \note mbedtls_platform_gmtime_r() is an abstraction in platform_util.h that
+ * behaves similarly to the gmtime_r() function from the C standard. Refer to
+ * the documentation for mbedtls_platform_gmtime_r() for more information.
+ *
+ * \note It is possible to configure an implementation for
+ * mbedtls_platform_gmtime_r() at compile-time by using the macro
+ * MBEDTLS_PLATFORM_GMTIME_R_ALT.
  */
 #define MBEDTLS_HAVE_TIME_DATE
 
@@ -669,6 +678,30 @@
 #define MBEDTLS_ECP_NIST_OPTIM
 
 /**
+ * \def MBEDTLS_ECP_RESTARTABLE
+ *
+ * Enable "non-blocking" ECC operations that can return early and be resumed.
+ *
+ * This allows various functions to pause by returning
+ * #MBEDTLS_ERR_ECP_IN_PROGRESS (or, for functions in the SSL module,
+ * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) and then be called later again in
+ * order to further progress and eventually complete their operation. This is
+ * controlled through mbedtls_ecp_set_max_ops() which limits the maximum
+ * number of ECC operations a function may perform before pausing; see
+ * mbedtls_ecp_set_max_ops() for more information.
+ *
+ * This is useful in non-threaded environments if you want to avoid blocking
+ * for too long on ECC (and, hence, X.509 or SSL/TLS) operations.
+ *
+ * Uncomment this macro to enable restartable ECC computations.
+ *
+ * \note  This option only works with the default software implementation of
+ *        elliptic curve functionality. It is incompatible with
+ *        MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT and MBEDTLS_ECDSA_XXX_ALT.
+ */
+//#define MBEDTLS_ECP_RESTARTABLE
+
+/**
  * \def MBEDTLS_ECDSA_DETERMINISTIC
  *
  * Enable deterministic ECDSA (RFC 6979).
@@ -1279,7 +1312,7 @@
 /**
  * \def MBEDTLS_SSL_RENEGOTIATION
  *
- * Disable support for TLS renegotiation.
+ * Enable support for TLS renegotiation.
  *
  * The two main uses of renegotiation are (1) refresh keys on long-lived
  * connections and (2) client authentication after the initial handshake.
@@ -2018,14 +2051,16 @@
 /**
  * \def MBEDTLS_CTR_DRBG_C
  *
- * Enable the CTR_DRBG AES-256-based random generator.
+ * Enable the CTR_DRBG AES-based random generator.
+ * The CTR_DRBG generator uses AES-256 by default.
+ * To use AES-128 instead, enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY below.
  *
  * Module:  library/ctr_drbg.c
  * Caller:
  *
  * Requires: MBEDTLS_AES_C
  *
- * This module provides the CTR_DRBG AES-256 random number generator.
+ * This module provides the CTR_DRBG AES random number generator.
  */
 #define MBEDTLS_CTR_DRBG_C
 
@@ -2910,6 +2945,7 @@
 //#define MBEDTLS_CTR_DRBG_MAX_INPUT                256 /**< Maximum number of additional input bytes */
 //#define MBEDTLS_CTR_DRBG_MAX_REQUEST             1024 /**< Maximum number of requested bytes per call */
 //#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT           384 /**< Maximum size of (re)seed buffer */
+//#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY              /**< Use 128-bit key for CTR_DRBG - may reduce security (see ctr_drbg.h) */
 
 /* HMAC_DRBG options */
 //#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL   10000 /**< Interval before reseed is performed by default */
@@ -3100,25 +3136,33 @@
  */
 //#define MBEDTLS_PLATFORM_ZEROIZE_ALT
 
-/* \} name SECTION: Customisation configuration options */
-
-/* Target and application specific configurations */
-//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "target_config.h"
+/**
+ * Uncomment the macro to let Mbed TLS use your alternate implementation of
+ * mbedtls_platform_gmtime_r(). This replaces the default implementation in
+ * platform_util.c.
+ *
+ * gmtime() is not a thread-safe function as defined in the C standard. The
+ * library will try to use safer implementations of this function, such as
+ * gmtime_r() when available. However, if Mbed TLS cannot identify the target
+ * system, the implementation of mbedtls_platform_gmtime_r() will default to
+ * using the standard gmtime(). In this case, calls from the library to
+ * gmtime() will be guarded by the global mutex mbedtls_threading_gmtime_mutex
+ * if MBEDTLS_THREADING_C is enabled. We recommend that calls from outside the
+ * library are also guarded with this mutex to avoid race conditions. However,
+ * if the macro MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, Mbed TLS will
+ * unconditionally use the implementation for mbedtls_platform_gmtime_r()
+ * supplied at compile time.
+ */
+//#define MBEDTLS_PLATFORM_GMTIME_R_ALT
 
-#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE)
-#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE
-#endif
+/* \} name SECTION: Customisation configuration options */
 
-/*
+/* Target and application specific configurations
+ *
  * Allow user to override any previous default.
  *
- * Use two macro names for that, as:
- * - with yotta the prefix YOTTA_CFG_ is forced
- * - without yotta is looks weird to have a YOTTA prefix.
  */
-#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE)
-#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE
-#elif defined(MBEDTLS_USER_CONFIG_FILE)
+#if defined(MBEDTLS_USER_CONFIG_FILE)
 #include MBEDTLS_USER_CONFIG_FILE
 #endif
 
diff --git a/crypto/mbedtls/include/mbedtls/ctr_drbg.h b/crypto/mbedtls/include/mbedtls/ctr_drbg.h
index 69d06ae..6aae0b0 100644
--- a/crypto/mbedtls/include/mbedtls/ctr_drbg.h
+++ b/crypto/mbedtls/include/mbedtls/ctr_drbg.h
@@ -8,8 +8,11 @@
  * Recommendation for Random Number Generation Using Deterministic Random
  * Bit Generators</em>.
  *
- * The Mbed TLS implementation of CTR_DRBG uses AES-256 as the underlying
- * block cipher.
+ * The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128
+ * as the underlying block cipher.
+ *
+ *  \warning Using 128-bit keys for CTR_DRBG limits the security of generated
+ *  keys and operations that use random values generated to 128-bit security.
  */
 /*
  *  Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
@@ -45,7 +48,13 @@
 #define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR                -0x003A  /**< Read or write error in file. */
 
 #define MBEDTLS_CTR_DRBG_BLOCKSIZE          16 /**< The block size used by the cipher. */
-#define MBEDTLS_CTR_DRBG_KEYSIZE            32 /**< The key size used by the cipher. */
+
+#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
+#define MBEDTLS_CTR_DRBG_KEYSIZE            16 /**< The key size used by the cipher (compile-time choice: 128 bits). */
+#else
+#define MBEDTLS_CTR_DRBG_KEYSIZE            32 /**< The key size used by the cipher (compile-time choice: 256 bits). */
+#endif
+
 #define MBEDTLS_CTR_DRBG_KEYBITS            ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) /**< The key size for the DRBG operation, in bits. */
 #define MBEDTLS_CTR_DRBG_SEEDLEN            ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) /**< The seed length, calculated as (counter + AES key). */
 
@@ -228,20 +237,41 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
                      const unsigned char *additional, size_t len );
 
 /**
- * \brief              This function updates the state of the CTR_DRBG context.
+ * \brief               This function updates the state of the CTR_DRBG context.
  *
- * \note               If \p add_len is greater than
- *                     #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first
- *                     #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used.
- *                     The remaining Bytes are silently discarded.
+ * \param ctx           The CTR_DRBG context.
+ * \param additional    The data to update the state with.
+ * \param add_len       Length of \p additional in bytes. This must be at
+ *                      most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
  *
- * \param ctx          The CTR_DRBG context.
- * \param additional   The data to update the state with.
- * \param add_len      Length of \p additional data.
+ * \return              \c 0 on success.
+ * \return              #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if
+ *                      \p add_len is more than
+ *                      #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
+ * \return              An error from the underlying AES cipher on failure.
+ */
+int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
+                                 const unsigned char *additional,
+                                 size_t add_len );
+
+/**
+ * \brief               This function updates the state of the CTR_DRBG context.
  *
+ * \warning             This function cannot report errors. You should use
+ *                      mbedtls_ctr_drbg_update_ret() instead.
+ *
+ * \note                If \p add_len is greater than
+ *                      #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first
+ *                      #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used.
+ *                      The remaining Bytes are silently discarded.
+ *
+ * \param ctx           The CTR_DRBG context.
+ * \param additional    The data to update the state with.
+ * \param add_len       Length of \p additional data.
  */
 void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
-                      const unsigned char *additional, size_t add_len );
+                              const unsigned char *additional,
+                              size_t add_len );
 
 /**
  * \brief   This function updates a CTR_DRBG instance with additional
diff --git a/crypto/mbedtls/include/mbedtls/des.h b/crypto/mbedtls/include/mbedtls/des.h
index 91d16b6..d62042d 100644
--- a/crypto/mbedtls/include/mbedtls/des.h
+++ b/crypto/mbedtls/include/mbedtls/des.h
@@ -42,6 +42,8 @@
 #define MBEDTLS_DES_DECRYPT     0
 
 #define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH              -0x0032  /**< The data input has an invalid length. */
+
+/* MBEDTLS_ERR_DES_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_DES_HW_ACCEL_FAILED                   -0x0033  /**< DES hardware accelerator failed. */
 
 #define MBEDTLS_DES_KEY_SIZE    8
diff --git a/crypto/mbedtls/include/mbedtls/dhm.h b/crypto/mbedtls/include/mbedtls/dhm.h
index 3e11789..8e2d020 100644
--- a/crypto/mbedtls/include/mbedtls/dhm.h
+++ b/crypto/mbedtls/include/mbedtls/dhm.h
@@ -84,7 +84,10 @@
 #define MBEDTLS_ERR_DHM_INVALID_FORMAT                    -0x3380  /**< The ASN.1 data is not formatted correctly. */
 #define MBEDTLS_ERR_DHM_ALLOC_FAILED                      -0x3400  /**< Allocation of memory failed. */
 #define MBEDTLS_ERR_DHM_FILE_IO_ERROR                     -0x3480  /**< Read or write of file failed. */
+
+/* MBEDTLS_ERR_DHM_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_DHM_HW_ACCEL_FAILED                   -0x3500  /**< DHM hardware accelerator failed. */
+
 #define MBEDTLS_ERR_DHM_SET_GROUP_FAILED                  -0x3580  /**< Setting the modulus and generator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/ecdh.h b/crypto/mbedtls/include/mbedtls/ecdh.h
index 95f3980..27f2ffc 100644
--- a/crypto/mbedtls/include/mbedtls/ecdh.h
+++ b/crypto/mbedtls/include/mbedtls/ecdh.h
@@ -50,6 +50,10 @@ typedef enum
 } mbedtls_ecdh_side;
 
 /**
+ *
+ * \warning         Performing multiple operations concurrently on the same
+ *                  ECDSA context is not supported; objects of this type
+ *                  should not be shared between multiple threads.
  * \brief           The ECDH context structure.
  */
 typedef struct mbedtls_ecdh_context
@@ -63,6 +67,10 @@ typedef struct mbedtls_ecdh_context
     mbedtls_ecp_point Vi;    /*!< The blinding value. */
     mbedtls_ecp_point Vf;    /*!< The unblinding value. */
     mbedtls_mpi _d;          /*!< The previous \p d. */
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    int restart_enabled;        /*!< The flag for restartable mode. */
+    mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */
+#endif
 }
 mbedtls_ecdh_context;
 
@@ -83,9 +91,8 @@ mbedtls_ecdh_context;
  * \param p_rng     The RNG context.
  *
  * \return          \c 0 on success.
- * \return          An \c MBEDTLS_ERR_ECP_XXX or
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX or
  *                  \c MBEDTLS_MPI_XXX error code on failure.
- *
  */
 int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
                      int (*f_rng)(void *, unsigned char *, size_t),
@@ -112,7 +119,7 @@ int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp
  * \param p_rng     The RNG context.
  *
  * \return          \c 0 on success.
- * \return          An \c MBEDTLS_ERR_ECP_XXX or
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX or
  *                  \c MBEDTLS_MPI_XXX error code on failure.
  */
 int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
@@ -155,7 +162,9 @@ void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx );
  * \param p_rng     The RNG context.
  *
  * \return          \c 0 on success.
- * \return          An \c MBEDTLS_ERR_ECP_XXX error code on failure.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX error code on failure.
  */
 int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
                       unsigned char *buf, size_t blen,
@@ -197,7 +206,7 @@ int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx,
  *                  0: The key of the peer.
  *
  * \return          \c 0 on success.
- * \return          An \c MBEDTLS_ERR_ECP_XXX error code on failure.
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX error code on failure.
  *
  */
 int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key,
@@ -220,7 +229,9 @@ int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypai
  * \param p_rng     The RNG context.
  *
  * \return          \c 0 on success.
- * \return          An \c MBEDTLS_ERR_ECP_XXX error code on failure.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX error code on failure.
  */
 int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
                       unsigned char *buf, size_t blen,
@@ -266,13 +277,31 @@ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
  * \param p_rng     The RNG context.
  *
  * \return          \c 0 on success.
- * \return          An \c MBEDTLS_ERR_ECP_XXX error code on failure.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX error code on failure.
  */
 int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
                       unsigned char *buf, size_t blen,
                       int (*f_rng)(void *, unsigned char *, size_t),
                       void *p_rng );
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           This function enables restartable EC computations for this
+ *                  context.  (Default: disabled.)
+ *
+ * \see             \c mbedtls_ecp_set_max_ops()
+ *
+ * \note            It is not possible to safely disable restartable
+ *                  computations once enabled, except by free-ing the context,
+ *                  which cancels possible in-progress operations.
+ *
+ * \param ctx       The ECDH context.
+ */
+void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx );
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/crypto/mbedtls/include/mbedtls/ecdsa.h b/crypto/mbedtls/include/mbedtls/ecdsa.h
index ce1a03d..4057828 100644
--- a/crypto/mbedtls/include/mbedtls/ecdsa.h
+++ b/crypto/mbedtls/include/mbedtls/ecdsa.h
@@ -55,16 +55,66 @@
 /** The maximal size of an ECDSA signature in Bytes. */
 #define MBEDTLS_ECDSA_MAX_LEN  ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) )
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  * \brief           The ECDSA context structure.
+ *
+ * \warning         Performing multiple operations concurrently on the same
+ *                  ECDSA context is not supported; objects of this type
+ *                  should not be shared between multiple threads.
  */
 typedef mbedtls_ecp_keypair mbedtls_ecdsa_context;
 
-#ifdef __cplusplus
-extern "C" {
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+
+/**
+ * \brief           Internal restart context for ecdsa_verify()
+ *
+ * \note            Opaque struct, defined in ecdsa.c
+ */
+typedef struct mbedtls_ecdsa_restart_ver mbedtls_ecdsa_restart_ver_ctx;
+
+/**
+ * \brief           Internal restart context for ecdsa_sign()
+ *
+ * \note            Opaque struct, defined in ecdsa.c
+ */
+typedef struct mbedtls_ecdsa_restart_sig mbedtls_ecdsa_restart_sig_ctx;
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+/**
+ * \brief           Internal restart context for ecdsa_sign_det()
+ *
+ * \note            Opaque struct, defined in ecdsa.c
+ */
+typedef struct mbedtls_ecdsa_restart_det mbedtls_ecdsa_restart_det_ctx;
 #endif
 
 /**
+ * \brief           General context for resuming ECDSA operations
+ */
+typedef struct
+{
+    mbedtls_ecp_restart_ctx ecp;        /*!<  base context for ECP restart and
+                                              shared administrative info    */
+    mbedtls_ecdsa_restart_ver_ctx *ver; /*!<  ecdsa_verify() sub-context    */
+    mbedtls_ecdsa_restart_sig_ctx *sig; /*!<  ecdsa_sign() sub-context      */
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+    mbedtls_ecdsa_restart_det_ctx *det; /*!<  ecdsa_sign_det() sub-context  */
+#endif
+} mbedtls_ecdsa_restart_ctx;
+
+#else /* MBEDTLS_ECP_RESTARTABLE */
+
+/* Now we can declare functions that take a pointer to that */
+typedef void mbedtls_ecdsa_restart_ctx;
+
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
+/**
  * \brief           This function computes the ECDSA signature of a
  *                  previously-hashed message.
  *
@@ -205,6 +255,40 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t
                            int (*f_rng)(void *, unsigned char *, size_t),
                            void *p_rng );
 
+/**
+ * \brief           This function computes the ECDSA signature and writes it
+ *                  to a buffer, in a restartable way.
+ *
+ * \see             \c mbedtls_ecdsa_write_signature()
+ *
+ * \note            This function is like \c mbedtls_ecdsa_write_signature()
+ *                  but it can return early and restart according to the limit
+ *                  set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
+ *
+ * \param ctx       The ECDSA context.
+ * \param md_alg    The message digest that was used to hash the message.
+ * \param hash      The message hash.
+ * \param hlen      The length of the hash.
+ * \param sig       The buffer that holds the signature.
+ * \param slen      The length of the signature written.
+ * \param f_rng     The RNG function.
+ * \param p_rng     The RNG context.
+ * \param rs_ctx    The restart context (NULL disables restart).
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or
+ *                  \c MBEDTLS_ERR_ASN1_XXX error code on failure.
+ */
+int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
+                           mbedtls_md_type_t md_alg,
+                           const unsigned char *hash, size_t hlen,
+                           unsigned char *sig, size_t *slen,
+                           int (*f_rng)(void *, unsigned char *, size_t),
+                           void *p_rng,
+                           mbedtls_ecdsa_restart_ctx *rs_ctx );
+
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
 #if ! defined(MBEDTLS_DEPRECATED_REMOVED)
 #if defined(MBEDTLS_DEPRECATED_WARNING)
@@ -289,6 +373,37 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
                           const unsigned char *sig, size_t slen );
 
 /**
+ * \brief           This function reads and verifies an ECDSA signature,
+ *                  in a restartable way.
+ *
+ * \see             \c mbedtls_ecdsa_read_signature()
+ *
+ * \note            This function is like \c mbedtls_ecdsa_read_signature()
+ *                  but it can return early and restart according to the limit
+ *                  set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
+ *
+ * \param ctx       The ECDSA context.
+ * \param hash      The message hash.
+ * \param hlen      The size of the hash.
+ * \param sig       The signature to read and verify.
+ * \param slen      The size of \p sig.
+ * \param rs_ctx    The restart context (NULL disables restart).
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid.
+ * \return          #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid
+ *                  signature in \p sig, but its length is less than \p siglen.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ * \return          Another \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX
+ *                  error code on failure for any other reason.
+ */
+int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
+                          const unsigned char *hash, size_t hlen,
+                          const unsigned char *sig, size_t slen,
+                          mbedtls_ecdsa_restart_ctx *rs_ctx );
+
+/**
  * \brief          This function generates an ECDSA keypair on the given curve.
  *
  * \see            ecp.h
@@ -332,6 +447,18 @@ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx );
  */
 void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx );
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           Initialize a restart context
+ */
+void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx );
+
+/**
+ * \brief           Free the components of a restart context
+ */
+void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx );
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/crypto/mbedtls/include/mbedtls/ecp.h b/crypto/mbedtls/include/mbedtls/ecp.h
index ed1b9d7..2fb1af4 100644
--- a/crypto/mbedtls/include/mbedtls/ecp.h
+++ b/crypto/mbedtls/include/mbedtls/ecp.h
@@ -49,8 +49,12 @@
 #define MBEDTLS_ERR_ECP_RANDOM_FAILED                     -0x4D00  /**< Generation of random value, such as ephemeral key, failed. */
 #define MBEDTLS_ERR_ECP_INVALID_KEY                       -0x4C80  /**< Invalid private or public key. */
 #define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH                  -0x4C00  /**< The buffer contains a valid signature followed by more data. */
+
+/* MBEDTLS_ERR_ECP_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED                   -0x4B80  /**< The ECP hardware accelerator failed. */
 
+#define MBEDTLS_ERR_ECP_IN_PROGRESS                       -0x4B00  /**< Operation in progress, call again with the same parameters to continue. */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -181,6 +185,70 @@ typedef struct mbedtls_ecp_group
 }
 mbedtls_ecp_group;
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+
+/**
+ * \brief           Internal restart context for multiplication
+ *
+ * \note            Opaque struct
+ */
+typedef struct mbedtls_ecp_restart_mul mbedtls_ecp_restart_mul_ctx;
+
+/**
+ * \brief           Internal restart context for ecp_muladd()
+ *
+ * \note            Opaque struct
+ */
+typedef struct mbedtls_ecp_restart_muladd mbedtls_ecp_restart_muladd_ctx;
+
+/**
+ * \brief           General context for resuming ECC operations
+ */
+typedef struct
+{
+    unsigned ops_done;                  /*!<  current ops count             */
+    unsigned depth;                     /*!<  call depth (0 = top-level)    */
+    mbedtls_ecp_restart_mul_ctx *rsm;   /*!<  ecp_mul_comb() sub-context    */
+    mbedtls_ecp_restart_muladd_ctx *ma; /*!<  ecp_muladd() sub-context      */
+} mbedtls_ecp_restart_ctx;
+
+/*
+ * Operation counts for restartable functions
+ */
+#define MBEDTLS_ECP_OPS_CHK   3 /*!< basic ops count for ecp_check_pubkey()  */
+#define MBEDTLS_ECP_OPS_DBL   8 /*!< basic ops count for ecp_double_jac()    */
+#define MBEDTLS_ECP_OPS_ADD  11 /*!< basic ops count for see ecp_add_mixed() */
+#define MBEDTLS_ECP_OPS_INV 120 /*!< empirical equivalent for mpi_mod_inv()  */
+
+/**
+ * \brief           Internal; for restartable functions in other modules.
+ *                  Check and update basic ops budget.
+ *
+ * \param grp       Group structure
+ * \param rs_ctx    Restart context
+ * \param ops       Number of basic ops to do
+ *
+ * \return          \c 0 if doing \p ops basic ops is still allowed,
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS otherwise.
+ */
+int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp,
+                              mbedtls_ecp_restart_ctx *rs_ctx,
+                              unsigned ops );
+
+/* Utility macro for checking and updating ops budget */
+#define MBEDTLS_ECP_BUDGET( ops )   \
+    MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, rs_ctx, \
+                                               (unsigned) (ops) ) );
+
+#else /* MBEDTLS_ECP_RESTARTABLE */
+
+#define MBEDTLS_ECP_BUDGET( ops )   /* no-op; for compatibility */
+
+/* We want to declare restartable versions of existing functions anyway */
+typedef void mbedtls_ecp_restart_ctx;
+
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 /**
  * \name SECTION: Module settings
  *
@@ -270,6 +338,75 @@ mbedtls_ecp_keypair;
  */
 #define MBEDTLS_ECP_TLS_NAMED_CURVE    3   /**< The named_curve of ECCurveType. */
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           Set the maximum number of basic operations done in a row.
+ *
+ *                  If more operations are needed to complete a computation,
+ *                  #MBEDTLS_ERR_ECP_IN_PROGRESS will be returned by the
+ *                  function performing the computation. It is then the
+ *                  caller's responsibility to either call again with the same
+ *                  parameters until it returns 0 or an error code; or to free
+ *                  the restart context if the operation is to be aborted.
+ *
+ *                  It is strictly required that all input parameters and the
+ *                  restart context be the same on successive calls for the
+ *                  same operation, but output parameters need not be the
+ *                  same; they must not be used until the function finally
+ *                  returns 0.
+ *
+ *                  This only applies to functions whose documentation
+ *                  mentions they may return #MBEDTLS_ERR_ECP_IN_PROGRESS (or
+ *                  #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS for functions in the
+ *                  SSL module). For functions that accept a "restart context"
+ *                  argument, passing NULL disables restart and makes the
+ *                  function equivalent to the function with the same name
+ *                  with \c _restartable removed. For functions in the ECDH
+ *                  module, restart is disabled unless the function accepts
+ *                  an "ECDH context" argument and
+ *                  mbedtls_ecdh_enable_restart() was previously called on
+ *                  that context. For function in the SSL module, restart is
+ *                  only enabled for specific sides and key exchanges
+ *                  (currently only for clients and ECDHE-ECDSA).
+ *
+ * \param max_ops   Maximum number of basic operations done in a row.
+ *                  Default: 0 (unlimited).
+ *                  Lower (non-zero) values mean ECC functions will block for
+ *                  a lesser maximum amount of time.
+ *
+ * \note            A "basic operation" is defined as a rough equivalent of a
+ *                  multiplication in GF(p) for the NIST P-256 curve.
+ *                  As an indication, with default settings, a scalar
+ *                  multiplication (full run of \c mbedtls_ecp_mul()) is:
+ *                  - about 3300 basic operations for P-256
+ *                  - about 9400 basic operations for P-384
+ *
+ * \note            Very low values are not always respected: sometimes
+ *                  functions need to block for a minimum number of
+ *                  operations, and will do so even if max_ops is set to a
+ *                  lower value.  That minimum depends on the curve size, and
+ *                  can be made lower by decreasing the value of
+ *                  \c MBEDTLS_ECP_WINDOW_SIZE.  As an indication, here is the
+ *                  lowest effective value for various curves and values of
+ *                  that parameter (w for short):
+ *                          w=6     w=5     w=4     w=3     w=2
+ *                  P-256   208     208     160     136     124
+ *                  P-384   682     416     320     272     248
+ *                  P-521  1364     832     640     544     496
+ *
+ * \note            This setting is currently ignored by Curve25519.
+ */
+void mbedtls_ecp_set_max_ops( unsigned max_ops );
+
+/**
+ * \brief           Check if restart is enabled (max_ops != 0)
+ *
+ * \return          \c 0 if \c max_ops == 0 (restart disabled)
+ * \return          \c 1 otherwise (restart enabled)
+ */
+int mbedtls_ecp_restart_is_enabled( void );
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 /**
  * \brief           This function retrieves the information defined in
  *                  mbedtls_ecp_curve_info() for all supported curves in order
@@ -366,6 +503,18 @@ void mbedtls_ecp_group_free( mbedtls_ecp_group *grp );
  */
 void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key );
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           Initialize a restart context
+ */
+void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx );
+
+/**
+ * \brief           Free the components of a restart context
+ */
+void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx );
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 /**
  * \brief           This function copies the contents of point \p Q into
  *                  point \p P.
@@ -598,6 +747,36 @@ int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
              int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
 
 /**
+ * \brief           This function performs multiplication of a point by
+ *                  an integer: \p R = \p m * \p P in a restartable way.
+ *
+ * \see             mbedtls_ecp_mul()
+ *
+ * \note            This function does the same as \c mbedtls_ecp_mul(), but
+ *                  it can return early and restart according to the limit set
+ *                  with \c mbedtls_ecp_set_max_ops() to reduce blocking.
+ *
+ * \param grp       The ECP group.
+ * \param R         The destination point.
+ * \param m         The integer by which to multiply.
+ * \param P         The point to multiply.
+ * \param f_rng     The RNG function.
+ * \param p_rng     The RNG context.
+ * \param rs_ctx    The restart context (NULL disables restart).
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private
+ *                  key, or \p P is not a valid public key.
+ * \return          #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ */
+int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+             const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+             mbedtls_ecp_restart_ctx *rs_ctx );
+
+/**
  * \brief           This function performs multiplication and addition of two
  *                  points by integers: \p R = \p m * \p P + \p n * \p Q
  *
@@ -624,6 +803,39 @@ int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
              const mbedtls_mpi *n, const mbedtls_ecp_point *Q );
 
 /**
+ * \brief           This function performs multiplication and addition of two
+ *                  points by integers: \p R = \p m * \p P + \p n * \p Q in a
+ *                  restartable way.
+ *
+ * \see             \c mbedtls_ecp_muladd()
+ *
+ * \note            This function works the same as \c mbedtls_ecp_muladd(),
+ *                  but it can return early and restart according to the limit
+ *                  set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
+ *
+ * \param grp       The ECP group.
+ * \param R         The destination point.
+ * \param m         The integer by which to multiply \p P.
+ * \param P         The point to multiply by \p m.
+ * \param n         The integer by which to multiply \p Q.
+ * \param Q         The point to be multiplied by \p n.
+ * \param rs_ctx    The restart context (NULL disables restart).
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not
+ *                  valid private keys, or \p P or \p Q are not valid public
+ *                  keys.
+ * \return          #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ */
+int mbedtls_ecp_muladd_restartable(
+             mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+             const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+             const mbedtls_mpi *n, const mbedtls_ecp_point *Q,
+             mbedtls_ecp_restart_ctx *rs_ctx );
+
+/**
  * \brief           This function checks that a point is a valid public key
  *                  on this curve.
  *
@@ -666,6 +878,23 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_po
 int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d );
 
 /**
+ * \brief           This function generates a private key.
+ *
+ * \param grp       The ECP group.
+ * \param d         The destination MPI (secret part).
+ * \param f_rng     The RNG function.
+ * \param p_rng     The RNG parameter.
+ *
+ * \return          \c 0 on success.
+ * \return          An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code
+ *                  on failure.
+ */
+int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp,
+                     mbedtls_mpi *d,
+                     int (*f_rng)(void *, unsigned char *, size_t),
+                     void *p_rng );
+
+/**
  * \brief           This function generates a keypair with a configurable base
  *                  point.
  *
diff --git a/crypto/mbedtls/include/mbedtls/error.h b/crypto/mbedtls/include/mbedtls/error.h
index 6b82d4f..0c38889 100644
--- a/crypto/mbedtls/include/mbedtls/error.h
+++ b/crypto/mbedtls/include/mbedtls/error.h
@@ -80,6 +80,7 @@
  * CHACHA20  3                  0x0051-0x0055
  * POLY1305  3                  0x0057-0x005B
  * CHACHAPOLY 2 0x0054-0x0056
+ * PLATFORM  1  0x0070-0x0072
  *
  * High-level module nr (3 bits - 0x0...-0x7...)
  * Name      ID  Nr of Errors
@@ -90,12 +91,12 @@
  * DHM       3   11
  * PK        3   15 (Started from top)
  * RSA       4   11
- * ECP       4   9 (Started from top)
+ * ECP       4   10 (Started from top)
  * MD        5   5
  * HKDF      5   1 (Started from top)
  * CIPHER    6   8
- * SSL       6   22 (Started from top)
- * SSL       7   31
+ * SSL       6   23 (Started from top)
+ * SSL       7   32
  *
  * Module dependent error code (5 bits 0x.00.-0x.F8.)
  */
diff --git a/crypto/mbedtls/include/mbedtls/gcm.h b/crypto/mbedtls/include/mbedtls/gcm.h
index 630733e..af0017f 100644
--- a/crypto/mbedtls/include/mbedtls/gcm.h
+++ b/crypto/mbedtls/include/mbedtls/gcm.h
@@ -41,7 +41,10 @@
 #define MBEDTLS_GCM_DECRYPT     0
 
 #define MBEDTLS_ERR_GCM_AUTH_FAILED                       -0x0012  /**< Authenticated decryption failed. */
+
+/* MBEDTLS_ERR_GCM_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_GCM_HW_ACCEL_FAILED                   -0x0013  /**< GCM hardware accelerator failed. */
+
 #define MBEDTLS_ERR_GCM_BAD_INPUT                         -0x0014  /**< Bad input parameters to function. */
 
 #ifdef __cplusplus
@@ -154,9 +157,9 @@ int mbedtls_gcm_setkey_noalloc( mbedtls_gcm_context *ctx,
  * \return          \c 0 if the encryption or decryption was performed
  *                  successfully. Note that in #MBEDTLS_GCM_DECRYPT mode,
  *                  this does not indicate that the data is authentic.
- * \return          #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths are not valid.
- * \return          #MBEDTLS_ERR_GCM_HW_ACCEL_FAILED or a cipher-specific
- *                  error code if the encryption or decryption failed.
+ * \return          #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths are not valid or
+ *                  a cipher-specific error code if the encryption
+ *                  or decryption failed.
  */
 int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx,
                        int mode,
@@ -193,9 +196,8 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx,
  *
  * \return          \c 0 if successful and authenticated.
  * \return          #MBEDTLS_ERR_GCM_AUTH_FAILED if the tag does not match.
- * \return          #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths are not valid.
- * \return          #MBEDTLS_ERR_GCM_HW_ACCEL_FAILED or a cipher-specific
- *                  error code if the decryption failed.
+ * \return          #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths are not valid or
+ *                  a cipher-specific error code if the decryption failed.
  */
 int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
                       size_t length,
diff --git a/crypto/mbedtls/include/mbedtls/hmac_drbg.h b/crypto/mbedtls/include/mbedtls/hmac_drbg.h
index 16b4a75..184ed1e 100644
--- a/crypto/mbedtls/include/mbedtls/hmac_drbg.h
+++ b/crypto/mbedtls/include/mbedtls/hmac_drbg.h
@@ -195,13 +195,33 @@ void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx,
  * \param additional    Additional data to update state with, or NULL
  * \param add_len       Length of additional data, or 0
  *
+ * \return              \c 0 on success, or an error from the underlying
+ *                      hash calculation.
+ *
  * \note                Additional data is optional, pass NULL and 0 as second
  *                      third argument if no additional data is being used.
  */
-void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
+int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
                        const unsigned char *additional, size_t add_len );
 
 /**
+ * \brief               HMAC_DRBG update state
+ *
+ * \warning             This function cannot report errors. You should use
+ *                      mbedtls_hmac_drbg_update_ret() instead.
+ *
+ * \param ctx           HMAC_DRBG context
+ * \param additional    Additional data to update state with, or NULL
+ * \param add_len       Length of additional data, or 0
+ *
+ * \note                Additional data is optional, pass NULL and 0 as second
+ *                      third argument if no additional data is being used.
+ */
+void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
+                               const unsigned char *additional,
+                               size_t add_len );
+
+/**
  * \brief               HMAC_DRBG reseeding (extracts data from entropy source)
  *
  * \param ctx           HMAC_DRBG context
diff --git a/crypto/mbedtls/include/mbedtls/md.h b/crypto/mbedtls/include/mbedtls/md.h
index bf29524..8bcf766 100644
--- a/crypto/mbedtls/include/mbedtls/md.h
+++ b/crypto/mbedtls/include/mbedtls/md.h
@@ -39,6 +39,8 @@
 #define MBEDTLS_ERR_MD_BAD_INPUT_DATA                     -0x5100  /**< Bad input parameters to function. */
 #define MBEDTLS_ERR_MD_ALLOC_FAILED                       -0x5180  /**< Failed to allocate memory. */
 #define MBEDTLS_ERR_MD_FILE_IO_ERROR                      -0x5200  /**< Opening or reading of file failed. */
+
+/* MBEDTLS_ERR_MD_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_MD_HW_ACCEL_FAILED                    -0x5280  /**< MD hardware accelerator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/md2.h b/crypto/mbedtls/include/mbedtls/md2.h
index a46bddb..f9bd98f 100644
--- a/crypto/mbedtls/include/mbedtls/md2.h
+++ b/crypto/mbedtls/include/mbedtls/md2.h
@@ -37,6 +37,7 @@
 
 #include <stddef.h>
 
+/* MBEDTLS_ERR_MD2_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_MD2_HW_ACCEL_FAILED                   -0x002B  /**< MD2 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/md4.h b/crypto/mbedtls/include/mbedtls/md4.h
index 1672e90..dc3c048 100644
--- a/crypto/mbedtls/include/mbedtls/md4.h
+++ b/crypto/mbedtls/include/mbedtls/md4.h
@@ -38,6 +38,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* MBEDTLS_ERR_MD4_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_MD4_HW_ACCEL_FAILED                   -0x002D  /**< MD4 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/md5.h b/crypto/mbedtls/include/mbedtls/md5.h
index 4c95090..6c3354f 100644
--- a/crypto/mbedtls/include/mbedtls/md5.h
+++ b/crypto/mbedtls/include/mbedtls/md5.h
@@ -37,6 +37,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* MBEDTLS_ERR_MD5_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_MD5_HW_ACCEL_FAILED                   -0x002F  /**< MD5 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/pk.h b/crypto/mbedtls/include/mbedtls/pk.h
index db54c6a..df3a03c 100644
--- a/crypto/mbedtls/include/mbedtls/pk.h
+++ b/crypto/mbedtls/include/mbedtls/pk.h
@@ -64,6 +64,8 @@
 #define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00  /**< Elliptic curve is unsupported (only NIST curves are supported). */
 #define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980  /**< Unavailable feature, e.g. RSA disabled for RSA key. */
 #define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH    -0x3900  /**< The buffer contains a valid signature followed by more data. */
+
+/* MBEDTLS_ERR_PK_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_PK_HW_ACCEL_FAILED     -0x3880  /**< PK hardware accelerator failed. */
 
 #ifdef __cplusplus
@@ -127,10 +129,24 @@ typedef struct mbedtls_pk_info_t mbedtls_pk_info_t;
  */
 typedef struct mbedtls_pk_context
 {
-    const mbedtls_pk_info_t *   pk_info; /**< Public key informations        */
+    const mbedtls_pk_info_t *   pk_info; /**< Public key information         */
     void *                      pk_ctx;  /**< Underlying public key context  */
 } mbedtls_pk_context;
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           Context for resuming operations
+ */
+typedef struct
+{
+    const mbedtls_pk_info_t *   pk_info; /**< Public key information         */
+    void *                      rs_ctx;  /**< Underlying restart context     */
+} mbedtls_pk_restart_ctx;
+#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+/* Now we can declare functions that take a pointer to that */
+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.
@@ -190,6 +206,18 @@ void mbedtls_pk_init( mbedtls_pk_context *ctx );
  */
 void mbedtls_pk_free( mbedtls_pk_context *ctx );
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           Initialize a restart context
+ */
+void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx );
+
+/**
+ * \brief           Free the components of a restart context
+ */
+void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx );
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
 /**
  * \brief           Initialize a PK context with the information given
  *                  and allocates the type-specific PK subcontext.
@@ -287,6 +315,32 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
                const unsigned char *sig, size_t sig_len );
 
 /**
+ * \brief           Restartable version of \c mbedtls_pk_verify()
+ *
+ * \note            Performs the same job as \c mbedtls_pk_verify(), but can
+ *                  return early and restart according to the limit set with
+ *                  \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC
+ *                  operations. For RSA, same as \c mbedtls_pk_verify().
+ *
+ * \param ctx       PK context to use
+ * \param md_alg    Hash algorithm used (see notes)
+ * \param hash      Hash of the message to sign
+ * \param hash_len  Hash length or 0 (see notes)
+ * \param sig       Signature to verify
+ * \param sig_len   Signature length
+ * \param rs_ctx    Restart context (NULL to disable restart)
+ *
+ * \return          See \c mbedtls_pk_verify(), or
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ */
+int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx,
+               mbedtls_md_type_t md_alg,
+               const unsigned char *hash, size_t hash_len,
+               const unsigned char *sig, size_t sig_len,
+               mbedtls_pk_restart_ctx *rs_ctx );
+
+/**
  * \brief           Verify signature, with options.
  *                  (Includes verification of the padding depending on type.)
  *
@@ -350,6 +404,35 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
              int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
 
 /**
+ * \brief           Restartable version of \c mbedtls_pk_sign()
+ *
+ * \note            Performs the same job as \c mbedtls_pk_sign(), but can
+ *                  return early and restart according to the limit set with
+ *                  \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC
+ *                  operations. For RSA, same as \c mbedtls_pk_sign().
+ *
+ * \param ctx       PK context to use - must hold a private key
+ * \param md_alg    Hash algorithm used (see notes)
+ * \param hash      Hash of the message to sign
+ * \param hash_len  Hash length or 0 (see notes)
+ * \param sig       Place to write the signature
+ * \param sig_len   Number of bytes written
+ * \param f_rng     RNG function
+ * \param p_rng     RNG parameter
+ * \param rs_ctx    Restart context (NULL to disable restart)
+ *
+ * \return          See \c mbedtls_pk_sign(), or
+ * \return          #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                  operations was reached: see \c mbedtls_ecp_set_max_ops().
+ */
+int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx,
+             mbedtls_md_type_t md_alg,
+             const unsigned char *hash, size_t hash_len,
+             unsigned char *sig, size_t *sig_len,
+             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+             mbedtls_pk_restart_ctx *rs_ctx );
+
+/**
  * \brief           Decrypt message (including padding if relevant).
  *
  * \param ctx       PK context to use - must hold a private key
diff --git a/crypto/mbedtls/include/mbedtls/pk_internal.h b/crypto/mbedtls/include/mbedtls/pk_internal.h
index 3dae0fc..48b7a5f 100644
--- a/crypto/mbedtls/include/mbedtls/pk_internal.h
+++ b/crypto/mbedtls/include/mbedtls/pk_internal.h
@@ -59,6 +59,21 @@ struct mbedtls_pk_info_t
                       int (*f_rng)(void *, unsigned char *, size_t),
                       void *p_rng );
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /** Verify signature (restartable) */
+    int (*verify_rs_func)( void *ctx, mbedtls_md_type_t md_alg,
+                           const unsigned char *hash, size_t hash_len,
+                           const unsigned char *sig, size_t sig_len,
+                           void *rs_ctx );
+
+    /** Make signature (restartable) */
+    int (*sign_rs_func)( void *ctx, mbedtls_md_type_t md_alg,
+                         const unsigned char *hash, size_t hash_len,
+                         unsigned char *sig, size_t *sig_len,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng, void *rs_ctx );
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
     /** Decrypt message */
     int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen,
                          unsigned char *output, size_t *olen, size_t osize,
@@ -80,6 +95,14 @@ struct mbedtls_pk_info_t
     /** Free the given context */
     void (*ctx_free_func)( void *ctx );
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /** Allocate the restart context */
+    void * (*rs_alloc_func)( void );
+
+    /** Free the restart context */
+    void (*rs_free_func)( void *rs_ctx );
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
     /** Interface with the debug module */
     void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items );
 
diff --git a/crypto/mbedtls/include/mbedtls/platform.h b/crypto/mbedtls/include/mbedtls/platform.h
index e299c16..240e856 100644
--- a/crypto/mbedtls/include/mbedtls/platform.h
+++ b/crypto/mbedtls/include/mbedtls/platform.h
@@ -40,9 +40,12 @@
 #endif
 
 #if defined(MBEDTLS_HAVE_TIME)
-#include "mbedlts/platform_time.h"
+#include "mbedtls/platform_time.h"
 #endif
 
+#define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED     -0x0070 /**< Hardware accelerator failed */
+#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/crypto/mbedtls/include/mbedtls/platform_util.h b/crypto/mbedtls/include/mbedtls/platform_util.h
index 84f0732..164a1a0 100644
--- a/crypto/mbedtls/include/mbedtls/platform_util.h
+++ b/crypto/mbedtls/include/mbedtls/platform_util.h
@@ -25,7 +25,17 @@
 #ifndef MBEDTLS_PLATFORM_UTIL_H
 #define MBEDTLS_PLATFORM_UTIL_H
 
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
 #include <stddef.h>
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include "mbedtls/platform_time.h"
+#include <time.h>
+#endif /* MBEDTLS_HAVE_TIME_DATE */
 
 #ifdef __cplusplus
 extern "C" {
@@ -55,6 +65,37 @@ extern "C" {
  */
 void mbedtls_platform_zeroize( void *buf, size_t len );
 
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+/**
+ * \brief      Platform-specific implementation of gmtime_r()
+ *
+ *             The function is a thread-safe abstraction that behaves
+ *             similarly to the gmtime_r() function from Unix/POSIX.
+ *
+ *             Mbed TLS will try to identify the underlying platform and
+ *             make use of an appropriate underlying implementation (e.g.
+ *             gmtime_r() for POSIX and gmtime_s() for Windows). If this is
+ *             not possible, then gmtime() will be used. In this case, calls
+ *             from the library to gmtime() will be guarded by the mutex
+ *             mbedtls_threading_gmtime_mutex if MBEDTLS_THREADING_C is
+ *             enabled. It is recommended that calls from outside the library
+ *             are also guarded by this mutex.
+ *
+ *             If MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, then Mbed TLS will
+ *             unconditionally use the alternative implementation for
+ *             mbedtls_platform_gmtime_r() supplied by the user at compile time.
+ *
+ * \param tt     Pointer to an object containing time (in seconds) since the
+ *               epoch to be converted
+ * \param tm_buf Pointer to an object where the results will be stored
+ *
+ * \return      Pointer to an object of type struct tm on success, otherwise
+ *              NULL
+ */
+struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
+                                      struct tm *tm_buf );
+#endif /* MBEDTLS_HAVE_TIME_DATE */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/crypto/mbedtls/include/mbedtls/poly1305.h b/crypto/mbedtls/include/mbedtls/poly1305.h
index c490cdf..b02f968 100644
--- a/crypto/mbedtls/include/mbedtls/poly1305.h
+++ b/crypto/mbedtls/include/mbedtls/poly1305.h
@@ -43,7 +43,13 @@
 #include <stddef.h>
 
 #define MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA         -0x0057 /**< Invalid input parameter(s). */
+
+/* MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE is deprecated and should not be
+ * used. */
 #define MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE    -0x0059 /**< Feature not available. For example, s part of the API is not implemented. */
+
+/* MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED        -0x005B  /**< Poly1305 hardware accelerator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/ripemd160.h b/crypto/mbedtls/include/mbedtls/ripemd160.h
index 0c8e568..c74b7d2 100644
--- a/crypto/mbedtls/include/mbedtls/ripemd160.h
+++ b/crypto/mbedtls/include/mbedtls/ripemd160.h
@@ -33,6 +33,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED             -0x0031  /**< RIPEMD160 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/rsa.h b/crypto/mbedtls/include/mbedtls/rsa.h
index 6eea5af..406a317 100644
--- a/crypto/mbedtls/include/mbedtls/rsa.h
+++ b/crypto/mbedtls/include/mbedtls/rsa.h
@@ -55,7 +55,12 @@
 #define MBEDTLS_ERR_RSA_VERIFY_FAILED                     -0x4380  /**< The PKCS#1 verification failed. */
 #define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE                  -0x4400  /**< The output buffer for decryption is not large enough. */
 #define MBEDTLS_ERR_RSA_RNG_FAILED                        -0x4480  /**< The random generator failed to generate non-zeros. */
+
+/* MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION is deprecated and should not be used.
+ */
 #define MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION             -0x4500  /**< The implementation does not offer the requested operation, for example, because of security violations or lack of functionality. */
+
+/* MBEDTLS_ERR_RSA_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_RSA_HW_ACCEL_FAILED                   -0x4580  /**< RSA hardware accelerator failed. */
 
 /*
@@ -281,7 +286,7 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx );
  *                 zero Bytes.
  *
  *                 Possible reasons for returning
- *                 #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:<ul>
+ *                 #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:<ul>
  *                 <li>An alternative RSA implementation is in use, which
  *                 stores the key externally, and either cannot or should
  *                 not export it into RAM.</li>
@@ -301,7 +306,7 @@ int mbedtls_rsa_complete( mbedtls_rsa_context *ctx );
  * \param E        The MPI to hold the public exponent, or NULL.
  *
  * \return         \c 0 on success.
- * \return         #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION if exporting the
+ * \return         #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if exporting the
  *                 requested parameters cannot be done due to missing
  *                 functionality or because of security policies.
  * \return         A non-zero return code on any other failure.
@@ -321,7 +326,7 @@ int mbedtls_rsa_export( const mbedtls_rsa_context *ctx,
  *                 zero Bytes.
  *
  *                 Possible reasons for returning
- *                 #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:<ul>
+ *                 #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:<ul>
  *                 <li>An alternative RSA implementation is in use, which
  *                 stores the key externally, and either cannot or should
  *                 not export it into RAM.</li>
@@ -350,7 +355,7 @@ int mbedtls_rsa_export( const mbedtls_rsa_context *ctx,
  * \param E_len    The size of the buffer for the public exponent.
  *
  * \return         \c 0 on success.
- * \return         #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION if exporting the
+ * \return         #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if exporting the
  *                 requested parameters cannot be done due to missing
  *                 functionality or because of security policies.
  * \return         A non-zero return code on any other failure.
@@ -563,7 +568,7 @@ int mbedtls_rsa_private( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Needed for padding, PKCS#1 v2.1
@@ -598,7 +603,7 @@ int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Needed for padding and
@@ -633,7 +638,7 @@ int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx,
  *
  * \note             Alternative implementations of RSA need not support
  *                   mode being set to #MBEDTLS_RSA_PRIVATE and might instead
- *                   return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                   return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx        The RSA context.
  * \param f_rng      The RNG function. Needed for padding and PKCS#1 v2.1
@@ -682,7 +687,7 @@ int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
@@ -725,7 +730,7 @@ int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
@@ -770,7 +775,7 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
  *
  * \note             Alternative implementations of RSA need not support
  *                   mode being set to #MBEDTLS_RSA_PUBLIC and might instead
- *                   return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                   return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx        The RSA context.
  * \param f_rng      The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
@@ -817,7 +822,7 @@ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Needed for PKCS#1 v2.1 encoding and for
@@ -856,7 +861,7 @@ int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
@@ -894,6 +899,16 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx,
  *                 Specifications</em> it is advised to keep both hashes the
  *                 same.
  *
+ * \note           This function always uses the maximum possible salt size,
+ *                 up to the length of the payload hash. This choice of salt
+ *                 size complies with FIPS 186-4 §5.5 (e) and RFC 8017 (PKCS#1
+ *                 v2.2) §9.1.1 step 3. Furthermore this function enforces a
+ *                 minimum salt size which is the hash size minus 2 bytes. If
+ *                 this minimum size is too large given the key size (the salt
+ *                 size, plus the hash size, plus 2 bytes must be no more than
+ *                 the key size in bytes), this function returns
+ *                 #MBEDTLS_ERR_RSA_BAD_INPUT_DATA.
+ *
  * \deprecated     It is deprecated and discouraged to call this function
  *                 in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library
  *                 are likely to remove the \p mode argument and have it
@@ -901,7 +916,7 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA context.
  * \param f_rng    The RNG function. Needed for PKCS#1 v2.1 encoding and for
@@ -947,7 +962,7 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA public key context.
  * \param f_rng    The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
@@ -985,7 +1000,7 @@ int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA public key context.
  * \param f_rng    The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
@@ -1034,7 +1049,7 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx,
  *
  * \note           Alternative implementations of RSA need not support
  *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead
- *                 return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION.
+ *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
  *
  * \param ctx      The RSA public key context.
  * \param f_rng    The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE.
diff --git a/crypto/mbedtls/include/mbedtls/sha1.h b/crypto/mbedtls/include/mbedtls/sha1.h
index 7a19da0..bcaeab5 100644
--- a/crypto/mbedtls/include/mbedtls/sha1.h
+++ b/crypto/mbedtls/include/mbedtls/sha1.h
@@ -40,6 +40,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED                  -0x0035  /**< SHA-1 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/sha256.h b/crypto/mbedtls/include/mbedtls/sha256.h
index 33aff28..47a31e8 100644
--- a/crypto/mbedtls/include/mbedtls/sha256.h
+++ b/crypto/mbedtls/include/mbedtls/sha256.h
@@ -36,6 +36,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED                -0x0037  /**< SHA-256 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/sha512.h b/crypto/mbedtls/include/mbedtls/sha512.h
index 0145890..020f95d 100644
--- a/crypto/mbedtls/include/mbedtls/sha512.h
+++ b/crypto/mbedtls/include/mbedtls/sha512.h
@@ -35,6 +35,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED                -0x0039  /**< SHA-512 hardware accelerator failed */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/ssl.h b/crypto/mbedtls/include/mbedtls/ssl.h
index 69fea93..ca11d9c 100644
--- a/crypto/mbedtls/include/mbedtls/ssl.h
+++ b/crypto/mbedtls/include/mbedtls/ssl.h
@@ -122,6 +122,7 @@
 #define MBEDTLS_ERR_SSL_CONTINUE_PROCESSING               -0x6580  /**< Internal-only message signaling that further message-processing should be done */
 #define MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS                 -0x6500  /**< The asynchronous operation is not completed yet. */
 #define MBEDTLS_ERR_SSL_EARLY_MESSAGE                     -0x6480  /**< Internal-only message signaling that a message arrived early. */
+#define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS                -0x7000  /**< A cryptographic operation is in progress. Try again later. */
 
 /*
  * Various constants
@@ -2773,13 +2774,14 @@ size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl );
 /**
  * \brief          Return the result of the certificate verification
  *
- * \param ssl      SSL context
+ * \param ssl      The SSL context to use.
  *
- * \return         0 if successful,
- *                 -1 if result is not available (eg because the handshake was
- *                 aborted too early), or
- *                 a combination of BADCERT_xxx and BADCRL_xxx flags, see
- *                 x509.h
+ * \return         \c 0 if the certificate verification was successful.
+ * \return         \c -1u if the result is not available. This may happen
+ *                 e.g. if the handshake aborts early, or a verification
+ *                 callback returned a fatal error.
+ * \return         A bitwise combination of \c MBEDTLS_X509_BADCERT_XXX
+ *                 and \c MBEDTLS_X509_BADCRL_XXX failure flags; see x509.h.
  */
 uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl );
 
@@ -2913,35 +2915,50 @@ int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session
  *
  * \param ssl      SSL context
  *
- * \return         0 if successful, or
- *                 MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or
- *                 MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED (see below), or
- *                 a specific SSL error code.
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE
+ *                 if the handshake is incomplete and waiting for data to
+ *                 be available for reading from or writing to the underlying
+ *                 transport - in this case you must call this function again
+ *                 when the underlying transport is ready for the operation.
+ * \return         #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous
+ *                 operation is in progress (see
+ *                 mbedtls_ssl_conf_async_private_cb()) - in this case you
+ *                 must call this function again when the operation is ready.
+ * \return         #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic
+ *                 operation is in progress (see mbedtls_ecp_set_max_ops()) -
+ *                 in this case you must call this function again to complete
+ *                 the handshake when you're done attending other tasks.
+ * \return         #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED if DTLS is in use
+ *                 and the client did not demonstrate reachability yet - in
+ *                 this case you must stop using the context (see below).
+ * \return         Another SSL error code - in this case you must stop using
+ *                 the context (see below).
+ *
+ * \warning        If this function returns something other than
+ *                 \c 0,
+ *                 #MBEDTLS_ERR_SSL_WANT_READ,
+ *                 #MBEDTLS_ERR_SSL_WANT_WRITE,
+ *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS,
+ *                 you must stop using the SSL context for reading or writing,
+ *                 and either free it or call \c mbedtls_ssl_session_reset()
+ *                 on it before re-using it for a new connection; the current
+ *                 connection must be closed.
  *
- *                 If this function returns MBEDTLS_ERR_SSL_WANT_READ, the
- *                 handshake is unfinished and no further data is available
- *                 from the underlying transport. In this case, you must call
- *                 the function again at some later stage.
+ * \note           If DTLS is in use, then you may choose to handle
+ *                 #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging
+ *                 purposes, as it is an expected return value rather than an
+ *                 actual error, but you still need to reset/free the context.
  *
  * \note           Remarks regarding event-driven DTLS:
- *                 If the function returns MBEDTLS_ERR_SSL_WANT_READ, no datagram
+ *                 If the function returns #MBEDTLS_ERR_SSL_WANT_READ, no datagram
  *                 from the underlying transport layer is currently being processed,
  *                 and it is safe to idle until the timer or the underlying transport
  *                 signal a new event. This is not true for a successful handshake,
  *                 in which case the datagram of the underlying transport that is
  *                 currently being processed might or might not contain further
  *                 DTLS records.
- *
- * \note           If this function returns something other than 0 or
- *                 MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using
- *                 the SSL context for reading or writing, and either free it or
- *                 call \c mbedtls_ssl_session_reset() on it before re-using it
- *                 for a new connection; the current connection must be closed.
- *
- * \note           If DTLS is in use, then you may choose to handle
- *                 MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging
- *                 purposes, as it is an expected return value rather than an
- *                 actual error, but you still need to reset/free the context.
  */
 int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl );
 
@@ -2949,20 +2966,21 @@ int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl );
  * \brief          Perform a single step of the SSL handshake
  *
  * \note           The state of the context (ssl->state) will be at
- *                 the next state after execution of this function. Do not
+ *                 the next state after this function returns \c 0. Do not
  *                 call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER.
  *
- * \note           If this function returns something other than 0 or
- *                 MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using
- *                 the SSL context for reading or writing, and either free it or
- *                 call \c mbedtls_ssl_session_reset() on it before re-using it
- *                 for a new connection; the current connection must be closed.
- *
  * \param ssl      SSL context
  *
- * \return         0 if successful, or
- *                 MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or
- *                 a specific SSL error code.
+ * \return         See mbedtls_ssl_handshake().
+ *
+ * \warning        If this function returns something other than \c 0,
+ *                 #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE,
+ *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, you must stop using
+ *                 the SSL context for reading or writing, and either free it
+ *                 or call \c mbedtls_ssl_session_reset() on it before
+ *                 re-using it for a new connection; the current connection
+ *                 must be closed.
  */
 int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl );
 
@@ -2977,13 +2995,18 @@ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl );
  * \param ssl      SSL context
  *
  * \return         0 if successful, or any mbedtls_ssl_handshake() return
- *                 value.
+ *                 value except #MBEDTLS_ERR_SSL_CLIENT_RECONNECT that can't
+ *                 happen during a renegotiation.
+ *
+ * \warning        If this function returns something other than \c 0,
+ *                 #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE,
+ *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, you must stop using
+ *                 the SSL context for reading or writing, and either free it
+ *                 or call \c mbedtls_ssl_session_reset() on it before
+ *                 re-using it for a new connection; the current connection
+ *                 must be closed.
  *
- * \note           If this function returns something other than 0 or
- *                 MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using
- *                 the SSL context for reading or writing, and either free it or
- *                 call \c mbedtls_ssl_session_reset() on it before re-using it
- *                 for a new connection; the current connection must be closed.
  */
 int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
@@ -2995,42 +3018,56 @@ int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl );
  * \param buf      buffer that will hold the data
  * \param len      maximum number of bytes to read
  *
- * \return         One of the following:
- *                 - 0 if the read end of the underlying transport was closed,
- *                 - the (positive) number of bytes read, or
- *                 - a negative error code on failure.
- *
- *                 If MBEDTLS_ERR_SSL_WANT_READ is returned, no application data
- *                 is available from the underlying transport. In this case,
- *                 the function needs to be called again at some later stage.
- *
- *                 If MBEDTLS_ERR_SSL_WANT_WRITE is returned, a write is pending
- *                 but the underlying transport isn't available for writing. In this
- *                 case, the function needs to be called again at some later stage.
+ * \return         The (positive) number of bytes read if successful.
+ * \return         \c 0 if the read end of the underlying transport was closed
+ *                 - in this case you must stop using the context (see below).
+ * \return         #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE
+ *                 if the handshake is incomplete and waiting for data to
+ *                 be available for reading from or writing to the underlying
+ *                 transport - in this case you must call this function again
+ *                 when the underlying transport is ready for the operation.
+ * \return         #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous
+ *                 operation is in progress (see
+ *                 mbedtls_ssl_conf_async_private_cb()) - in this case you
+ *                 must call this function again when the operation is ready.
+ * \return         #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic
+ *                 operation is in progress (see mbedtls_ecp_set_max_ops()) -
+ *                 in this case you must call this function again to complete
+ *                 the handshake when you're done attending other tasks.
+ * \return         #MBEDTLS_ERR_SSL_CLIENT_RECONNECT if we're at the server
+ *                 side of a DTLS connection and the client is initiating a
+ *                 new connection using the same source port. See below.
+ * \return         Another SSL error code - in this case you must stop using
+ *                 the context (see below).
+ *
+ * \warning        If this function returns something other than
+ *                 a positive value,
+ *                 #MBEDTLS_ERR_SSL_WANT_READ,
+ *                 #MBEDTLS_ERR_SSL_WANT_WRITE,
+ *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS,
+ *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_CLIENT_RECONNECT,
+ *                 you must stop using the SSL context for reading or writing,
+ *                 and either free it or call \c mbedtls_ssl_session_reset()
+ *                 on it before re-using it for a new connection; the current
+ *                 connection must be closed.
  *
- *                 When this function return MBEDTLS_ERR_SSL_CLIENT_RECONNECT
+ * \note           When this function returns #MBEDTLS_ERR_SSL_CLIENT_RECONNECT
  *                 (which can only happen server-side), it means that a client
  *                 is initiating a new connection using the same source port.
  *                 You can either treat that as a connection close and wait
  *                 for the client to resend a ClientHello, or directly
  *                 continue with \c mbedtls_ssl_handshake() with the same
- *                 context (as it has beeen reset internally). Either way, you
- *                 should make sure this is seen by the application as a new
+ *                 context (as it has been reset internally). Either way, you
+ *                 must make sure this is seen by the application as a new
  *                 connection: application state, if any, should be reset, and
  *                 most importantly the identity of the client must be checked
  *                 again. WARNING: not validating the identity of the client
  *                 again, or not transmitting the new identity to the
  *                 application layer, would allow authentication bypass!
  *
- * \note           If this function returns something other than a positive value
- *                 or MBEDTLS_ERR_SSL_WANT_READ/WRITE or MBEDTLS_ERR_SSL_CLIENT_RECONNECT,
- *                 you must stop using the SSL context for reading or writing,
- *                 and either free it or call \c mbedtls_ssl_session_reset() on it
- *                 before re-using it for a new connection; the current connection
- *                 must be closed.
- *
  * \note           Remarks regarding event-driven DTLS:
- *                 - If the function returns MBEDTLS_ERR_SSL_WANT_READ, no datagram
+ *                 - If the function returns #MBEDTLS_ERR_SSL_WANT_READ, no datagram
  *                   from the underlying transport layer is currently being processed,
  *                   and it is safe to idle until the timer or the underlying transport
  *                   signal a new event.
@@ -3059,21 +3096,39 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len )
  * \param buf      buffer holding the data
  * \param len      how many bytes must be written
  *
- * \return         the number of bytes actually written (may be less than len),
- *                 or MBEDTLS_ERR_SSL_WANT_WRITE or MBEDTLS_ERR_SSL_WANT_READ,
- *                 or another negative error code.
- *
- * \note           If this function returns something other than 0, a positive
- *                 value or MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop
- *                 using the SSL context for reading or writing, and either
- *                 free it or call \c mbedtls_ssl_session_reset() on it before
- *                 re-using it for a new connection; the current connection
- *                 must be closed.
+ * \return         The (non-negative) number of bytes actually written if
+ *                 successful (may be less than \p len).
+ * \return         #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE
+ *                 if the handshake is incomplete and waiting for data to
+ *                 be available for reading from or writing to the underlying
+ *                 transport - in this case you must call this function again
+ *                 when the underlying transport is ready for the operation.
+ * \return         #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous
+ *                 operation is in progress (see
+ *                 mbedtls_ssl_conf_async_private_cb()) - in this case you
+ *                 must call this function again when the operation is ready.
+ * \return         #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic
+ *                 operation is in progress (see mbedtls_ecp_set_max_ops()) -
+ *                 in this case you must call this function again to complete
+ *                 the handshake when you're done attending other tasks.
+ * \return         Another SSL error code - in this case you must stop using
+ *                 the context (see below).
+ *
+ * \warning        If this function returns something other than
+ *                 a non-negative value,
+ *                 #MBEDTLS_ERR_SSL_WANT_READ,
+ *                 #MBEDTLS_ERR_SSL_WANT_WRITE,
+ *                 #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or
+ *                 #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS,
+ *                 you must stop using the SSL context for reading or writing,
+ *                 and either free it or call \c mbedtls_ssl_session_reset()
+ *                 on it before re-using it for a new connection; the current
+ *                 connection must be closed.
  *
- * \note           When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ,
+ * \note           When this function returns #MBEDTLS_ERR_SSL_WANT_WRITE/READ,
  *                 it must be called later with the *same* arguments,
  *                 until it returns a value greater that or equal to 0. When
- *                 the function returns MBEDTLS_ERR_SSL_WANT_WRITE there may be
+ *                 the function returns #MBEDTLS_ERR_SSL_WANT_WRITE there may be
  *                 some partial data in the output buffer, however this is not
  *                 yet sent.
  *
diff --git a/crypto/mbedtls/include/mbedtls/ssl_internal.h b/crypto/mbedtls/include/mbedtls/ssl_internal.h
index 4b4417a..97abb9f 100644
--- a/crypto/mbedtls/include/mbedtls/ssl_internal.h
+++ b/crypto/mbedtls/include/mbedtls/ssl_internal.h
@@ -93,6 +93,14 @@
 #endif /* MBEDTLS_SSL_PROTO_TLS1_1 */
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 
+/* Shorthand for restartable ECC */
+#if defined(MBEDTLS_ECP_RESTARTABLE) && \
+    defined(MBEDTLS_SSL_CLI_C) && \
+    defined(MBEDTLS_SSL_PROTO_TLS1_2) && \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#define MBEDTLS_SSL__ECP_RESTARTABLE
+#endif
+
 #define MBEDTLS_SSL_INITIAL_HANDSHAKE           0
 #define MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS   1   /* In progress */
 #define MBEDTLS_SSL_RENEGOTIATION_DONE          2   /* Done or aborted */
@@ -287,7 +295,18 @@ struct mbedtls_ssl_handshake_params
     mbedtls_x509_crl *sni_ca_crl;       /*!< trusted CAs CRLs from SNI      */
 #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
-
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    int ecrs_enabled;                   /*!< Handshake supports EC restart? */
+    mbedtls_x509_crt_restart_ctx ecrs_ctx;  /*!< restart context            */
+    enum { /* this complements ssl->state with info on intra-state operations */
+        ssl_ecrs_none = 0,              /*!< nothing going on (yet)         */
+        ssl_ecrs_crt_verify,            /*!< Certificate: crt_verify()      */
+        ssl_ecrs_ske_start_processing,  /*!< ServerKeyExchange: pk_verify() */
+        ssl_ecrs_cke_ecdh_calc_secret,  /*!< ClientKeyExchange: ECDH step 2 */
+        ssl_ecrs_crt_vrfy_sign,         /*!< CertificateVerify: pk_sign()   */
+    } ecrs_state;                       /*!< current (or last) operation    */
+    size_t ecrs_n;                      /*!< place for saving a length      */
+#endif
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     unsigned int out_msg_seq;           /*!<  Outgoing handshake sequence number */
     unsigned int in_msg_seq;            /*!<  Incoming handshake sequence number */
diff --git a/crypto/mbedtls/include/mbedtls/threading.h b/crypto/mbedtls/include/mbedtls/threading.h
index 5112ebb..92e6e6b 100644
--- a/crypto/mbedtls/include/mbedtls/threading.h
+++ b/crypto/mbedtls/include/mbedtls/threading.h
@@ -36,7 +36,10 @@
 extern "C" {
 #endif
 
+/* MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE is deprecated and should not be
+ * used. */
 #define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE         -0x001A  /**< The selected feature is not available. */
+
 #define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA              -0x001C  /**< Bad input parameters to function. */
 #define MBEDTLS_ERR_THREADING_MUTEX_ERROR                 -0x001E  /**< Locking / unlocking / free failed with error code. */
 
@@ -99,6 +102,17 @@ extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex );
 #if defined(MBEDTLS_FS_IO)
 extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex;
 #endif
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+/* This mutex may or may not be used in the default definition of
+ * mbedtls_platform_gmtime_r(), but in order to determine that,
+ * we need to check POSIX features, hence modify _POSIX_C_SOURCE.
+ * With the current approach, this declaration is orphaned, lacking
+ * an accompanying definition, in case mbedtls_platform_gmtime_r()
+ * doesn't need it, but that's not a problem. */
+extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex;
+#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
+
 #endif /* MBEDTLS_THREADING_C */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/include/mbedtls/version.h b/crypto/mbedtls/include/mbedtls/version.h
index 17b8ba4..9ce0942 100644
--- a/crypto/mbedtls/include/mbedtls/version.h
+++ b/crypto/mbedtls/include/mbedtls/version.h
@@ -39,17 +39,17 @@
  * Major, Minor, Patchlevel
  */
 #define MBEDTLS_VERSION_MAJOR  2
-#define MBEDTLS_VERSION_MINOR  13
-#define MBEDTLS_VERSION_PATCH  0
+#define MBEDTLS_VERSION_MINOR  14
+#define MBEDTLS_VERSION_PATCH  1
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x020D0000
-#define MBEDTLS_VERSION_STRING         "2.13.0"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.13.0"
+#define MBEDTLS_VERSION_NUMBER         0x020E0100
+#define MBEDTLS_VERSION_STRING         "2.14.1"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.14.1"
 
 #if defined(MBEDTLS_VERSION_C)
 
diff --git a/crypto/mbedtls/include/mbedtls/x509_crt.h b/crypto/mbedtls/include/mbedtls/x509_crt.h
index d41ec93..afeefca 100644
--- a/crypto/mbedtls/include/mbedtls/x509_crt.h
+++ b/crypto/mbedtls/include/mbedtls/x509_crt.h
@@ -143,6 +143,63 @@ typedef struct mbedtls_x509write_cert
 }
 mbedtls_x509write_cert;
 
+/**
+ * Item in a verification chain: cert and flags for it
+ */
+typedef struct {
+    mbedtls_x509_crt *crt;
+    uint32_t flags;
+} mbedtls_x509_crt_verify_chain_item;
+
+/**
+ * Max size of verification chain: end-entity + intermediates + trusted root
+ */
+#define MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE  ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 )
+
+/**
+ * Verification chain as built by \c mbedtls_crt_verify_chain()
+ */
+typedef struct
+{
+    mbedtls_x509_crt_verify_chain_item items[MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE];
+    unsigned len;
+} mbedtls_x509_crt_verify_chain;
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+
+/**
+ * \brief       Context for resuming X.509 verify operations
+ */
+typedef struct
+{
+    /* for check_signature() */
+    mbedtls_pk_restart_ctx pk;
+
+    /* for find_parent_in() */
+    mbedtls_x509_crt *parent; /* non-null iff parent_in in progress */
+    mbedtls_x509_crt *fallback_parent;
+    int fallback_signature_is_good;
+
+    /* for find_parent() */
+    int parent_is_trusted; /* -1 if find_parent is not in progress */
+
+    /* for verify_chain() */
+    enum {
+        x509_crt_rs_none,
+        x509_crt_rs_find_parent,
+    } in_progress;  /* none if no operation is in progress */
+    int self_cnt;
+    mbedtls_x509_crt_verify_chain ver_chain;
+
+} mbedtls_x509_crt_restart_ctx;
+
+#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
+/* Now we can declare functions that take a pointer to that */
+typedef void mbedtls_x509_crt_restart_ctx;
+
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 /**
  * Default security profile. Should provide a good balance between security
@@ -353,6 +410,37 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
                      int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
                      void *p_vrfy );
 
+/**
+ * \brief          Restartable version of \c mbedtls_crt_verify_with_profile()
+ *
+ * \note           Performs the same job as \c mbedtls_crt_verify_with_profile()
+ *                 but can return early and restart according to the limit
+ *                 set with \c mbedtls_ecp_set_max_ops() to reduce blocking.
+ *
+ * \param crt      a certificate (chain) to be verified
+ * \param trust_ca the list of trusted CAs
+ * \param ca_crl   the list of CRLs for trusted CAs
+ * \param profile  security profile for verification
+ * \param cn       expected Common Name (can be set to
+ *                 NULL if the CN must not be verified)
+ * \param flags    result of the verification
+ * \param f_vrfy   verification function
+ * \param p_vrfy   verification parameter
+ * \param rs_ctx   restart context (NULL to disable restart)
+ *
+ * \return         See \c mbedtls_crt_verify_with_profile(), or
+ * \return         #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ *                 operations was reached: see \c mbedtls_ecp_set_max_ops().
+ */
+int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt,
+                     mbedtls_x509_crt *trust_ca,
+                     mbedtls_x509_crl *ca_crl,
+                     const mbedtls_x509_crt_profile *profile,
+                     const char *cn, uint32_t *flags,
+                     int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
+                     void *p_vrfy,
+                     mbedtls_x509_crt_restart_ctx *rs_ctx );
+
 #if defined(MBEDTLS_X509_CHECK_KEY_USAGE)
 /**
  * \brief          Check usage of certificate against keyUsage extension.
@@ -424,6 +512,18 @@ void mbedtls_x509_crt_init( mbedtls_x509_crt *crt );
  * \param crt      Certificate chain to free
  */
 void mbedtls_x509_crt_free( mbedtls_x509_crt *crt );
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+/**
+ * \brief           Initialize a restart context
+ */
+void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx );
+
+/**
+ * \brief           Free the components of a restart context
+ */
+void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx );
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 /* \} name */
diff --git a/crypto/mbedtls/include/mbedtls/xtea.h b/crypto/mbedtls/include/mbedtls/xtea.h
index c70c3fe..6430c13 100644
--- a/crypto/mbedtls/include/mbedtls/xtea.h
+++ b/crypto/mbedtls/include/mbedtls/xtea.h
@@ -37,6 +37,8 @@
 #define MBEDTLS_XTEA_DECRYPT     0
 
 #define MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH             -0x0028  /**< The data input has an invalid length. */
+
+/* MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED is deprecated and should not be used. */
 #define MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED                  -0x0029  /**< XTEA hardware accelerator failed. */
 
 #ifdef __cplusplus
diff --git a/crypto/mbedtls/src/aes.c b/crypto/mbedtls/src/aes.c
index 5c939bb..3de571e 100644
--- a/crypto/mbedtls/src/aes.c
+++ b/crypto/mbedtls/src/aes.c
@@ -36,6 +36,7 @@
 #include <string.h>
 
 #include "mbedtls/aes.h"
+#include "mbedtls/platform.h"
 #include "mbedtls/platform_util.h"
 #if defined(MBEDTLS_PADLOCK_C)
 #include "mbedtls/padlock.h"
@@ -1142,11 +1143,11 @@ int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx,
     unsigned char prev_tweak[16];
     unsigned char tmp[16];
 
-    /* Sectors must be at least 16 bytes. */
+    /* Data units must be at least 16 bytes long. */
     if( length < 16 )
         return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
 
-    /* NIST SP 80-38E disallows data units larger than 2**20 blocks. */
+    /* NIST SP 800-38E disallows data units larger than 2**20 blocks. */
     if( length > ( 1 << 20 ) * 16 )
         return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
 
@@ -1757,7 +1758,7 @@ int mbedtls_aes_self_test( int verbose )
          * there is an alternative underlying implementation i.e. when
          * MBEDTLS_AES_ALT is defined.
          */
-        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 )
         {
             mbedtls_printf( "skipped\n" );
             continue;
@@ -1821,7 +1822,7 @@ int mbedtls_aes_self_test( int verbose )
          * there is an alternative underlying implementation i.e. when
          * MBEDTLS_AES_ALT is defined.
          */
-        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 )
         {
             mbedtls_printf( "skipped\n" );
             continue;
@@ -1886,7 +1887,7 @@ int mbedtls_aes_self_test( int verbose )
          * there is an alternative underlying implementation i.e. when
          * MBEDTLS_AES_ALT is defined.
          */
-        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 )
         {
             mbedtls_printf( "skipped\n" );
             continue;
@@ -1949,7 +1950,7 @@ int mbedtls_aes_self_test( int verbose )
          * there is an alternative underlying implementation i.e. when
          * MBEDTLS_AES_ALT is defined.
          */
-        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 )
         {
             mbedtls_printf( "skipped\n" );
             continue;
diff --git a/crypto/mbedtls/src/asn1write.c b/crypto/mbedtls/src/asn1write.c
index 72acdf3..d617de5 100644
--- a/crypto/mbedtls/src/asn1write.c
+++ b/crypto/mbedtls/src/asn1write.c
@@ -257,34 +257,37 @@ int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
     return( (int) len );
 }
 
-int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
-                                 const char *text, size_t text_len )
+int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag,
+    const char *text, size_t text_len )
 {
     int ret;
     size_t len = 0;
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
-                  (const unsigned char *) text, text_len ) );
+        (const unsigned char *) text, text_len ) );
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_PRINTABLE_STRING ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );
 
     return( (int) len );
 }
 
-int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
-                           const char *text, size_t text_len )
+int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start,
+    const char *text, size_t text_len )
 {
-    int ret;
-    size_t len = 0;
-
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
-                  (const unsigned char *) text, text_len ) );
+    return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) );
+}
 
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) );
+int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
+                                 const char *text, size_t text_len )
+{
+    return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) );
+}
 
-    return( (int) len );
+int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
+                           const char *text, size_t text_len )
+{
+    return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) );
 }
 
 int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
diff --git a/crypto/mbedtls/src/bignum.c b/crypto/mbedtls/src/bignum.c
index 423e375..be4df2f 100644
--- a/crypto/mbedtls/src/bignum.c
+++ b/crypto/mbedtls/src/bignum.c
@@ -321,6 +321,10 @@ int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
     return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
 }
 
+/* Get a specific byte, without range checks. */
+#define GET_BYTE( X, i )                                \
+    ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff )
+
 /*
  * Set a bit to a specific value of 0 or 1
  */
@@ -704,19 +708,40 @@ cleanup:
 /*
  * Export X into unsigned binary data, big endian
  */
-int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
+int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
+                              unsigned char *buf, size_t buflen )
 {
-    size_t i, j, n;
-
-    n = mbedtls_mpi_size( X );
-
-    if( buflen < n )
-        return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+    size_t stored_bytes = X->n * ciL;
+    size_t bytes_to_copy;
+    unsigned char *p;
+    size_t i;
 
-    memset( buf, 0, buflen );
+    if( stored_bytes < buflen )
+    {
+        /* There is enough space in the output buffer. Write initial
+         * null bytes and record the position at which to start
+         * writing the significant bytes. In this case, the execution
+         * trace of this function does not depend on the value of the
+         * number. */
+        bytes_to_copy = stored_bytes;
+        p = buf + buflen - stored_bytes;
+        memset( buf, 0, buflen - stored_bytes );
+    }
+    else
+    {
+        /* The output buffer is smaller than the allocated size of X.
+         * However X may fit if its leading bytes are zero. */
+        bytes_to_copy = buflen;
+        p = buf;
+        for( i = bytes_to_copy; i < stored_bytes; i++ )
+        {
+            if( GET_BYTE( X, i ) != 0 )
+                return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+        }
+    }
 
-    for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
-        buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+    for( i = 0; i < bytes_to_copy; i++ )
+        p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
 
     return( 0 );
 }
@@ -2056,12 +2081,12 @@ cleanup:
 /*
  * Miller-Rabin pseudo-primality test  (HAC 4.24)
  */
-static int mpi_miller_rabin( const mbedtls_mpi *X,
+static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds,
                              int (*f_rng)(void *, unsigned char *, size_t),
                              void *p_rng )
 {
     int ret, count;
-    size_t i, j, k, n, s;
+    size_t i, j, k, s;
     mbedtls_mpi W, R, T, A, RR;
 
     mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A );
@@ -2077,27 +2102,12 @@ static int mpi_miller_rabin( const mbedtls_mpi *X,
     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
 
     i = mbedtls_mpi_bitlen( X );
-    /*
-     * HAC, table 4.4
-     */
-    n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
-          ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
-          ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
 
-    for( i = 0; i < n; i++ )
+    for( i = 0; i < rounds; i++ )
     {
         /*
          * pick a random A, 1 < A < |X| - 1
          */
-        MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
-
-        if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 )
-        {
-            j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W );
-            MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) );
-        }
-        A.p[0] |= 3;
-
         count = 0;
         do {
             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
@@ -2105,7 +2115,7 @@ static int mpi_miller_rabin( const mbedtls_mpi *X,
             j = mbedtls_mpi_bitlen( &A );
             k = mbedtls_mpi_bitlen( &W );
             if (j > k) {
-                MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) );
+                A.p[A.n - 1] &= ( (mbedtls_mpi_uint) 1 << ( k - ( A.n - 1 ) * biL - 1 ) ) - 1;
             }
 
             if (count++ > 30) {
@@ -2160,9 +2170,9 @@ cleanup:
 /*
  * Pseudo-primality test: small factors, then Miller-Rabin
  */
-int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
-                  int (*f_rng)(void *, unsigned char *, size_t),
-                  void *p_rng )
+int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds,
+                              int (*f_rng)(void *, unsigned char *, size_t),
+                              void *p_rng )
 {
     int ret;
     mbedtls_mpi XX;
@@ -2186,17 +2196,34 @@ int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
         return( ret );
     }
 
-    return( mpi_miller_rabin( &XX, f_rng, p_rng ) );
+    return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) );
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+/*
+ * Pseudo-primality test, error probability 2^-80
+ */
+int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
+                  int (*f_rng)(void *, unsigned char *, size_t),
+                  void *p_rng )
+{
+    /*
+     * In the past our key generation aimed for an error rate of at most
+     * 2^-80. Since this function is deprecated, aim for the same certainty
+     * here as well.
+     */
+    return mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng );
 }
+#endif
 
 /*
  * Prime number generation
  *
- * If dh_flag is 0 and nbits is at least 1024, then the procedure
- * follows the RSA probably-prime generation method of FIPS 186-4.
- * NB. FIPS 186-4 only allows the specific bit lengths of 1024 and 1536.
+ * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
+ * be either 1024 bits or 1536 bits long, and flags must contain
+ * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
  */
-int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
+int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags,
                    int (*f_rng)(void *, unsigned char *, size_t),
                    void *p_rng )
 {
@@ -2209,6 +2236,7 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
 #endif
     int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
     size_t k, n;
+    int rounds;
     mbedtls_mpi_uint r;
     mbedtls_mpi Y;
 
@@ -2219,6 +2247,27 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
 
     n = BITS_TO_LIMBS( nbits );
 
+    if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 )
+    {
+        /*
+         * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
+         */
+        rounds = ( ( nbits >= 1300 ) ?  2 : ( nbits >=  850 ) ?  3 :
+                   ( nbits >=  650 ) ?  4 : ( nbits >=  350 ) ?  8 :
+                   ( nbits >=  250 ) ? 12 : ( nbits >=  150 ) ? 18 : 27 );
+    }
+    else
+    {
+        /*
+         * 2^-100 error probability, number of rounds computed based on HAC,
+         * fact 4.48
+         */
+        rounds = ( ( nbits >= 1450 ) ?  4 : ( nbits >=  1150 ) ?  5 :
+                   ( nbits >= 1000 ) ?  6 : ( nbits >=   850 ) ?  7 :
+                   ( nbits >=  750 ) ?  8 : ( nbits >=   500 ) ? 13 :
+                   ( nbits >=  250 ) ? 28 : ( nbits >=   150 ) ? 40 : 51 );
+    }
+
     while( 1 )
     {
         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
@@ -2229,9 +2278,9 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
         if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) );
         X->p[0] |= 1;
 
-        if( dh_flag == 0 )
+        if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 )
         {
-            ret = mbedtls_mpi_is_prime( X, f_rng, p_rng );
+            ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng );
 
             if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
                 goto cleanup;
@@ -2264,8 +2313,10 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
                  */
                 if( ( ret = mpi_check_small_factors(  X         ) ) == 0 &&
                     ( ret = mpi_check_small_factors( &Y         ) ) == 0 &&
-                    ( ret = mpi_miller_rabin(  X, f_rng, p_rng  ) ) == 0 &&
-                    ( ret = mpi_miller_rabin( &Y, f_rng, p_rng  ) ) == 0 )
+                    ( ret = mpi_miller_rabin(  X, rounds, f_rng, p_rng  ) )
+                                                                    == 0 &&
+                    ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng  ) )
+                                                                    == 0 )
                     goto cleanup;
 
                 if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
diff --git a/crypto/mbedtls/src/certs.c b/crypto/mbedtls/src/certs.c
index f1379b8..ff0f11e 100644
--- a/crypto/mbedtls/src/certs.c
+++ b/crypto/mbedtls/src/certs.c
@@ -218,12 +218,13 @@ const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa );
 const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest";
 const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1;
 
+/* tests/data_files/server2.crt */
 const char mbedtls_test_srv_crt_rsa[] =
 "-----BEGIN CERTIFICATE-----\r\n"
 "MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"
-"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
+"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
 "MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"
-"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"
+"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"
 "AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n"
 "owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n"
 "NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n"
@@ -231,16 +232,17 @@ const char mbedtls_test_srv_crt_rsa[] =
 "hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n"
 "HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n"
 "VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n"
-"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n"
-"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n"
-"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n"
-"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n"
-"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n"
-"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n"
-"zhuYwjVuX6JHG0c=\r\n"
+"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAAFzC0rF\r\n"
+"y6De8WMcdgQrEw3AhBHFjzqnxZw1ene4IBSC7lTw8rBSy3jOWQdPUWn+0y/pCeeF\r\n"
+"kti6sevFdl1hLemGtd4q+T9TKEKGg3ND4ARfB5AUZZ9uEHq8WBkiwus5clGS17Qd\r\n"
+"dS/TOisB59tQruLx1E1bPLtBKyqk4koC5WAULJwfpswGSyWJTpYwIpxcWE3D2tBu\r\n"
+"UB6MZfXZFzWmWEOyKbeoXjXe8GBCGgHLywvYDsGQ36HSGtEsAvR2QaTLSxWYcfk1\r\n"
+"fbDn4jSWkb4yZy1r01UEigFQtONieGwRFaUqEcFJHJvEEGVgh9keaVlOj2vrwf5r\r\n"
+"4mN4lW7gLdenN6g=\r\n"
 "-----END CERTIFICATE-----\r\n";
 const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
 
+/* tests/data_files/server2.key */
 const char mbedtls_test_srv_key_rsa[] =
 "-----BEGIN RSA PRIVATE KEY-----\r\n"
 "MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n"
@@ -271,11 +273,12 @@ const char mbedtls_test_srv_key_rsa[] =
 "-----END RSA PRIVATE KEY-----\r\n";
 const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa );
 
+/* tests/data_files/cli-rsa-sha256.crt */
 const char mbedtls_test_cli_crt_rsa[] =
 "-----BEGIN CERTIFICATE-----\r\n"
-"MIIDhTCCAm2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"
+"MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"
 "MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
-"MTcwNTA1MTMwNzU5WhcNMjcwNTA2MTMwNzU5WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n"
+"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n"
 "A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n"
 "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n"
 "M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n"
@@ -283,18 +286,18 @@ const char mbedtls_test_cli_crt_rsa[] =
 "MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n"
 "4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n"
 "/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n"
-"o4GSMIGPMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITBjBgNVHSMEXDBa\r\n"
-"gBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNV\r\n"
-"BAoMCFBvbGFyU1NMMRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBggEAMAkGA1Ud\r\n"
-"EwQCMAAwDQYJKoZIhvcNAQELBQADggEBAC7yO786NvcHpK8UovKIG9cB32oSQQom\r\n"
-"LoR0eHDRzdqEkoq7yGZufHFiRAAzbMqJfogRtxlrWAeB4y/jGaMBV25IbFOIcH2W\r\n"
-"iCEaMMbG+VQLKNvuC63kmw/Zewc9ThM6Pa1Hcy0axT0faf1B/U01j0FIcw/6mTfK\r\n"
-"D8w48OIwc1yr0JtutCVjig5DC0yznGMt32RyseOLcUe+lfq005v2PAiCozr5X8rE\r\n"
-"ofGZpiM2NqRPePgYy+Vc75Zk28xkRQq1ncprgQb3S4vTsZdScpM9hLf+eMlrgqlj\r\n"
-"c5PLSkXBeLE5+fedkyfTaLxxQlgCpuoOhKBm04/R1pWNzUHyqagjO9Q=\r\n"
+"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n"
+"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQsFAAOC\r\n"
+"AQEAlHabem2Tu69VUN7EipwnQn1dIHdgvT5i+iQHpSxY1crPnBbAeSdAXwsVEqLQ\r\n"
+"gOOIAQD5VIITNuoGgo4i+4OpNh9u7ZkpRHla+/swsfrFWRRbBNP5Bcu74AGLstwU\r\n"
+"zM8gIkBiyfM1Q1qDQISV9trlCG6O8vh8dp/rbI3rfzo99BOHXgFCrzXjCuW4vDsF\r\n"
+"r+Dao26bX3sJ6UnEWg1H3o2x6PpUcvQ36h71/bz4TEbbUUEpe02V4QWuL+wrhHJL\r\n"
+"U7o3SVE3Og7jPF8sat0a50YUWhwEFI256m02KAXLg89ueUyYKEr6rNwhcvXJpvU9\r\n"
+"giIVvd0Sbjjnn7NC4VDbcXV8vw==\r\n"
 "-----END CERTIFICATE-----\r\n";
 const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa );
 
+/* tests/data_files/cli-rsa.key */
 const char mbedtls_test_cli_key_rsa[] =
 "-----BEGIN RSA PRIVATE KEY-----\r\n"
 "MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n"
diff --git a/crypto/mbedtls/src/cipher.c b/crypto/mbedtls/src/cipher.c
index 7ae6c4a..d7acf34 100644
--- a/crypto/mbedtls/src/cipher.c
+++ b/crypto/mbedtls/src/cipher.c
@@ -237,10 +237,14 @@ int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
                    const unsigned char *iv, size_t iv_len )
 {
     size_t actual_iv_size;
-
-    if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv )
+    if( NULL == ctx || NULL == ctx->cipher_info )
+        return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+    else if( NULL == iv && iv_len != 0  )
         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
 
+    if( NULL == iv && iv_len == 0 )
+        ctx->iv_size = 0;
+
     /* avoid buffer overflow in ctx->iv */
     if( iv_len > MBEDTLS_MAX_IV_LENGTH )
         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
@@ -268,8 +272,11 @@ int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
     }
 #endif
 
-    memcpy( ctx->iv, iv, actual_iv_size );
-    ctx->iv_size = actual_iv_size;
+    if ( actual_iv_size != 0 )
+    {
+        memcpy( ctx->iv, iv, actual_iv_size );
+        ctx->iv_size = actual_iv_size;
+    }
 
     return( 0 );
 }
diff --git a/crypto/mbedtls/src/cipher_wrap.c b/crypto/mbedtls/src/cipher_wrap.c
index 893490a..6dd8c5d 100644
--- a/crypto/mbedtls/src/cipher_wrap.c
+++ b/crypto/mbedtls/src/cipher_wrap.c
@@ -258,7 +258,7 @@ static const mbedtls_cipher_info_t aes_128_ecb_info = {
     MBEDTLS_MODE_ECB,
     128,
     "AES-128-ECB",
-    16,
+    0,
     0,
     16,
     &aes_info
@@ -269,7 +269,7 @@ static const mbedtls_cipher_info_t aes_192_ecb_info = {
     MBEDTLS_MODE_ECB,
     192,
     "AES-192-ECB",
-    16,
+    0,
     0,
     16,
     &aes_info
@@ -280,7 +280,7 @@ static const mbedtls_cipher_info_t aes_256_ecb_info = {
     MBEDTLS_MODE_ECB,
     256,
     "AES-256-ECB",
-    16,
+    0,
     0,
     16,
     &aes_info
diff --git a/crypto/mbedtls/src/ctr_drbg.c b/crypto/mbedtls/src/ctr_drbg.c
index d0e5ba8..0655e76 100644
--- a/crypto/mbedtls/src/ctr_drbg.c
+++ b/crypto/mbedtls/src/ctr_drbg.c
@@ -66,6 +66,18 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
  * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow
  * NIST tests to succeed (which require known length fixed entropy)
  */
+/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
+ * mbedtls_ctr_drbg_seed_entropy_len(ctx, f_entropy, p_entropy,
+ *                                   custom, len, entropy_len)
+ * implements
+ * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
+ *                      security_strength) -> initial_working_state
+ * with inputs
+ *   custom[:len] = nonce || personalization_string
+ * where entropy_input comes from f_entropy for entropy_len bytes
+ * and with outputs
+ *   ctx = initial_working_state
+ */
 int mbedtls_ctr_drbg_seed_entropy_len(
                    mbedtls_ctr_drbg_context *ctx,
                    int (*f_entropy)(void *, unsigned char *, size_t),
@@ -256,6 +268,14 @@ exit:
     return( ret );
 }
 
+/* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
+ * ctr_drbg_update_internal(ctx, provided_data)
+ * implements
+ * CTR_DRBG_Update(provided_data, Key, V)
+ * with inputs and outputs
+ *   ctx->aes_ctx = Key
+ *   ctx->counter = V
+ */
 static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
                               const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
 {
@@ -279,9 +299,7 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
          * Crypt counter block
          */
         if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ) ) != 0 )
-        {
-            return( ret );
-        }
+            goto exit;
 
         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
     }
@@ -293,31 +311,70 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
      * Update key and counter
      */
     if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
-    {
-        return( ret );
-    }
+        goto exit;
     memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE );
 
-    return( 0 );
+exit:
+    mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
+    return( ret );
 }
 
-void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
-                      const unsigned char *additional, size_t add_len )
+/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
+ * mbedtls_ctr_drbg_update(ctx, additional, add_len)
+ * implements
+ * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
+ *                      security_strength) -> initial_working_state
+ * with inputs
+ *   ctx->counter = all-bits-0
+ *   ctx->aes_ctx = context from all-bits-0 key
+ *   additional[:add_len] = entropy_input || nonce || personalization_string
+ * and with outputs
+ *   ctx = initial_working_state
+ */
+int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
+                                 const unsigned char *additional,
+                                 size_t add_len )
 {
     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
+    int ret;
 
-    if( add_len > 0 )
-    {
-        /* MAX_INPUT would be more logical here, but we have to match
-         * block_cipher_df()'s limits since we can't propagate errors */
-        if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
-            add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT;
+    if( add_len == 0 )
+        return( 0 );
 
-        block_cipher_df( add_input, additional, add_len );
-        ctr_drbg_update_internal( ctx, add_input );
-    }
+    if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
+        goto exit;
+    if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
+        goto exit;
+
+exit:
+    mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
+    return( ret );
 }
 
+/* Deprecated function, kept for backward compatibility. */
+void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
+                              const unsigned char *additional,
+                              size_t add_len )
+{
+    /* MAX_INPUT would be more logical here, but we have to match
+     * block_cipher_df()'s limits since we can't propagate errors */
+    if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
+        add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT;
+    (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len );
+}
+
+/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
+ * mbedtls_ctr_drbg_reseed(ctx, additional, len)
+ * implements
+ * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
+ *                -> new_working_state
+ * with inputs
+ *   ctx contains working_state
+ *   additional[:len] = additional_input
+ * and entropy_input comes from calling ctx->f_entropy
+ * and with output
+ *   ctx contains new_working_state
+ */
 int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
                      const unsigned char *additional, size_t len )
 {
@@ -355,22 +412,39 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
      * Reduce to 384 bits
      */
     if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
-    {
-        return( ret );
-    }
+        goto exit;
 
     /*
      * Update state
      */
     if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
-    {
-        return( ret );
-    }
+        goto exit;
     ctx->reseed_counter = 1;
 
-    return( 0 );
+exit:
+    mbedtls_platform_zeroize( seed, sizeof( seed ) );
+    return( ret );
 }
 
+/* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
+ * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
+ * implements
+ * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
+ *                -> working_state_after_reseed
+ *                if required, then
+ * CTR_DRBG_Generate(working_state_after_reseed,
+ *                   requested_number_of_bits, additional_input)
+ *                -> status, returned_bits, new_working_state
+ * with inputs
+ *   ctx contains working_state
+ *   requested_number_of_bits = 8 * output_len
+ *   additional[:add_len] = additional_input
+ * and entropy_input comes from calling ctx->f_entropy
+ * and with outputs
+ *   status = SUCCESS (this function does the reseed internally)
+ *   returned_bits = output[:output_len]
+ *   ctx contains new_working_state
+ */
 int mbedtls_ctr_drbg_random_with_add( void *p_rng,
                               unsigned char *output, size_t output_len,
                               const unsigned char *additional, size_t add_len )
@@ -404,13 +478,9 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng,
     if( add_len > 0 )
     {
         if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
-        {
-            return( ret );
-        }
+            goto exit;
         if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
-        {
-            return( ret );
-        }
+            goto exit;
     }
 
     while( output_len > 0 )
@@ -426,9 +496,7 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng,
          * Crypt counter block
          */
         if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 )
-        {
-            return( ret );
-        }
+            goto exit;
 
         use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE :
                                                        output_len;
@@ -441,12 +509,13 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng,
     }
 
     if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
-    {
-        return( ret );
-    }
+        goto exit;
 
     ctx->reseed_counter++;
 
+exit:
+    mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
+    mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
     return( 0 );
 }
 
@@ -518,7 +587,7 @@ int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char
     if( fread( buf, 1, n, f ) != n )
         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
     else
-        mbedtls_ctr_drbg_update( ctx, buf, n );
+        ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n );
 
     fclose( f );
 
diff --git a/crypto/mbedtls/src/ecdh.c b/crypto/mbedtls/src/ecdh.c
index 61380b6..e6ae999 100644
--- a/crypto/mbedtls/src/ecdh.c
+++ b/crypto/mbedtls/src/ecdh.c
@@ -40,36 +40,62 @@
 
 #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
 /*
- * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair
+ * Generate public key (restartable version)
+ *
+ * Note: this internal function relies on its caller preserving the value of
+ * the output parameter 'd' across continuation calls. This would not be
+ * acceptable for a public function but is OK here as we control call sites.
+ */
+static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
+                    mbedtls_mpi *d, mbedtls_ecp_point *Q,
+                    int (*f_rng)(void *, unsigned char *, size_t),
+                    void *p_rng,
+                    mbedtls_ecp_restart_ctx *rs_ctx )
+{
+    int ret;
+
+    /* If multiplication is in progress, we already generated a privkey */
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx == NULL || rs_ctx->rsm == NULL )
+#endif
+        MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
+
+    MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
+                                                  f_rng, p_rng, rs_ctx ) );
+
+cleanup:
+    return( ret );
+}
+
+/*
+ * Generate public key
  */
 int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
                      int (*f_rng)(void *, unsigned char *, size_t),
                      void *p_rng )
 {
-    return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng );
+    return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
 }
-#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */
+#endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
 
 #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
 /*
  * Compute shared secret (SEC1 3.3.1)
  */
-int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
+static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
+                         mbedtls_mpi *z,
                          const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
                          int (*f_rng)(void *, unsigned char *, size_t),
-                         void *p_rng )
+                         void *p_rng,
+                         mbedtls_ecp_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_ecp_point P;
 
     mbedtls_ecp_point_init( &P );
 
-    /*
-     * Make sure Q is a valid pubkey before using it
-     */
-    MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
-
-    MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) );
+    MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
+                                                  f_rng, p_rng, rs_ctx ) );
 
     if( mbedtls_ecp_is_zero( &P ) )
     {
@@ -84,14 +110,39 @@ cleanup:
 
     return( ret );
 }
-#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
+
+/*
+ * Compute shared secret (SEC1 3.3.1)
+ */
+int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
+                         const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng )
+{
+    return( ecdh_compute_shared_restartable( grp, z, Q, d,
+                                             f_rng, p_rng, NULL ) );
+}
+#endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
 
 /*
  * Initialize context
  */
 void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
 {
-    memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
+    mbedtls_ecp_group_init( &ctx->grp );
+    mbedtls_mpi_init( &ctx->d  );
+    mbedtls_ecp_point_init( &ctx->Q   );
+    mbedtls_ecp_point_init( &ctx->Qp  );
+    mbedtls_mpi_init( &ctx->z  );
+    ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
+    mbedtls_ecp_point_init( &ctx->Vi  );
+    mbedtls_ecp_point_init( &ctx->Vf  );
+    mbedtls_mpi_init( &ctx->_d );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    ctx->restart_enabled = 0;
+    mbedtls_ecp_restart_init( &ctx->rs );
+#endif
 }
 
 /*
@@ -103,14 +154,28 @@ void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
         return;
 
     mbedtls_ecp_group_free( &ctx->grp );
+    mbedtls_mpi_free( &ctx->d  );
     mbedtls_ecp_point_free( &ctx->Q   );
     mbedtls_ecp_point_free( &ctx->Qp  );
+    mbedtls_mpi_free( &ctx->z  );
     mbedtls_ecp_point_free( &ctx->Vi  );
     mbedtls_ecp_point_free( &ctx->Vf  );
-    mbedtls_mpi_free( &ctx->d  );
-    mbedtls_mpi_free( &ctx->z  );
     mbedtls_mpi_free( &ctx->_d );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    mbedtls_ecp_restart_free( &ctx->rs );
+#endif
+}
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/*
+ * Enable restartable operations for context
+ */
+void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx )
+{
+    ctx->restart_enabled = 1;
 }
+#endif
 
 /*
  * Setup and write the ServerKeyExhange parameters (RFC 4492)
@@ -126,13 +191,28 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
 {
     int ret;
     size_t grp_len, pt_len;
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    mbedtls_ecp_restart_ctx *rs_ctx = NULL;
+#endif
 
     if( ctx == NULL || ctx->grp.pbits == 0 )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
-    if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) )
-                != 0 )
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ctx->restart_enabled )
+        rs_ctx = &ctx->rs;
+#endif
+
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
+                                             f_rng, p_rng, rs_ctx ) ) != 0 )
+        return( ret );
+#else
+    if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
+                                         f_rng, p_rng ) ) != 0 )
         return( ret );
+#endif /* MBEDTLS_ECP_RESTARTABLE */
 
     if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) )
                 != 0 )
@@ -142,7 +222,7 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
     blen -= grp_len;
 
     if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format,
-                                     &pt_len, buf, blen ) ) != 0 )
+                                             &pt_len, buf, blen ) ) != 0 )
         return( ret );
 
     *olen = grp_len + pt_len;
@@ -206,13 +286,27 @@ int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
                       void *p_rng )
 {
     int ret;
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    mbedtls_ecp_restart_ctx *rs_ctx = NULL;
+#endif
 
     if( ctx == NULL || ctx->grp.pbits == 0 )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
-    if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) )
-                != 0 )
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ctx->restart_enabled )
+        rs_ctx = &ctx->rs;
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
+                    f_rng, p_rng, rs_ctx ) ) != 0 )
         return( ret );
+#else
+    if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
+                                         f_rng, p_rng ) ) != 0 )
+        return( ret );
+#endif /* MBEDTLS_ECP_RESTARTABLE */
 
     return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format,
                                 olen, buf, blen );
@@ -248,15 +342,31 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
                       void *p_rng )
 {
     int ret;
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    mbedtls_ecp_restart_ctx *rs_ctx = NULL;
+#endif
 
-    if( ctx == NULL )
+    if( ctx == NULL || ctx->grp.pbits == 0 )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
-    if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d,
-                                     f_rng, p_rng ) ) != 0 )
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ctx->restart_enabled )
+        rs_ctx = &ctx->rs;
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ( ret = ecdh_compute_shared_restartable( &ctx->grp,
+                    &ctx->z, &ctx->Qp, &ctx->d, f_rng, p_rng, rs_ctx ) ) != 0 )
+    {
+        return( ret );
+    }
+#else
+    if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp,
+                                             &ctx->d, f_rng, p_rng ) ) != 0 )
     {
         return( ret );
     }
+#endif /* MBEDTLS_ECP_RESTARTABLE */
 
     if( mbedtls_mpi_size( &ctx->z ) > blen )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
diff --git a/crypto/mbedtls/src/ecdsa.c b/crypto/mbedtls/src/ecdsa.c
index 17a88bd..a62c14c 100644
--- a/crypto/mbedtls/src/ecdsa.c
+++ b/crypto/mbedtls/src/ecdsa.c
@@ -42,6 +42,178 @@
 #include "mbedtls/hmac_drbg.h"
 #endif
 
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdlib.h>
+#define mbedtls_calloc    calloc
+#define mbedtls_free       free
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+
+/*
+ * Sub-context for ecdsa_verify()
+ */
+struct mbedtls_ecdsa_restart_ver
+{
+    mbedtls_mpi u1, u2;     /* intermediate values  */
+    enum {                  /* what to do next?     */
+        ecdsa_ver_init = 0, /* getting started      */
+        ecdsa_ver_muladd,   /* muladd step          */
+    } state;
+};
+
+/*
+ * Init verify restart sub-context
+ */
+static void ecdsa_restart_ver_init( mbedtls_ecdsa_restart_ver_ctx *ctx )
+{
+    mbedtls_mpi_init( &ctx->u1 );
+    mbedtls_mpi_init( &ctx->u2 );
+    ctx->state = ecdsa_ver_init;
+}
+
+/*
+ * Free the components of a verify restart sub-context
+ */
+static void ecdsa_restart_ver_free( mbedtls_ecdsa_restart_ver_ctx *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_mpi_free( &ctx->u1 );
+    mbedtls_mpi_free( &ctx->u2 );
+
+    ecdsa_restart_ver_init( ctx );
+}
+
+/*
+ * Sub-context for ecdsa_sign()
+ */
+struct mbedtls_ecdsa_restart_sig
+{
+    int sign_tries;
+    int key_tries;
+    mbedtls_mpi k;          /* per-signature random */
+    mbedtls_mpi r;          /* r value              */
+    enum {                  /* what to do next?     */
+        ecdsa_sig_init = 0, /* getting started      */
+        ecdsa_sig_mul,      /* doing ecp_mul()      */
+        ecdsa_sig_modn,     /* mod N computations   */
+    } state;
+};
+
+/*
+ * Init verify sign sub-context
+ */
+static void ecdsa_restart_sig_init( mbedtls_ecdsa_restart_sig_ctx *ctx )
+{
+    ctx->sign_tries = 0;
+    ctx->key_tries = 0;
+    mbedtls_mpi_init( &ctx->k );
+    mbedtls_mpi_init( &ctx->r );
+    ctx->state = ecdsa_sig_init;
+}
+
+/*
+ * Free the components of a sign restart sub-context
+ */
+static void ecdsa_restart_sig_free( mbedtls_ecdsa_restart_sig_ctx *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_mpi_free( &ctx->k );
+    mbedtls_mpi_free( &ctx->r );
+}
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+/*
+ * Sub-context for ecdsa_sign_det()
+ */
+struct mbedtls_ecdsa_restart_det
+{
+    mbedtls_hmac_drbg_context rng_ctx;  /* DRBG state   */
+    enum {                      /* what to do next?     */
+        ecdsa_det_init = 0,     /* getting started      */
+        ecdsa_det_sign,         /* make signature       */
+    } state;
+};
+
+/*
+ * Init verify sign_det sub-context
+ */
+static void ecdsa_restart_det_init( mbedtls_ecdsa_restart_det_ctx *ctx )
+{
+    mbedtls_hmac_drbg_init( &ctx->rng_ctx );
+    ctx->state = ecdsa_det_init;
+}
+
+/*
+ * Free the components of a sign_det restart sub-context
+ */
+static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_hmac_drbg_free( &ctx->rng_ctx );
+
+    ecdsa_restart_det_init( ctx );
+}
+#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
+
+#define ECDSA_RS_ECP    &rs_ctx->ecp
+
+/* Utility macro for checking and updating ops budget */
+#define ECDSA_BUDGET( ops )   \
+    MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, &rs_ctx->ecp, ops ) );
+
+/* Call this when entering a function that needs its own sub-context */
+#define ECDSA_RS_ENTER( SUB )   do {                                 \
+    /* reset ops count for this call if top-level */                 \
+    if( rs_ctx != NULL && rs_ctx->ecp.depth++ == 0 )                 \
+        rs_ctx->ecp.ops_done = 0;                                    \
+                                                                     \
+    /* set up our own sub-context if needed */                       \
+    if( mbedtls_ecp_restart_is_enabled() &&                          \
+        rs_ctx != NULL && rs_ctx->SUB == NULL )                      \
+    {                                                                \
+        rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) );   \
+        if( rs_ctx->SUB == NULL )                                    \
+            return( MBEDTLS_ERR_ECP_ALLOC_FAILED );                  \
+                                                                     \
+        ecdsa_restart_## SUB ##_init( rs_ctx->SUB );                 \
+    }                                                                \
+} while( 0 )
+
+/* Call this when leaving a function that needs its own sub-context */
+#define ECDSA_RS_LEAVE( SUB )   do {                                 \
+    /* clear our sub-context when not in progress (done or error) */ \
+    if( rs_ctx != NULL && rs_ctx->SUB != NULL &&                     \
+        ret != MBEDTLS_ERR_ECP_IN_PROGRESS )                         \
+    {                                                                \
+        ecdsa_restart_## SUB ##_free( rs_ctx->SUB );                 \
+        mbedtls_free( rs_ctx->SUB );                                 \
+        rs_ctx->SUB = NULL;                                          \
+    }                                                                \
+                                                                     \
+    if( rs_ctx != NULL )                                             \
+        rs_ctx->ecp.depth--;                                         \
+} while( 0 )
+
+#else /* MBEDTLS_ECP_RESTARTABLE */
+
+#define ECDSA_RS_ECP    NULL
+
+#define ECDSA_BUDGET( ops )   /* no-op; for compatibility */
+
+#define ECDSA_RS_ENTER( SUB )   (void) rs_ctx
+#define ECDSA_RS_LEAVE( SUB )   (void) rs_ctx
+
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 /*
  * Derive a suitable integer for group grp from a buffer of length len
  * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
@@ -70,13 +242,17 @@ cleanup:
  * Compute ECDSA signature of a hashed message (SEC1 4.1.3)
  * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
  */
-int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
+static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
+                mbedtls_mpi *r, mbedtls_mpi *s,
                 const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
-                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+                mbedtls_ecdsa_restart_ctx *rs_ctx )
 {
-    int ret, key_tries, sign_tries, blind_tries;
+    int ret, key_tries, sign_tries;
+    int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries;
     mbedtls_ecp_point R;
     mbedtls_mpi k, e, t;
+    mbedtls_mpi *pk = &k, *pr = r;
 
     /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
     if( grp->N.p == NULL )
@@ -89,26 +265,72 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
     mbedtls_ecp_point_init( &R );
     mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t );
 
-    sign_tries = 0;
+    ECDSA_RS_ENTER( sig );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->sig != NULL )
+    {
+        /* redirect to our context */
+        p_sign_tries = &rs_ctx->sig->sign_tries;
+        p_key_tries = &rs_ctx->sig->key_tries;
+        pk = &rs_ctx->sig->k;
+        pr = &rs_ctx->sig->r;
+
+        /* jump to current step */
+        if( rs_ctx->sig->state == ecdsa_sig_mul )
+            goto mul;
+        if( rs_ctx->sig->state == ecdsa_sig_modn )
+            goto modn;
+    }
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
+    *p_sign_tries = 0;
     do
     {
+        if( *p_sign_tries++ > 10 )
+        {
+            ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
+            goto cleanup;
+        }
+
         /*
          * Steps 1-3: generate a suitable ephemeral keypair
          * and set r = xR mod n
          */
-        key_tries = 0;
+        *p_key_tries = 0;
         do
         {
-            MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) );
-            MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) );
-
-            if( key_tries++ > 10 )
+            if( *p_key_tries++ > 10 )
             {
                 ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
                 goto cleanup;
             }
+
+            MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+            if( rs_ctx != NULL && rs_ctx->sig != NULL )
+                rs_ctx->sig->state = ecdsa_sig_mul;
+
+mul:
+#endif
+            MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G,
+                                                  f_rng, p_rng, ECDSA_RS_ECP ) );
+            MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) );
         }
-        while( mbedtls_mpi_cmp_int( r, 0 ) == 0 );
+        while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+        if( rs_ctx != NULL && rs_ctx->sig != NULL )
+            rs_ctx->sig->state = ecdsa_sig_modn;
+
+modn:
+#endif
+        /*
+         * Accounting for everything up to the end of the loop
+         * (step 6, but checking now avoids saving e and t)
+         */
+        ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 );
 
         /*
          * Step 5: derive MPI from hashed message
@@ -119,57 +341,60 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
          * Generate a random value to blind inv_mod in next step,
          * avoiding a potential timing leak.
          */
-        blind_tries = 0;
-        do
-        {
-            size_t n_size = ( grp->nbits + 7 ) / 8;
-            MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) );
-            MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) );
-
-            /* See mbedtls_ecp_gen_keypair() */
-            if( ++blind_tries > 30 )
-                return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
-        }
-        while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 ||
-               mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 );
+        MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) );
 
         /*
          * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n
          */
-        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) );
-
-        if( sign_tries++ > 10 )
-        {
-            ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
-            goto cleanup;
-        }
     }
     while( mbedtls_mpi_cmp_int( s, 0 ) == 0 );
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->sig != NULL )
+        mbedtls_mpi_copy( r, pr );
+#endif
+
 cleanup:
     mbedtls_ecp_point_free( &R );
     mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t );
 
+    ECDSA_RS_LEAVE( sig );
+
     return( ret );
 }
-#endif /* MBEDTLS_ECDSA_SIGN_ALT */
+
+/*
+ * Compute ECDSA signature of a hashed message
+ */
+int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
+                const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
+                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+    return( ecdsa_sign_restartable( grp, r, s, d, buf, blen,
+                                    f_rng, p_rng, NULL ) );
+}
+#endif /* !MBEDTLS_ECDSA_SIGN_ALT */
 
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
 /*
  * Deterministic signature wrapper
  */
-int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
+static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp,
+                    mbedtls_mpi *r, mbedtls_mpi *s,
                     const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
-                    mbedtls_md_type_t md_alg )
+                    mbedtls_md_type_t md_alg,
+                    mbedtls_ecdsa_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_hmac_drbg_context rng_ctx;
+    mbedtls_hmac_drbg_context *p_rng = &rng_ctx;
     unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES];
     size_t grp_len = ( grp->nbits + 7 ) / 8;
     const mbedtls_md_info_t *md_info;
@@ -181,21 +406,58 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi
     mbedtls_mpi_init( &h );
     mbedtls_hmac_drbg_init( &rng_ctx );
 
+    ECDSA_RS_ENTER( det );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->det != NULL )
+    {
+        /* redirect to our context */
+        p_rng = &rs_ctx->det->rng_ctx;
+
+        /* jump to current step */
+        if( rs_ctx->det->state == ecdsa_det_sign )
+            goto sign;
+    }
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
     /* Use private key and message hash (reduced) to initialize HMAC_DRBG */
     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) );
     MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) );
     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) );
-    mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len );
+    mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->det != NULL )
+        rs_ctx->det->state = ecdsa_det_sign;
 
+sign:
+#endif
+#if defined(MBEDTLS_ECDSA_SIGN_ALT)
     ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
-                      mbedtls_hmac_drbg_random, &rng_ctx );
+                              mbedtls_hmac_drbg_random, p_rng );
+#else
+    ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
+                      mbedtls_hmac_drbg_random, p_rng, rs_ctx );
+#endif /* MBEDTLS_ECDSA_SIGN_ALT */
 
 cleanup:
     mbedtls_hmac_drbg_free( &rng_ctx );
     mbedtls_mpi_free( &h );
 
+    ECDSA_RS_LEAVE( det );
+
     return( ret );
 }
+
+/*
+ * Deterministic signature wrapper
+ */
+int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
+                    const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
+                    mbedtls_md_type_t md_alg )
+{
+    return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, NULL ) );
+}
 #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
 
 #if !defined(MBEDTLS_ECDSA_VERIFY_ALT)
@@ -203,21 +465,40 @@ cleanup:
  * Verify ECDSA signature of hashed message (SEC1 4.1.4)
  * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message)
  */
-int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
-                  const unsigned char *buf, size_t blen,
-                  const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s)
+static int ecdsa_verify_restartable( mbedtls_ecp_group *grp,
+                                     const unsigned char *buf, size_t blen,
+                                     const mbedtls_ecp_point *Q,
+                                     const mbedtls_mpi *r, const mbedtls_mpi *s,
+                                     mbedtls_ecdsa_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_mpi e, s_inv, u1, u2;
     mbedtls_ecp_point R;
+    mbedtls_mpi *pu1 = &u1, *pu2 = &u2;
 
     mbedtls_ecp_point_init( &R );
-    mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
+    mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv );
+    mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
 
     /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
     if( grp->N.p == NULL )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
+    ECDSA_RS_ENTER( ver );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ver != NULL )
+    {
+        /* redirect to our context */
+        pu1 = &rs_ctx->ver->u1;
+        pu2 = &rs_ctx->ver->u2;
+
+        /* jump to current step */
+        if( rs_ctx->ver->state == ecdsa_ver_muladd )
+            goto muladd;
+    }
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
     /*
      * Step 1: make sure r and s are in range 1..n-1
      */
@@ -229,11 +510,6 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
     }
 
     /*
-     * Additional precaution: make sure Q is valid
-     */
-    MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
-
-    /*
      * Step 3: derive MPI from hashed message
      */
     MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) );
@@ -241,21 +517,27 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
     /*
      * Step 4: u1 = e / s mod n, u2 = r / s mod n
      */
+    ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 );
+
     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) );
 
-    MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) );
 
-    MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) );
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ver != NULL )
+        rs_ctx->ver->state = ecdsa_ver_muladd;
+
+muladd:
+#endif
     /*
      * Step 5: R = u1 G + u2 Q
-     *
-     * Since we're not using any secret data, no need to pass a RNG to
-     * mbedtls_ecp_mul() for countermesures.
      */
-    MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) );
+    MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp,
+                     &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) );
 
     if( mbedtls_ecp_is_zero( &R ) )
     {
@@ -280,11 +562,24 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
 
 cleanup:
     mbedtls_ecp_point_free( &R );
-    mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
+    mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv );
+    mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
+
+    ECDSA_RS_LEAVE( ver );
 
     return( ret );
 }
-#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
+
+/*
+ * Verify ECDSA signature of hashed message
+ */
+int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
+                  const unsigned char *buf, size_t blen,
+                  const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s)
+{
+    return( ecdsa_verify_restartable( grp, buf, blen, Q, r, s, NULL ) );
+}
+#endif /* !MBEDTLS_ECDSA_VERIFY_ALT */
 
 /*
  * Convert a signature (given by context) to ASN.1
@@ -313,11 +608,13 @@ static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
 /*
  * Compute and write signature
  */
-int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg,
+int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
+                           mbedtls_md_type_t md_alg,
                            const unsigned char *hash, size_t hlen,
                            unsigned char *sig, size_t *slen,
                            int (*f_rng)(void *, unsigned char *, size_t),
-                           void *p_rng )
+                           void *p_rng,
+                           mbedtls_ecdsa_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_mpi r, s;
@@ -329,14 +626,19 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t
     (void) f_rng;
     (void) p_rng;
 
-    MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d,
-                             hash, hlen, md_alg ) );
+    MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d,
+                             hash, hlen, md_alg, rs_ctx ) );
 #else
     (void) md_alg;
 
+#if defined(MBEDTLS_ECDSA_SIGN_ALT)
     MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
                          hash, hlen, f_rng, p_rng ) );
-#endif
+#else
+    MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d,
+                         hash, hlen, f_rng, p_rng, rs_ctx ) );
+#endif /* MBEDTLS_ECDSA_SIGN_ALT */
+#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
 
     MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );
 
@@ -347,7 +649,20 @@ cleanup:
     return( ret );
 }
 
-#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \
+/*
+ * Compute and write signature
+ */
+int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg,
+                           const unsigned char *hash, size_t hlen,
+                           unsigned char *sig, size_t *slen,
+                           int (*f_rng)(void *, unsigned char *, size_t),
+                           void *p_rng )
+{
+    return( mbedtls_ecdsa_write_signature_restartable(
+                ctx, md_alg, hash, hlen, sig, slen, f_rng, p_rng, NULL ) );
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED) && \
     defined(MBEDTLS_ECDSA_DETERMINISTIC)
 int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
                                const unsigned char *hash, size_t hlen,
@@ -366,6 +681,18 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
                           const unsigned char *hash, size_t hlen,
                           const unsigned char *sig, size_t slen )
 {
+    return( mbedtls_ecdsa_read_signature_restartable(
+                ctx, hash, hlen, sig, slen, NULL ) );
+}
+
+/*
+ * Restartable read and check signature
+ */
+int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
+                          const unsigned char *hash, size_t hlen,
+                          const unsigned char *sig, size_t slen,
+                          mbedtls_ecdsa_restart_ctx *rs_ctx )
+{
     int ret;
     unsigned char *p = (unsigned char *) sig;
     const unsigned char *end = sig + slen;
@@ -395,10 +722,15 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
         ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
         goto cleanup;
     }
-
+#if defined(MBEDTLS_ECDSA_VERIFY_ALT)
     if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
-                              &ctx->Q, &r, &s ) ) != 0 )
+                                      &ctx->Q, &r, &s ) ) != 0 )
+        goto cleanup;
+#else
+    if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen,
+                              &ctx->Q, &r, &s, rs_ctx ) ) != 0 )
         goto cleanup;
+#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
 
     /* At this point we know that the buffer starts with a valid signature.
      * Return 0 if the buffer just contains the signature, and a specific
@@ -423,7 +755,7 @@ int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid,
     return( mbedtls_ecp_group_load( &ctx->grp, gid ) ||
             mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) );
 }
-#endif /* MBEDTLS_ECDSA_GENKEY_ALT */
+#endif /* !MBEDTLS_ECDSA_GENKEY_ALT */
 
 /*
  * Set context from an mbedtls_ecp_keypair
@@ -458,4 +790,42 @@ void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx )
     mbedtls_ecp_keypair_free( ctx );
 }
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/*
+ * Initialize a restart context
+ */
+void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx )
+{
+    mbedtls_ecp_restart_init( &ctx->ecp );
+
+    ctx->ver = NULL;
+    ctx->sig = NULL;
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+    ctx->det = NULL;
+#endif
+}
+
+/*
+ * Free the components of a restart context
+ */
+void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx )
+{
+    mbedtls_ecp_restart_free( &ctx->ecp );
+
+    ecdsa_restart_ver_free( ctx->ver );
+    mbedtls_free( ctx->ver );
+    ctx->ver = NULL;
+
+    ecdsa_restart_sig_free( ctx->sig );
+    mbedtls_free( ctx->sig );
+    ctx->sig = NULL;
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+    ecdsa_restart_det_free( ctx->det );
+    mbedtls_free( ctx->det );
+    ctx->det = NULL;
+#endif
+}
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 #endif /* MBEDTLS_ECDSA_C */
diff --git a/crypto/mbedtls/src/ecp.c b/crypto/mbedtls/src/ecp.c
index 9e2c085..de5725c 100644
--- a/crypto/mbedtls/src/ecp.c
+++ b/crypto/mbedtls/src/ecp.c
@@ -82,6 +82,230 @@
 static unsigned long add_count, dbl_count, mul_count;
 #endif
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/*
+ * Maximum number of "basic operations" to be done in a row.
+ *
+ * Default value 0 means that ECC operations will not yield.
+ * Note that regardless of the value of ecp_max_ops, always at
+ * least one step is performed before yielding.
+ *
+ * Setting ecp_max_ops=1 can be suitable for testing purposes
+ * as it will interrupt computation at all possible points.
+ */
+static unsigned ecp_max_ops = 0;
+
+/*
+ * Set ecp_max_ops
+ */
+void mbedtls_ecp_set_max_ops( unsigned max_ops )
+{
+    ecp_max_ops = max_ops;
+}
+
+/*
+ * Check if restart is enabled
+ */
+int mbedtls_ecp_restart_is_enabled( void )
+{
+    return( ecp_max_ops != 0 );
+}
+
+/*
+ * Restart sub-context for ecp_mul_comb()
+ */
+struct mbedtls_ecp_restart_mul
+{
+    mbedtls_ecp_point R;    /* current intermediate result                  */
+    size_t i;               /* current index in various loops, 0 outside    */
+    mbedtls_ecp_point *T;   /* table for precomputed points                 */
+    unsigned char T_size;   /* number of points in table T                  */
+    enum {                  /* what were we doing last time we returned?    */
+        ecp_rsm_init = 0,       /* nothing so far, dummy initial state      */
+        ecp_rsm_pre_dbl,        /* precompute 2^n multiples                 */
+        ecp_rsm_pre_norm_dbl,   /* normalize precomputed 2^n multiples      */
+        ecp_rsm_pre_add,        /* precompute remaining points by adding    */
+        ecp_rsm_pre_norm_add,   /* normalize all precomputed points         */
+        ecp_rsm_comb_core,      /* ecp_mul_comb_core()                      */
+        ecp_rsm_final_norm,     /* do the final normalization               */
+    } state;
+};
+
+/*
+ * Init restart_mul sub-context
+ */
+static void ecp_restart_rsm_init( mbedtls_ecp_restart_mul_ctx *ctx )
+{
+    mbedtls_ecp_point_init( &ctx->R );
+    ctx->i = 0;
+    ctx->T = NULL;
+    ctx->T_size = 0;
+    ctx->state = ecp_rsm_init;
+}
+
+/*
+ * Free the components of a restart_mul sub-context
+ */
+static void ecp_restart_rsm_free( mbedtls_ecp_restart_mul_ctx *ctx )
+{
+    unsigned char i;
+
+    if( ctx == NULL )
+        return;
+
+    mbedtls_ecp_point_free( &ctx->R );
+
+    if( ctx->T != NULL )
+    {
+        for( i = 0; i < ctx->T_size; i++ )
+            mbedtls_ecp_point_free( ctx->T + i );
+        mbedtls_free( ctx->T );
+    }
+
+    ecp_restart_rsm_init( ctx );
+}
+
+/*
+ * Restart context for ecp_muladd()
+ */
+struct mbedtls_ecp_restart_muladd
+{
+    mbedtls_ecp_point mP;       /* mP value                             */
+    mbedtls_ecp_point R;        /* R intermediate result                */
+    enum {                      /* what should we do next?              */
+        ecp_rsma_mul1 = 0,      /* first multiplication                 */
+        ecp_rsma_mul2,          /* second multiplication                */
+        ecp_rsma_add,           /* addition                             */
+        ecp_rsma_norm,          /* normalization                        */
+    } state;
+};
+
+/*
+ * Init restart_muladd sub-context
+ */
+static void ecp_restart_ma_init( mbedtls_ecp_restart_muladd_ctx *ctx )
+{
+    mbedtls_ecp_point_init( &ctx->mP );
+    mbedtls_ecp_point_init( &ctx->R );
+    ctx->state = ecp_rsma_mul1;
+}
+
+/*
+ * Free the components of a restart_muladd sub-context
+ */
+static void ecp_restart_ma_free( mbedtls_ecp_restart_muladd_ctx *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_ecp_point_free( &ctx->mP );
+    mbedtls_ecp_point_free( &ctx->R );
+
+    ecp_restart_ma_init( ctx );
+}
+
+/*
+ * Initialize a restart context
+ */
+void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx )
+{
+    ctx->ops_done = 0;
+    ctx->depth = 0;
+    ctx->rsm = NULL;
+    ctx->ma = NULL;
+}
+
+/*
+ * Free the components of a restart context
+ */
+void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    ecp_restart_rsm_free( ctx->rsm );
+    mbedtls_free( ctx->rsm );
+
+    ecp_restart_ma_free( ctx->ma );
+    mbedtls_free( ctx->ma );
+
+    mbedtls_ecp_restart_init( ctx );
+}
+
+/*
+ * Check if we can do the next step
+ */
+int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp,
+                              mbedtls_ecp_restart_ctx *rs_ctx,
+                              unsigned ops )
+{
+    if( rs_ctx != NULL && ecp_max_ops != 0 )
+    {
+        /* scale depending on curve size: the chosen reference is 256-bit,
+         * and multiplication is quadratic. Round to the closest integer. */
+        if( grp->pbits >= 512 )
+            ops *= 4;
+        else if( grp->pbits >= 384 )
+            ops *= 2;
+
+        /* Avoid infinite loops: always allow first step.
+         * Because of that, however, it's not generally true
+         * that ops_done <= ecp_max_ops, so the check
+         * ops_done > ecp_max_ops below is mandatory. */
+        if( ( rs_ctx->ops_done != 0 ) &&
+            ( rs_ctx->ops_done > ecp_max_ops ||
+              ops > ecp_max_ops - rs_ctx->ops_done ) )
+        {
+            return( MBEDTLS_ERR_ECP_IN_PROGRESS );
+        }
+
+        /* update running count */
+        rs_ctx->ops_done += ops;
+    }
+
+    return( 0 );
+}
+
+/* Call this when entering a function that needs its own sub-context */
+#define ECP_RS_ENTER( SUB )   do {                                      \
+    /* reset ops count for this call if top-level */                    \
+    if( rs_ctx != NULL && rs_ctx->depth++ == 0 )                        \
+        rs_ctx->ops_done = 0;                                           \
+                                                                        \
+    /* set up our own sub-context if needed */                          \
+    if( mbedtls_ecp_restart_is_enabled() &&                             \
+        rs_ctx != NULL && rs_ctx->SUB == NULL )                         \
+    {                                                                   \
+        rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) );      \
+        if( rs_ctx->SUB == NULL )                                       \
+            return( MBEDTLS_ERR_ECP_ALLOC_FAILED );                     \
+                                                                        \
+        ecp_restart_## SUB ##_init( rs_ctx->SUB );                      \
+    }                                                                   \
+} while( 0 )
+
+/* Call this when leaving a function that needs its own sub-context */
+#define ECP_RS_LEAVE( SUB )   do {                                      \
+    /* clear our sub-context when not in progress (done or error) */    \
+    if( rs_ctx != NULL && rs_ctx->SUB != NULL &&                        \
+        ret != MBEDTLS_ERR_ECP_IN_PROGRESS )                            \
+    {                                                                   \
+        ecp_restart_## SUB ##_free( rs_ctx->SUB );                      \
+        mbedtls_free( rs_ctx->SUB );                                    \
+        rs_ctx->SUB = NULL;                                             \
+    }                                                                   \
+                                                                        \
+    if( rs_ctx != NULL )                                                \
+        rs_ctx->depth--;                                                \
+} while( 0 )
+
+#else /* MBEDTLS_ECP_RESTARTABLE */
+
+#define ECP_RS_ENTER( sub )     (void) rs_ctx;
+#define ECP_RS_LEAVE( sub )     (void) rs_ctx;
+
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) ||   \
     defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) ||   \
     defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ||   \
@@ -289,7 +513,21 @@ void mbedtls_ecp_group_init( mbedtls_ecp_group *grp )
     if( grp == NULL )
         return;
 
-    memset( grp, 0, sizeof( mbedtls_ecp_group ) );
+    grp->id = MBEDTLS_ECP_DP_NONE;
+    mbedtls_mpi_init( &grp->P );
+    mbedtls_mpi_init( &grp->A );
+    mbedtls_mpi_init( &grp->B );
+    mbedtls_ecp_point_init( &grp->G );
+    mbedtls_mpi_init( &grp->N );
+    grp->pbits = 0;
+    grp->nbits = 0;
+    grp->h = 0;
+    grp->modp = NULL;
+    grp->t_pre = NULL;
+    grp->t_post = NULL;
+    grp->t_data = NULL;
+    grp->T = NULL;
+    grp->T_size = 0;
 }
 
 /*
@@ -752,11 +990,10 @@ static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p
         return( 0 );
 
 #if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_normalize_jac( grp, pt );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_normalize_jac( grp, pt ) );
 #endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */
+
     mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi );
 
     /*
@@ -796,32 +1033,33 @@ cleanup:
  * Cost: 1N(t) := 1I + (6t - 3)M + 1S
  */
 static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
-                                   mbedtls_ecp_point *T[], size_t t_len )
+                                   mbedtls_ecp_point *T[], size_t T_size )
 {
     int ret;
     size_t i;
     mbedtls_mpi *c, u, Zi, ZZi;
 
-    if( t_len < 2 )
+    if( T_size < 2 )
         return( ecp_normalize_jac( grp, *T ) );
 
 #if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_normalize_jac_many(grp, T, t_len);
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_normalize_jac_many( grp, T, T_size ) );
 #endif
 
-    if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL )
+    if( ( c = mbedtls_calloc( T_size, sizeof( mbedtls_mpi ) ) ) == NULL )
         return( MBEDTLS_ERR_ECP_ALLOC_FAILED );
 
+    for( i = 0; i < T_size; i++ )
+        mbedtls_mpi_init( &c[i] );
+
     mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi );
 
     /*
      * c[i] = Z_0 * ... * Z_i
      */
     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) );
-    for( i = 1; i < t_len; i++ )
+    for( i = 1; i < T_size; i++ )
     {
         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) );
         MOD_MUL( c[i] );
@@ -830,9 +1068,9 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
     /*
      * u = 1 / (Z_0 * ... * Z_n) mod P
      */
-    MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[T_size-1], &grp->P ) );
 
-    for( i = t_len - 1; ; i-- )
+    for( i = T_size - 1; ; i-- )
     {
         /*
          * Zi = 1 / Z_i mod p
@@ -872,7 +1110,7 @@ static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
 cleanup:
 
     mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi );
-    for( i = 0; i < t_len; i++ )
+    for( i = 0; i < T_size; i++ )
         mbedtls_mpi_free( &c[i] );
     mbedtls_free( c );
 
@@ -929,10 +1167,8 @@ static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
 #endif
 
 #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_double_jac( grp, R, P );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_double_jac( grp, R, P ) );
 #endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */
 
     mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U );
@@ -1027,10 +1263,8 @@ static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
 #endif
 
 #if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_add_mixed( grp, R, P, Q );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_add_mixed( grp, R, P, Q ) );
 #endif /* MBEDTLS_ECP_ADD_MIXED_ALT */
 
     /*
@@ -1114,10 +1348,8 @@ static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *p
     int count = 0;
 
 #if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng ) );
 #endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */
 
     p_size = ( grp->pbits + 7 ) / 8;
@@ -1173,11 +1405,38 @@ cleanup:
  * modified version that provides resistance to SPA by avoiding zero
  * digits in the representation as in [3]. We modify the method further by
  * requiring that all K_i be odd, which has the small cost that our
- * representation uses one more K_i, due to carries.
+ * representation uses one more K_i, due to carries, but saves on the size of
+ * the precomputed table.
+ *
+ * Summary of the comb method and its modifications:
+ *
+ * - The goal is to compute m*P for some w*d-bit integer m.
+ *
+ * - The basic comb method splits m into the w-bit integers
+ *   x[0] .. x[d-1] where x[i] consists of the bits in m whose
+ *   index has residue i modulo d, and computes m * P as
+ *   S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where
+ *   S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P.
+ *
+ * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by
+ *    .. + 2^{i-1} S[x[i-1]] - 2^i S[x[i]] + 2^{i+1} S[x[i]] + 2^{i+2} S[x[i+2]] ..,
+ *   thereby successively converting it into a form where all summands
+ *   are nonzero, at the cost of negative summands. This is the basic idea of [3].
  *
- * Also, for the sake of compactness, only the seven low-order bits of x[i]
- * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in
- * the paper): it is set if and only if if s_i == -1;
+ * - More generally, even if x[i+1] != 0, we can first transform the sum as
+ *   .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] ..,
+ *   and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]].
+ *   Performing and iterating this procedure for those x[i] that are even
+ *   (keeping track of carry), we can transform the original sum into one of the form
+ *   S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]]
+ *   with all x'[i] odd. It is therefore only necessary to know S at odd indices,
+ *   which is why we are only computing half of it in the first place in
+ *   ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb.
+ *
+ * - For the sake of compactness, only the seven low-order bits of x[i]
+ *   are used to represent its absolute value (K_i in the paper), and the msb
+ *   of x[i] encodes the sign (s_i in the paper): it is set if and only if
+ *   if s_i == -1;
  *
  * Calling conventions:
  * - x is an array of size d + 1
@@ -1186,8 +1445,8 @@ cleanup:
  * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d
  *   (the result will be incorrect if these assumptions are not satisfied)
  */
-static void ecp_comb_fixed( unsigned char x[], size_t d,
-                            unsigned char w, const mbedtls_mpi *m )
+static void ecp_comb_recode_core( unsigned char x[], size_t d,
+                                  unsigned char w, const mbedtls_mpi *m )
 {
     size_t i, j;
     unsigned char c, cc, adjust;
@@ -1217,70 +1476,178 @@ static void ecp_comb_fixed( unsigned char x[], size_t d,
 }
 
 /*
- * Precompute points for the comb method
+ * Precompute points for the adapted comb method
  *
- * If i = i_{w-1} ... i_1 is the binary representation of i, then
- * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P
+ * Assumption: T must be able to hold 2^{w - 1} elements.
  *
- * T must be able to hold 2^{w - 1} elements
+ * Operation: If i = i_{w-1} ... i_1 is the binary representation of i,
+ *            sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P.
  *
  * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1)
+ *
+ * Note: Even comb values (those where P would be omitted from the
+ *       sum defining T[i] above) are not needed in our adaption
+ *       the comb method. See ecp_comb_recode_core().
+ *
+ * This function currently works in four steps:
+ * (1) [dbl]      Computation of intermediate T[i] for 2-power values of i
+ * (2) [norm_dbl] Normalization of coordinates of these T[i]
+ * (3) [add]      Computation of all T[i]
+ * (4) [norm_add] Normalization of all T[i]
+ *
+ * Step 1 can be interrupted but not the others; together with the final
+ * coordinate normalization they are the largest steps done at once, depending
+ * on the window size. Here are operation counts for P-256:
+ *
+ * step     (2)     (3)     (4)
+ * w = 5    142     165     208
+ * w = 4    136      77     160
+ * w = 3    130      33     136
+ * w = 2    124      11     124
+ *
+ * So if ECC operations are blocking for too long even with a low max_ops
+ * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order
+ * to minimize maximum blocking time.
  */
 static int ecp_precompute_comb( const mbedtls_ecp_group *grp,
                                 mbedtls_ecp_point T[], const mbedtls_ecp_point *P,
-                                unsigned char w, size_t d )
+                                unsigned char w, size_t d,
+                                mbedtls_ecp_restart_ctx *rs_ctx )
 {
     int ret;
-    unsigned char i, k;
-    size_t j;
+    unsigned char i;
+    size_t j = 0;
+    const unsigned char T_size = 1U << ( w - 1 );
     mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1];
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+    {
+        if( rs_ctx->rsm->state == ecp_rsm_pre_dbl )
+            goto dbl;
+        if( rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl )
+            goto norm_dbl;
+        if( rs_ctx->rsm->state == ecp_rsm_pre_add )
+            goto add;
+        if( rs_ctx->rsm->state == ecp_rsm_pre_norm_add )
+            goto norm_add;
+    }
+#else
+    (void) rs_ctx;
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+    {
+        rs_ctx->rsm->state = ecp_rsm_pre_dbl;
+
+        /* initial state for the loop */
+        rs_ctx->rsm->i = 0;
+    }
+
+dbl:
+#endif
     /*
      * Set T[0] = P and
      * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value)
      */
     MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) );
 
-    k = 0;
-    for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 )
+        j = rs_ctx->rsm->i;
+    else
+#endif
+        j = 0;
+
+    for( ; j < d * ( w - 1 ); j++ )
     {
+        MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL );
+
+        i = 1U << ( j / d );
         cur = T + i;
-        MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) );
-        for( j = 0; j < d; j++ )
-            MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) );
 
-        TT[k++] = cur;
+        if( j % d == 0 )
+            MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) );
+
+        MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) );
     }
 
-    MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) );
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+        rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl;
+
+norm_dbl:
+#endif
+    /*
+     * Normalize current elements in T. As T has holes,
+     * use an auxiliary array of pointers to elements in T.
+     */
+    j = 0;
+    for( i = 1; i < T_size; i <<= 1 )
+        TT[j++] = T + i;
+
+    MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 );
 
+    MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+        rs_ctx->rsm->state = ecp_rsm_pre_add;
+
+add:
+#endif
     /*
      * Compute the remaining ones using the minimal number of additions
      * Be careful to update T[2^l] only after using it!
      */
-    k = 0;
-    for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
+    MBEDTLS_ECP_BUDGET( ( T_size - 1 ) * MBEDTLS_ECP_OPS_ADD );
+
+    for( i = 1; i < T_size; i <<= 1 )
     {
         j = i;
         while( j-- )
-        {
             MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) );
-            TT[k++] = &T[i + j];
-        }
     }
 
-    MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) );
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+        rs_ctx->rsm->state = ecp_rsm_pre_norm_add;
+
+norm_add:
+#endif
+    /*
+     * Normalize final elements in T. Even though there are no holes now, we
+     * still need the auxiliary array for homogeneity with the previous
+     * call. Also, skip T[0] which is already normalised, being a copy of P.
+     */
+    for( j = 0; j + 1 < T_size; j++ )
+        TT[j] = T + j + 1;
+
+    MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 );
+
+    MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) );
 
 cleanup:
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL &&
+        ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+    {
+        if( rs_ctx->rsm->state == ecp_rsm_pre_dbl )
+            rs_ctx->rsm->i = j;
+    }
+#endif
 
     return( ret );
 }
 
 /*
  * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ]
+ *
+ * See ecp_comb_recode_core() for background
  */
 static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
-                            const mbedtls_ecp_point T[], unsigned char t_len,
+                            const mbedtls_ecp_point T[], unsigned char T_size,
                             unsigned char i )
 {
     int ret;
@@ -1290,7 +1657,7 @@ static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
     ii =  ( i & 0x7Fu ) >> 1;
 
     /* Read the whole table to thwart cache-based timing attacks */
-    for( j = 0; j < t_len; j++ )
+    for( j = 0; j < T_size; j++ )
     {
         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) );
@@ -1310,10 +1677,11 @@ cleanup:
  * Cost: d A + d D + 1 R
  */
 static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
-                              const mbedtls_ecp_point T[], unsigned char t_len,
+                              const mbedtls_ecp_point T[], unsigned char T_size,
                               const unsigned char x[], size_t d,
                               int (*f_rng)(void *, unsigned char *, size_t),
-                              void *p_rng )
+                              void *p_rng,
+                              mbedtls_ecp_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_ecp_point Txi;
@@ -1321,17 +1689,42 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R
 
     mbedtls_ecp_point_init( &Txi );
 
-    /* Start with a non-zero point and randomize its coordinates */
-    i = d;
-    MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) );
-    if( f_rng != 0 )
-        MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) );
+#if !defined(MBEDTLS_ECP_RESTARTABLE)
+    (void) rs_ctx;
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL &&
+        rs_ctx->rsm->state != ecp_rsm_comb_core )
+    {
+        rs_ctx->rsm->i = 0;
+        rs_ctx->rsm->state = ecp_rsm_comb_core;
+    }
 
-    while( i-- != 0 )
+    /* new 'if' instead of nested for the sake of the 'else' branch */
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 )
     {
+        /* restore current index (R already pointing to rs_ctx->rsm->R) */
+        i = rs_ctx->rsm->i;
+    }
+    else
+#endif
+    {
+        /* Start with a non-zero point and randomize its coordinates */
+        i = d;
+        MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, T_size, x[i] ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) );
+        if( f_rng != 0 )
+            MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) );
+    }
+
+    while( i != 0 )
+    {
+        MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD );
+        --i;
+
         MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) );
-        MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) );
+        MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, T_size, x[i] ) );
         MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) );
     }
 
@@ -1339,32 +1732,130 @@ cleanup:
 
     mbedtls_ecp_point_free( &Txi );
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL &&
+        ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+    {
+        rs_ctx->rsm->i = i;
+        /* no need to save R, already pointing to rs_ctx->rsm->R */
+    }
+#endif
+
     return( ret );
 }
 
 /*
- * Multiplication using the comb method,
- * for curves in short Weierstrass form
- */
-static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
-                         const mbedtls_mpi *m, const mbedtls_ecp_point *P,
-                         int (*f_rng)(void *, unsigned char *, size_t),
-                         void *p_rng )
+ * Recode the scalar to get constant-time comb multiplication
+ *
+ * As the actual scalar recoding needs an odd scalar as a starting point,
+ * this wrapper ensures that by replacing m by N - m if necessary, and
+ * informs the caller that the result of multiplication will be negated.
+ *
+ * This works because we only support large prime order for Short Weierstrass
+ * curves, so N is always odd hence either m or N - m is.
+ *
+ * See ecp_comb_recode_core() for background.
+ */
+static int ecp_comb_recode_scalar( const mbedtls_ecp_group *grp,
+                                   const mbedtls_mpi *m,
+                                   unsigned char k[COMB_MAX_D + 1],
+                                   size_t d,
+                                   unsigned char w,
+                                   unsigned char *parity_trick )
 {
     int ret;
-    unsigned char w, m_is_odd, p_eq_g, pre_len, i;
-    size_t d;
-    unsigned char k[COMB_MAX_D + 1];
-    mbedtls_ecp_point *T;
     mbedtls_mpi M, mm;
 
     mbedtls_mpi_init( &M );
     mbedtls_mpi_init( &mm );
 
-    /* we need N to be odd to trnaform m in an odd number, check now */
+    /* N is always odd (see above), just make extra sure */
     if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
+    /* do we need the parity trick? */
+    *parity_trick = ( mbedtls_mpi_get_bit( m, 0 ) == 0 );
+
+    /* execute parity fix in constant time */
+    MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, *parity_trick ) );
+
+    /* actual scalar recoding */
+    ecp_comb_recode_core( k, d, w, &M );
+
+cleanup:
+    mbedtls_mpi_free( &mm );
+    mbedtls_mpi_free( &M );
+
+    return( ret );
+}
+
+/*
+ * Perform comb multiplication (for short Weierstrass curves)
+ * once the auxiliary table has been pre-computed.
+ *
+ * Scalar recoding may use a parity trick that makes us compute -m * P,
+ * if that is the case we'll need to recover m * P at the end.
+ */
+static int ecp_mul_comb_after_precomp( const mbedtls_ecp_group *grp,
+                                mbedtls_ecp_point *R,
+                                const mbedtls_mpi *m,
+                                const mbedtls_ecp_point *T,
+                                unsigned char T_size,
+                                unsigned char w,
+                                size_t d,
+                                int (*f_rng)(void *, unsigned char *, size_t),
+                                void *p_rng,
+                                mbedtls_ecp_restart_ctx *rs_ctx )
+{
+    int ret;
+    unsigned char parity_trick;
+    unsigned char k[COMB_MAX_D + 1];
+    mbedtls_ecp_point *RR = R;
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+    {
+        RR = &rs_ctx->rsm->R;
+
+        if( rs_ctx->rsm->state == ecp_rsm_final_norm )
+            goto final_norm;
+    }
+#endif
+
+    MBEDTLS_MPI_CHK( ecp_comb_recode_scalar( grp, m, k, d, w,
+                                            &parity_trick ) );
+    MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, RR, T, T_size, k, d,
+                                        f_rng, p_rng, rs_ctx ) );
+    MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, RR, parity_trick ) );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+        rs_ctx->rsm->state = ecp_rsm_final_norm;
+
+final_norm:
+#endif
+    MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV );
+    MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, RR ) );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL )
+        MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, RR ) );
+#endif
+
+cleanup:
+    return( ret );
+}
+
+/*
+ * Pick window size based on curve size and whether we optimize for base point
+ */
+static unsigned char ecp_pick_window_size( const mbedtls_ecp_group *grp,
+                                           unsigned char p_eq_g )
+{
+    unsigned char w;
+
     /*
      * Minimize the number of multiplications, that is minimize
      * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w )
@@ -1377,14 +1868,8 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
      * Just adding one avoids upping the cost of the first mul too much,
      * and the memory cost too.
      */
-#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
-    p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 &&
-               mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 );
     if( p_eq_g )
         w++;
-#else
-    p_eq_g = 0;
-#endif
 
     /*
      * Make sure w is within bounds.
@@ -1395,75 +1880,140 @@ static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
     if( w >= grp->nbits )
         w = 2;
 
-    /* Other sizes that depend on w */
-    pre_len = 1U << ( w - 1 );
+    return( w );
+}
+
+/*
+ * Multiplication using the comb method - for curves in short Weierstrass form
+ *
+ * This function is mainly responsible for administrative work:
+ * - managing the restart context if enabled
+ * - managing the table of precomputed points (passed between the below two
+ *   functions): allocation, computation, ownership tranfer, freeing.
+ *
+ * It delegates the actual arithmetic work to:
+ *      ecp_precompute_comb() and ecp_mul_comb_with_precomp()
+ *
+ * See comments on ecp_comb_recode_core() regarding the computation strategy.
+ */
+static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+                         const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+                         int (*f_rng)(void *, unsigned char *, size_t),
+                         void *p_rng,
+                         mbedtls_ecp_restart_ctx *rs_ctx )
+{
+    int ret;
+    unsigned char w, p_eq_g, i;
+    size_t d;
+    unsigned char T_size, T_ok;
+    mbedtls_ecp_point *T;
+
+    ECP_RS_ENTER( rsm );
+
+    /* Is P the base point ? */
+#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
+    p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 &&
+               mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 );
+#else
+    p_eq_g = 0;
+#endif
+
+    /* Pick window size and deduce related sizes */
+    w = ecp_pick_window_size( grp, p_eq_g );
+    T_size = 1U << ( w - 1 );
     d = ( grp->nbits + w - 1 ) / w;
 
-    /*
-     * Prepare precomputed points: if P == G we want to
-     * use grp->T if already initialized, or initialize it.
-     */
-    T = p_eq_g ? grp->T : NULL;
+    /* Pre-computed table: do we have it already for the base point? */
+    if( p_eq_g && grp->T != NULL )
+    {
+        /* second pointer to the same table, will be deleted on exit */
+        T = grp->T;
+        T_ok = 1;
+    }
+    else
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    /* Pre-computed table: do we have one in progress? complete? */
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL )
+    {
+        /* transfer ownership of T from rsm to local function */
+        T = rs_ctx->rsm->T;
+        rs_ctx->rsm->T = NULL;
+        rs_ctx->rsm->T_size = 0;
 
-    if( T == NULL )
+        /* This effectively jumps to the call to mul_comb_after_precomp() */
+        T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core;
+    }
+    else
+#endif
+    /* Allocate table if we didn't have any */
     {
-        T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) );
+        T = mbedtls_calloc( T_size, sizeof( mbedtls_ecp_point ) );
         if( T == NULL )
         {
             ret = MBEDTLS_ERR_ECP_ALLOC_FAILED;
             goto cleanup;
         }
 
-        MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) );
+        for( i = 0; i < T_size; i++ )
+            mbedtls_ecp_point_init( &T[i] );
+
+        T_ok = 0;
+    }
+
+    /* Compute table (or finish computing it) if not done already */
+    if( !T_ok )
+    {
+        MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d, rs_ctx ) );
 
         if( p_eq_g )
         {
+            /* almost transfer ownership of T to the group, but keep a copy of
+             * the pointer to use for calling the next function more easily */
             grp->T = T;
-            grp->T_size = pre_len;
+            grp->T_size = T_size;
         }
     }
 
-    /*
-     * Make sure M is odd (M = m or M = N - m, since N is odd)
-     * using the fact that m * P = - (N - m) * P
-     */
-    m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) );
+    /* Actual comb multiplication using precomputed points */
+    MBEDTLS_MPI_CHK( ecp_mul_comb_after_precomp( grp, R, m,
+                                                 T, T_size, w, d,
+                                                 f_rng, p_rng, rs_ctx ) );
 
-    /*
-     * Go for comb multiplication, R = M * P
-     */
-    ecp_comb_fixed( k, d, w, &M );
-    MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) );
+cleanup:
 
-    /*
-     * Now get m * P from M * P and normalize it
-     */
-    MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) );
-    MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
+    /* does T belong to the group? */
+    if( T == grp->T )
+        T = NULL;
 
-cleanup:
+    /* does T belong to the restart context? */
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL )
+    {
+        /* transfer ownership of T from local function to rsm */
+        rs_ctx->rsm->T_size = T_size;
+        rs_ctx->rsm->T = T;
+        T = NULL;
+    }
+#endif
 
-    /* There are two cases where T is not stored in grp:
-     * - P != G
-     * - An intermediate operation failed before setting grp->T
-     * In either case, T must be freed.
-     */
-    if( T != NULL && T != grp->T )
+    /* did T belong to us? then let's destroy it! */
+    if( T != NULL )
     {
-        for( i = 0; i < pre_len; i++ )
+        for( i = 0; i < T_size; i++ )
             mbedtls_ecp_point_free( &T[i] );
         mbedtls_free( T );
     }
 
-    mbedtls_mpi_free( &M );
-    mbedtls_mpi_free( &mm );
-
+    /* don't free R while in progress in case R == P */
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
+#endif
+    /* prevent caller from using invalid value */
     if( ret != 0 )
         mbedtls_ecp_point_free( R );
 
+    ECP_RS_LEAVE( rsm );
+
     return( ret );
 }
 
@@ -1487,10 +2037,8 @@ static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P
     int ret;
 
 #if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_normalize_mxz( grp, P );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_normalize_mxz( grp, P ) );
 #endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */
 
     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) );
@@ -1518,10 +2066,8 @@ static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P
     int count = 0;
 
 #if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng );
 #endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */
 
     p_size = ( grp->pbits + 7 ) / 8;
@@ -1573,10 +2119,8 @@ static int ecp_double_add_mxz( const mbedtls_ecp_group *grp,
     mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB;
 
 #if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
-    if ( mbedtls_internal_ecp_grp_capable( grp ) )
-    {
-        return mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d );
-    }
+    if( mbedtls_internal_ecp_grp_capable( grp ) )
+        return( mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d ) );
 #endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */
 
     mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B );
@@ -1673,54 +2217,77 @@ cleanup:
 #endif /* ECP_MONTGOMERY */
 
 /*
- * Multiplication R = m * P
+ * Restartable multiplication R = m * P
  */
-int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
              const mbedtls_mpi *m, const mbedtls_ecp_point *P,
-             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+             mbedtls_ecp_restart_ctx *rs_ctx )
 {
     int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
 #if defined(MBEDTLS_ECP_INTERNAL_ALT)
     char is_grp_capable = 0;
 #endif
 
-    /* Common sanity checks */
-    if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 )
-        return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
-
-    if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 ||
-        ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 )
-        return( ret );
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    /* reset ops count for this call if top-level */
+    if( rs_ctx != NULL && rs_ctx->depth++ == 0 )
+        rs_ctx->ops_done = 0;
+#endif
 
 #if defined(MBEDTLS_ECP_INTERNAL_ALT)
-    if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp )  )
-    {
+    if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) )
         MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
+#endif /* MBEDTLS_ECP_INTERNAL_ALT */
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    /* skip argument check when restarting */
+    if( rs_ctx == NULL || rs_ctx->rsm == NULL )
+#endif
+    {
+        /* check_privkey is free */
+        MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_CHK );
+
+        /* Common sanity checks */
+        MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( grp, m ) );
+        MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) );
     }
 
-#endif /* MBEDTLS_ECP_INTERNAL_ALT */
+    ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
 #if defined(ECP_MONTGOMERY)
     if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
-        ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng );
-
+        MBEDTLS_MPI_CHK( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) );
 #endif
 #if defined(ECP_SHORTWEIERSTRASS)
     if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
-        ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng );
-
+        MBEDTLS_MPI_CHK( ecp_mul_comb( grp, R, m, P, f_rng, p_rng, rs_ctx ) );
 #endif
-#if defined(MBEDTLS_ECP_INTERNAL_ALT)
+
 cleanup:
 
-    if ( is_grp_capable )
-    {
+#if defined(MBEDTLS_ECP_INTERNAL_ALT)
+    if( is_grp_capable )
         mbedtls_internal_ecp_free( grp );
-    }
-
 #endif /* MBEDTLS_ECP_INTERNAL_ALT */
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL )
+        rs_ctx->depth--;
+#endif
+
     return( ret );
 }
 
+/*
+ * Multiplication R = m * P
+ */
+int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+             const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+    return( mbedtls_ecp_mul_restartable( grp, R, m, P, f_rng, p_rng, NULL ) );
+}
+
 #if defined(ECP_SHORTWEIERSTRASS)
 /*
  * Check that an affine point is valid as a public key,
@@ -1778,7 +2345,8 @@ cleanup:
 static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp,
                                       mbedtls_ecp_point *R,
                                       const mbedtls_mpi *m,
-                                      const mbedtls_ecp_point *P )
+                                      const mbedtls_ecp_point *P,
+                                      mbedtls_ecp_restart_ctx *rs_ctx )
 {
     int ret;
 
@@ -1794,7 +2362,8 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp,
     }
     else
     {
-        MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) );
+        MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, R, m, P,
+                                                      NULL, NULL, rs_ctx ) );
     }
 
 cleanup:
@@ -1802,15 +2371,19 @@ cleanup:
 }
 
 /*
- * Linear combination
+ * Restartable linear combination
  * NOT constant-time
  */
-int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+int mbedtls_ecp_muladd_restartable(
+             mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
              const mbedtls_mpi *m, const mbedtls_ecp_point *P,
-             const mbedtls_mpi *n, const mbedtls_ecp_point *Q )
+             const mbedtls_mpi *n, const mbedtls_ecp_point *Q,
+             mbedtls_ecp_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_ecp_point mP;
+    mbedtls_ecp_point *pmP = &mP;
+    mbedtls_ecp_point *pR = R;
 #if defined(MBEDTLS_ECP_INTERNAL_ALT)
     char is_grp_capable = 0;
 #endif
@@ -1820,33 +2393,83 @@ int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
 
     mbedtls_ecp_point_init( &mP );
 
-    MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) );
-    MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R,   n, Q ) );
-
 #if defined(MBEDTLS_ECP_INTERNAL_ALT)
-    if (  is_grp_capable = mbedtls_internal_ecp_grp_capable( grp )  )
-    {
+    if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) )
         MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
-    }
-
 #endif /* MBEDTLS_ECP_INTERNAL_ALT */
-    MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) );
-    MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
 
-cleanup:
+    ECP_RS_ENTER( ma );
 
-#if defined(MBEDTLS_ECP_INTERNAL_ALT)
-    if ( is_grp_capable )
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ma != NULL )
     {
-        mbedtls_internal_ecp_free( grp );
+        /* redirect intermediate results to restart context */
+        pmP = &rs_ctx->ma->mP;
+        pR  = &rs_ctx->ma->R;
+
+        /* jump to next operation */
+        if( rs_ctx->ma->state == ecp_rsma_mul2 )
+            goto mul2;
+        if( rs_ctx->ma->state == ecp_rsma_add )
+            goto add;
+        if( rs_ctx->ma->state == ecp_rsma_norm )
+            goto norm;
     }
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
+    MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pmP, m, P, rs_ctx ) );
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ma != NULL )
+        rs_ctx->ma->state = ecp_rsma_mul2;
 
+mul2:
+#endif
+    MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pR,  n, Q, rs_ctx ) );
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ma != NULL )
+        rs_ctx->ma->state = ecp_rsma_add;
+
+add:
+#endif
+    MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_ADD );
+    MBEDTLS_MPI_CHK( ecp_add_mixed( grp, pR, pmP, pR ) );
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ma != NULL )
+        rs_ctx->ma->state = ecp_rsma_norm;
+
+norm:
+#endif
+    MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV );
+    MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, pR ) );
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && rs_ctx->ma != NULL )
+        MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, pR ) );
+#endif
+
+cleanup:
+#if defined(MBEDTLS_ECP_INTERNAL_ALT)
+    if( is_grp_capable )
+        mbedtls_internal_ecp_free( grp );
 #endif /* MBEDTLS_ECP_INTERNAL_ALT */
+
     mbedtls_ecp_point_free( &mP );
 
+    ECP_RS_LEAVE( ma );
+
     return( ret );
 }
 
+/*
+ * Linear combination
+ * NOT constant-time
+ */
+int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+             const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+             const mbedtls_mpi *n, const mbedtls_ecp_point *Q )
+{
+    return( mbedtls_ecp_muladd_restartable( grp, R, m, P, n, Q, NULL ) );
+}
 
 #if defined(ECP_MONTGOMERY)
 /*
@@ -1921,15 +2544,14 @@ int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *
 }
 
 /*
- * Generate a keypair with configurable base point
+ * Generate a private key
  */
-int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
-                     const mbedtls_ecp_point *G,
-                     mbedtls_mpi *d, mbedtls_ecp_point *Q,
+int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp,
+                     mbedtls_mpi *d,
                      int (*f_rng)(void *, unsigned char *, size_t),
                      void *p_rng )
 {
-    int ret;
+    int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
     size_t n_size = ( grp->nbits + 7 ) / 8;
 
 #if defined(ECP_MONTGOMERY)
@@ -1958,8 +2580,8 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
             MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) );
         }
     }
-    else
 #endif /* ECP_MONTGOMERY */
+
 #if defined(ECP_SHORTWEIERSTRASS)
     if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
     {
@@ -1993,15 +2615,28 @@ int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
         while( mbedtls_mpi_cmp_int( d, 1 ) < 0 ||
                mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 );
     }
-    else
 #endif /* ECP_SHORTWEIERSTRASS */
-        return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
 cleanup:
-    if( ret != 0 )
-        return( ret );
+    return( ret );
+}
+
+/*
+ * Generate a keypair with configurable base point
+ */
+int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
+                     const mbedtls_ecp_point *G,
+                     mbedtls_mpi *d, mbedtls_ecp_point *Q,
+                     int (*f_rng)(void *, unsigned char *, size_t),
+                     void *p_rng )
+{
+    int ret;
+
+    MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
+    MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) );
 
-    return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) );
+cleanup:
+    return( ret );
 }
 
 /*
diff --git a/crypto/mbedtls/src/error.c b/crypto/mbedtls/src/error.c
index 6c88689..eabee9e 100644
--- a/crypto/mbedtls/src/error.c
+++ b/crypto/mbedtls/src/error.c
@@ -165,6 +165,10 @@
 #include "mbedtls/pkcs5.h"
 #endif
 
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#endif
+
 #if defined(MBEDTLS_POLY1305_C)
 #include "mbedtls/poly1305.h"
 #endif
@@ -289,6 +293,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
             mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" );
         if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) )
             mbedtls_snprintf( buf, buflen, "ECP - The ECP hardware accelerator failed" );
+        if( use_ret == -(MBEDTLS_ERR_ECP_IN_PROGRESS) )
+            mbedtls_snprintf( buf, buflen, "ECP - Operation in progress, call again with the same parameters to continue" );
 #endif /* MBEDTLS_ECP_C */
 
 #if defined(MBEDTLS_MD_C)
@@ -517,6 +523,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
             mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" );
         if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) )
             mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" );
+        if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) )
+            mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" );
 #endif /* MBEDTLS_SSL_TLS_C */
 
 #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
@@ -823,6 +831,13 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
         mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" );
 #endif /* MBEDTLS_PADLOCK_C */
 
+#if defined(MBEDTLS_PLATFORM_C)
+    if( use_ret == -(MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED) )
+        mbedtls_snprintf( buf, buflen, "PLATFORM - Hardware accelerator failed" );
+    if( use_ret == -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) )
+        mbedtls_snprintf( buf, buflen, "PLATFORM - The requested feature is not supported by the platform" );
+#endif /* MBEDTLS_PLATFORM_C */
+
 #if defined(MBEDTLS_POLY1305_C)
     if( use_ret == -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA) )
         mbedtls_snprintf( buf, buflen, "POLY1305 - Invalid input parameter(s)" );
diff --git a/crypto/mbedtls/src/gcm.c b/crypto/mbedtls/src/gcm.c
index 8992a31..75e650f 100644
--- a/crypto/mbedtls/src/gcm.c
+++ b/crypto/mbedtls/src/gcm.c
@@ -48,9 +48,8 @@
 
 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
 #include "mbedtls/aes.h"
-#if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
-#else
+#if !defined(MBEDTLS_PLATFORM_C)
 #include <stdio.h>
 #define mbedtls_printf printf
 #endif /* MBEDTLS_PLATFORM_C */
@@ -799,7 +798,7 @@ int mbedtls_gcm_self_test( int verbose )
              * there is an alternative underlying implementation i.e. when
              * MBEDTLS_AES_ALT is defined.
              */
-            if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && key_len == 192 )
+            if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && key_len == 192 )
             {
                 mbedtls_printf( "skipped\n" );
                 break;
diff --git a/crypto/mbedtls/src/hmac_drbg.c b/crypto/mbedtls/src/hmac_drbg.c
index dad55ff..6aa1e19 100644
--- a/crypto/mbedtls/src/hmac_drbg.c
+++ b/crypto/mbedtls/src/hmac_drbg.c
@@ -66,29 +66,56 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
 /*
  * HMAC_DRBG update, using optional additional data (10.1.2.2)
  */
-void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
-                       const unsigned char *additional, size_t add_len )
+int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
+                                  const unsigned char *additional,
+                                  size_t add_len )
 {
     size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
     unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1;
     unsigned char sep[1];
     unsigned char K[MBEDTLS_MD_MAX_SIZE];
+    int ret = 0;
 
     for( sep[0] = 0; sep[0] < rounds; sep[0]++ )
     {
         /* Step 1 or 4 */
-        mbedtls_md_hmac_reset( &ctx->md_ctx );
-        mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
-        mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 );
+        if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 )
+            goto exit;
+        if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
+                                            ctx->V, md_len ) ) != 0 )
+            goto exit;
+        if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
+                                            sep, 1 ) ) != 0 )
+            goto exit;
         if( rounds == 2 )
-            mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len );
-        mbedtls_md_hmac_finish( &ctx->md_ctx, K );
+        {
+            if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
+                                                additional, add_len ) ) != 0 )
+            goto exit;
+        }
+        if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 )
+            goto exit;
 
         /* Step 2 or 5 */
-        mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len );
-        mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
-        mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V );
+        if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 )
+            goto exit;
+        if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
+                                            ctx->V, md_len ) ) != 0 )
+            goto exit;
+        if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 )
+            goto exit;
     }
+
+exit:
+    mbedtls_platform_zeroize( K, sizeof( K ) );
+    return( ret );
+}
+
+void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
+                               const unsigned char *additional,
+                               size_t add_len )
+{
+    (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len );
 }
 
 /*
@@ -108,10 +135,13 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
      * Use the V memory location, which is currently all 0, to initialize the
      * MD context with an all-zero key. Then set V to its initial value.
      */
-    mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) );
+    if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V,
+                                        mbedtls_md_get_size( md_info ) ) ) != 0 )
+        return( ret );
     memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) );
 
-    mbedtls_hmac_drbg_update( ctx, data, data_len );
+    if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 )
+        return( ret );
 
     return( 0 );
 }
@@ -124,6 +154,7 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
 {
     unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT];
     size_t seedlen;
+    int ret;
 
     /* III. Check input length */
     if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT ||
@@ -135,7 +166,8 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
     memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT );
 
     /* IV. Gather entropy_len bytes of entropy for the seed */
-    if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 )
+    if( ( ret = ctx->f_entropy( ctx->p_entropy,
+                                seed, ctx->entropy_len ) ) != 0 )
         return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
 
     seedlen = ctx->entropy_len;
@@ -148,13 +180,16 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
     }
 
     /* 2. Update state */
-    mbedtls_hmac_drbg_update( ctx, seed, seedlen );
+    if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 )
+        goto exit;
 
     /* 3. Reset reseed_counter */
     ctx->reseed_counter = 1;
 
+exit:
     /* 4. Done */
-    return( 0 );
+    mbedtls_platform_zeroize( seed, seedlen );
+    return( ret );
 }
 
 /*
@@ -180,7 +215,8 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
      * Use the V memory location, which is currently all 0, to initialize the
      * MD context with an all-zero key. Then set V to its initial value.
      */
-    mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size );
+    if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ) ) != 0 )
+        return( ret );
     memset( ctx->V, 0x01, md_size );
 
     ctx->f_entropy = f_entropy;
@@ -273,16 +309,24 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng,
 
     /* 2. Use additional data if any */
     if( additional != NULL && add_len != 0 )
-        mbedtls_hmac_drbg_update( ctx, additional, add_len );
+    {
+        if( ( ret = mbedtls_hmac_drbg_update_ret( ctx,
+                                                  additional, add_len ) ) != 0 )
+            goto exit;
+    }
 
     /* 3, 4, 5. Generate bytes */
     while( left != 0 )
     {
         size_t use_len = left > md_len ? md_len : left;
 
-        mbedtls_md_hmac_reset( &ctx->md_ctx );
-        mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
-        mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V );
+        if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 )
+            goto exit;
+        if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
+                                            ctx->V, md_len ) ) != 0 )
+            goto exit;
+        if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 )
+            goto exit;
 
         memcpy( out, ctx->V, use_len );
         out += use_len;
@@ -290,13 +334,16 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng,
     }
 
     /* 6. Update */
-    mbedtls_hmac_drbg_update( ctx, additional, add_len );
+    if( ( ret = mbedtls_hmac_drbg_update_ret( ctx,
+                                              additional, add_len ) ) != 0 )
+        goto exit;
 
     /* 7. Update reseed counter */
     ctx->reseed_counter++;
 
+exit:
     /* 8. Done */
-    return( 0 );
+    return( ret );
 }
 
 /*
@@ -388,7 +435,7 @@ int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const ch
     if( fread( buf, 1, n, f ) != n )
         ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
     else
-        mbedtls_hmac_drbg_update( ctx, buf, n );
+        ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n );
 
     fclose( f );
 
diff --git a/crypto/mbedtls/src/pk.c b/crypto/mbedtls/src/pk.c
index f05b139..e0e8dba 100644
--- a/crypto/mbedtls/src/pk.c
+++ b/crypto/mbedtls/src/pk.c
@@ -69,6 +69,34 @@ void mbedtls_pk_free( mbedtls_pk_context *ctx )
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pk_context ) );
 }
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+/*
+ * Initialize a restart context
+ */
+void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx )
+{
+    ctx->pk_info = NULL;
+    ctx->rs_ctx = NULL;
+}
+
+/*
+ * Free the components of a restart context
+ */
+void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx )
+{
+    if( ctx == NULL || ctx->pk_info == NULL ||
+        ctx->pk_info->rs_free_func == NULL )
+    {
+        return;
+    }
+
+    ctx->pk_info->rs_free_func( ctx->rs_ctx );
+
+    ctx->pk_info = NULL;
+    ctx->rs_ctx = NULL;
+}
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
 /*
  * Get pk_info structure from type
  */
@@ -171,17 +199,66 @@ static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len
     return( 0 );
 }
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
 /*
- * Verify a signature
+ * Helper to set up a restart context if needed
  */
-int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+static int pk_restart_setup( mbedtls_pk_restart_ctx *ctx,
+                             const mbedtls_pk_info_t *info )
+{
+    /* Don't do anything if already set up or invalid */
+    if( ctx == NULL || ctx->pk_info != NULL )
+        return( 0 );
+
+    /* Should never happen when we're called */
+    if( info->rs_alloc_func == NULL || info->rs_free_func == NULL )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+
+    if( ( ctx->rs_ctx = info->rs_alloc_func() ) == NULL )
+        return( MBEDTLS_ERR_PK_ALLOC_FAILED );
+
+    ctx->pk_info = info;
+
+    return( 0 );
+}
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
+/*
+ * Verify a signature (restartable)
+ */
+int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx,
+               mbedtls_md_type_t md_alg,
                const unsigned char *hash, size_t hash_len,
-               const unsigned char *sig, size_t sig_len )
+               const unsigned char *sig, size_t sig_len,
+               mbedtls_pk_restart_ctx *rs_ctx )
 {
     if( ctx == NULL || ctx->pk_info == NULL ||
         pk_hashlen_helper( md_alg, &hash_len ) != 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /* optimization: use non-restartable version if restart disabled */
+    if( rs_ctx != NULL &&
+        mbedtls_ecp_restart_is_enabled() &&
+        ctx->pk_info->verify_rs_func != NULL )
+    {
+        int ret;
+
+        if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 )
+            return( ret );
+
+        ret = ctx->pk_info->verify_rs_func( ctx->pk_ctx,
+                   md_alg, hash, hash_len, sig, sig_len, rs_ctx->rs_ctx );
+
+        if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
+            mbedtls_pk_restart_free( rs_ctx );
+
+        return( ret );
+    }
+#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+    (void) rs_ctx;
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
     if( ctx->pk_info->verify_func == NULL )
         return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
 
@@ -190,6 +267,17 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
 }
 
 /*
+ * Verify a signature
+ */
+int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+               const unsigned char *hash, size_t hash_len,
+               const unsigned char *sig, size_t sig_len )
+{
+    return( mbedtls_pk_verify_restartable( ctx, md_alg, hash, hash_len,
+                                           sig, sig_len, NULL ) );
+}
+
+/*
  * Verify a signature with options
  */
 int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options,
@@ -248,17 +336,42 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options,
 }
 
 /*
- * Make a signature
+ * Make a signature (restartable)
  */
-int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx,
+             mbedtls_md_type_t md_alg,
              const unsigned char *hash, size_t hash_len,
              unsigned char *sig, size_t *sig_len,
-             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+             mbedtls_pk_restart_ctx *rs_ctx )
 {
     if( ctx == NULL || ctx->pk_info == NULL ||
         pk_hashlen_helper( md_alg, &hash_len ) != 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /* optimization: use non-restartable version if restart disabled */
+    if( rs_ctx != NULL &&
+        mbedtls_ecp_restart_is_enabled() &&
+        ctx->pk_info->sign_rs_func != NULL )
+    {
+        int ret;
+
+        if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 )
+            return( ret );
+
+        ret = ctx->pk_info->sign_rs_func( ctx->pk_ctx, md_alg,
+                hash, hash_len, sig, sig_len, f_rng, p_rng, rs_ctx->rs_ctx );
+
+        if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
+            mbedtls_pk_restart_free( rs_ctx );
+
+        return( ret );
+    }
+#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+    (void) rs_ctx;
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
     if( ctx->pk_info->sign_func == NULL )
         return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
 
@@ -267,6 +380,18 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
 }
 
 /*
+ * Make a signature
+ */
+int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+             const unsigned char *hash, size_t hash_len,
+             unsigned char *sig, size_t *sig_len,
+             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+    return( mbedtls_pk_sign_restartable( ctx, md_alg, hash, hash_len,
+                                         sig, sig_len, f_rng, p_rng, NULL ) );
+}
+
+/*
  * Decrypt message
  */
 int mbedtls_pk_decrypt( mbedtls_pk_context *ctx,
diff --git a/crypto/mbedtls/src/pk_wrap.c b/crypto/mbedtls/src/pk_wrap.c
index 2c7d2d7..87806be 100644
--- a/crypto/mbedtls/src/pk_wrap.c
+++ b/crypto/mbedtls/src/pk_wrap.c
@@ -190,11 +190,19 @@ const mbedtls_pk_info_t mbedtls_rsa_info = {
     rsa_can_do,
     rsa_verify_wrap,
     rsa_sign_wrap,
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    NULL,
+    NULL,
+#endif
     rsa_decrypt_wrap,
     rsa_encrypt_wrap,
     rsa_check_pair_wrap,
     rsa_alloc_wrap,
     rsa_free_wrap,
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    NULL,
+    NULL,
+#endif
     rsa_debug,
 };
 #endif /* MBEDTLS_RSA_C */
@@ -262,6 +270,110 @@ static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
     return( ret );
 }
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+/* Forward declarations */
+static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                       const unsigned char *hash, size_t hash_len,
+                       const unsigned char *sig, size_t sig_len,
+                       void *rs_ctx );
+
+static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                   const unsigned char *hash, size_t hash_len,
+                   unsigned char *sig, size_t *sig_len,
+                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+                   void *rs_ctx );
+
+/*
+ * Restart context for ECDSA operations with ECKEY context
+ *
+ * We need to store an actual ECDSA context, as we need to pass the same to
+ * the underlying ecdsa function, so we can't create it on the fly every time.
+ */
+typedef struct
+{
+    mbedtls_ecdsa_restart_ctx ecdsa_rs;
+    mbedtls_ecdsa_context ecdsa_ctx;
+} eckey_restart_ctx;
+
+static void *eckey_rs_alloc( void )
+{
+    eckey_restart_ctx *rs_ctx;
+
+    void *ctx = mbedtls_calloc( 1, sizeof( eckey_restart_ctx ) );
+
+    if( ctx != NULL )
+    {
+        rs_ctx = ctx;
+        mbedtls_ecdsa_restart_init( &rs_ctx->ecdsa_rs );
+        mbedtls_ecdsa_init( &rs_ctx->ecdsa_ctx );
+    }
+
+    return( ctx );
+}
+
+static void eckey_rs_free( void *ctx )
+{
+    eckey_restart_ctx *rs_ctx;
+
+    if( ctx == NULL)
+        return;
+
+    rs_ctx = ctx;
+    mbedtls_ecdsa_restart_free( &rs_ctx->ecdsa_rs );
+    mbedtls_ecdsa_free( &rs_ctx->ecdsa_ctx );
+
+    mbedtls_free( ctx );
+}
+
+static int eckey_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                       const unsigned char *hash, size_t hash_len,
+                       const unsigned char *sig, size_t sig_len,
+                       void *rs_ctx )
+{
+    int ret;
+    eckey_restart_ctx *rs = rs_ctx;
+
+    /* Should never happen */
+    if( rs == NULL )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+
+    /* set up our own sub-context if needed (that is, on first run) */
+    if( rs->ecdsa_ctx.grp.pbits == 0 )
+        MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) );
+
+    MBEDTLS_MPI_CHK( ecdsa_verify_rs_wrap( &rs->ecdsa_ctx,
+                                           md_alg, hash, hash_len,
+                                           sig, sig_len, &rs->ecdsa_rs ) );
+
+cleanup:
+    return( ret );
+}
+
+static int eckey_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                   const unsigned char *hash, size_t hash_len,
+                   unsigned char *sig, size_t *sig_len,
+                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+                       void *rs_ctx )
+{
+    int ret;
+    eckey_restart_ctx *rs = rs_ctx;
+
+    /* Should never happen */
+    if( rs == NULL )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+
+    /* set up our own sub-context if needed (that is, on first run) */
+    if( rs->ecdsa_ctx.grp.pbits == 0 )
+        MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) );
+
+    MBEDTLS_MPI_CHK( ecdsa_sign_rs_wrap( &rs->ecdsa_ctx, md_alg,
+                                         hash, hash_len, sig, sig_len,
+                                         f_rng, p_rng, &rs->ecdsa_rs ) );
+
+cleanup:
+    return( ret );
+}
+#endif /* MBEDTLS_ECP_RESTARTABLE */
 #endif /* MBEDTLS_ECDSA_C */
 
 static int eckey_check_pair( const void *pub, const void *prv )
@@ -301,15 +413,23 @@ const mbedtls_pk_info_t mbedtls_eckey_info = {
 #if defined(MBEDTLS_ECDSA_C)
     eckey_verify_wrap,
     eckey_sign_wrap,
-#else
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    eckey_verify_rs_wrap,
+    eckey_sign_rs_wrap,
+#endif
+#else /* MBEDTLS_ECDSA_C */
     NULL,
     NULL,
-#endif
+#endif /* MBEDTLS_ECDSA_C */
     NULL,
     NULL,
     eckey_check_pair,
     eckey_alloc_wrap,
     eckey_free_wrap,
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    eckey_rs_alloc,
+    eckey_rs_free,
+#endif
     eckey_debug,
 };
 
@@ -329,11 +449,19 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = {
     eckeydh_can_do,
     NULL,
     NULL,
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    NULL,
+    NULL,
+#endif
     NULL,
     NULL,
     eckey_check_pair,
     eckey_alloc_wrap,       /* Same underlying key structure */
     eckey_free_wrap,        /* Same underlying key structure */
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    NULL,
+    NULL,
+#endif
     eckey_debug,            /* Same underlying key structure */
 };
 #endif /* MBEDTLS_ECP_C */
@@ -369,6 +497,40 @@ static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
                 md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) );
 }
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                       const unsigned char *hash, size_t hash_len,
+                       const unsigned char *sig, size_t sig_len,
+                       void *rs_ctx )
+{
+    int ret;
+    ((void) md_alg);
+
+    ret = mbedtls_ecdsa_read_signature_restartable(
+            (mbedtls_ecdsa_context *) ctx,
+            hash, hash_len, sig, sig_len,
+            (mbedtls_ecdsa_restart_ctx *) rs_ctx );
+
+    if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH )
+        return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH );
+
+    return( ret );
+}
+
+static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                   const unsigned char *hash, size_t hash_len,
+                   unsigned char *sig, size_t *sig_len,
+                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+                   void *rs_ctx )
+{
+    return( mbedtls_ecdsa_write_signature_restartable(
+                (mbedtls_ecdsa_context *) ctx,
+                md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng,
+                (mbedtls_ecdsa_restart_ctx *) rs_ctx ) );
+
+}
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 static void *ecdsa_alloc_wrap( void )
 {
     void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) );
@@ -385,6 +547,24 @@ static void ecdsa_free_wrap( void *ctx )
     mbedtls_free( ctx );
 }
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+static void *ecdsa_rs_alloc( void )
+{
+    void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_restart_ctx ) );
+
+    if( ctx != NULL )
+        mbedtls_ecdsa_restart_init( ctx );
+
+    return( ctx );
+}
+
+static void ecdsa_rs_free( void *ctx )
+{
+    mbedtls_ecdsa_restart_free( ctx );
+    mbedtls_free( ctx );
+}
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
 const mbedtls_pk_info_t mbedtls_ecdsa_info = {
     MBEDTLS_PK_ECDSA,
     "ECDSA",
@@ -392,11 +572,19 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = {
     ecdsa_can_do,
     ecdsa_verify_wrap,
     ecdsa_sign_wrap,
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    ecdsa_verify_rs_wrap,
+    ecdsa_sign_rs_wrap,
+#endif
     NULL,
     NULL,
     eckey_check_pair,   /* Compatible key structures */
     ecdsa_alloc_wrap,
     ecdsa_free_wrap,
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    ecdsa_rs_alloc,
+    ecdsa_rs_free,
+#endif
     eckey_debug,        /* Compatible key structures */
 };
 #endif /* MBEDTLS_ECDSA_C */
@@ -506,6 +694,10 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = {
     rsa_alt_can_do,
     NULL,
     rsa_alt_sign_wrap,
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    NULL,
+    NULL,
+#endif
     rsa_alt_decrypt_wrap,
     NULL,
 #if defined(MBEDTLS_RSA_C)
@@ -515,6 +707,10 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = {
 #endif
     rsa_alt_alloc_wrap,
     rsa_alt_free_wrap,
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    NULL,
+    NULL,
+#endif
     NULL,
 };
 
diff --git a/crypto/mbedtls/src/pkparse.c b/crypto/mbedtls/src/pkparse.c
index d6ac987..86d9fb0 100644
--- a/crypto/mbedtls/src/pkparse.c
+++ b/crypto/mbedtls/src/pkparse.c
@@ -1295,6 +1295,7 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk,
         return( 0 );
 
     mbedtls_pk_free( pk );
+    mbedtls_pk_init( pk );
 
     if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH )
     {
@@ -1306,39 +1307,42 @@ int mbedtls_pk_parse_key( mbedtls_pk_context *pk,
         return( 0 );
 
     mbedtls_pk_free( pk );
+    mbedtls_pk_init( pk );
 
 #if defined(MBEDTLS_RSA_C)
 
     pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA );
-    if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ||
-        ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ),
-                                        key, keylen ) ) != 0 )
-    {
-        mbedtls_pk_free( pk );
-    }
-    else
+    if( mbedtls_pk_setup( pk, pk_info ) == 0 &&
+        pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 )
     {
         return( 0 );
     }
 
+    mbedtls_pk_free( pk );
+    mbedtls_pk_init( pk );
 #endif /* MBEDTLS_RSA_C */
 
 #if defined(MBEDTLS_ECP_C)
-
     pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );
-    if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ||
-        ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ),
-                                       key, keylen ) ) != 0 )
-    {
-        mbedtls_pk_free( pk );
-    }
-    else
+    if( mbedtls_pk_setup( pk, pk_info ) == 0 &&
+        pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ),
+                               key, keylen ) == 0 )
     {
         return( 0 );
     }
-
+    mbedtls_pk_free( pk );
 #endif /* MBEDTLS_ECP_C */
 
+    /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't,
+     * it is ok to leave the PK context initialized but not
+     * freed: It is the caller's responsibility to call pk_init()
+     * before calling this function, and to call pk_free()
+     * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C
+     * isn't, this leads to mbedtls_pk_free() being called
+     * twice, once here and once by the caller, but this is
+     * also ok and in line with the mbedtls_pk_free() calls
+     * on failed PEM parsing attempts. */
+
     return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
 }
 
diff --git a/crypto/mbedtls/src/platform.c b/crypto/mbedtls/src/platform.c
index b24b2fa..73a6db9 100644
--- a/crypto/mbedtls/src/platform.c
+++ b/crypto/mbedtls/src/platform.c
@@ -30,7 +30,14 @@
 #include "mbedtls/platform.h"
 #include "mbedtls/platform_util.h"
 
-#if defined(MBEDTLS_PLATFORM_MEMORY)
+/* The compile time configuration of memory allocation via the macros
+ * MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO takes precedence over the runtime
+ * configuration via mbedtls_platform_set_calloc_free(). So, omit everything
+ * related to the latter if MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO are defined. */
+#if defined(MBEDTLS_PLATFORM_MEMORY) &&                 \
+    !( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&        \
+       defined(MBEDTLS_PLATFORM_FREE_MACRO) )
+
 #if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
 static void *platform_calloc_uninit( size_t n, size_t size )
 {
@@ -71,7 +78,9 @@ int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
     mbedtls_free_func = free_func;
     return( 0 );
 }
-#endif /* MBEDTLS_PLATFORM_MEMORY */
+#endif /* MBEDTLS_PLATFORM_MEMORY &&
+          !( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&
+             defined(MBEDTLS_PLATFORM_FREE_MACRO) ) */
 
 #if defined(_WIN32)
 #include <stdarg.h>
diff --git a/crypto/mbedtls/src/platform_util.c b/crypto/mbedtls/src/platform_util.c
index 1a57de9..ca5fe4f 100644
--- a/crypto/mbedtls/src/platform_util.c
+++ b/crypto/mbedtls/src/platform_util.c
@@ -20,6 +20,14 @@
  *  This file is part of Mbed TLS (https://tls.mbed.org)
  */
 
+/*
+ * Ensure gmtime_r is available even with -std=c99; must be defined before
+ * config.h, which pulls in glibc's features.h. Harmless on other platforms.
+ */
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/config.h"
 #else
@@ -27,6 +35,7 @@
 #endif
 
 #include "mbedtls/platform_util.h"
+#include "mbedtls/threading.h"
 
 #include <stddef.h>
 #include <string.h>
@@ -65,3 +74,62 @@ void mbedtls_platform_zeroize( void *buf, size_t len )
     memset_func( buf, 0, len );
 }
 #endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+#include <time.h>
+#if !defined(_WIN32) && (defined(unix) || \
+    defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
+    defined(__MACH__)))
+#include <unistd.h>
+#endif /* !_WIN32 && (unix || __unix || __unix__ ||
+        * (__APPLE__ && __MACH__)) */
+
+#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
+       ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
+         _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+/*
+ * This is a convenience shorthand macro to avoid checking the long
+ * preprocessor conditions above. Ideally, we could expose this macro in
+ * platform_util.h and simply use it in platform_util.c, threading.c and
+ * threading.h. However, this macro is not part of the Mbed TLS public API, so
+ * we keep it private by only defining it in this file
+ */
+#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
+#define PLATFORM_UTIL_USE_GMTIME
+#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
+
+#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
+             ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
+                _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+
+struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
+                                      struct tm *tm_buf )
+{
+#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
+    return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL );
+#elif !defined(PLATFORM_UTIL_USE_GMTIME)
+    return( gmtime_r( tt, tm_buf ) );
+#else
+    struct tm *lt;
+
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
+        return( NULL );
+#endif /* MBEDTLS_THREADING_C */
+
+    lt = gmtime( tt );
+
+    if( lt != NULL )
+    {
+        memcpy( tm_buf, lt, sizeof( struct tm ) );
+    }
+
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
+        return( NULL );
+#endif /* MBEDTLS_THREADING_C */
+
+    return( ( lt == NULL ) ? NULL : tm_buf );
+#endif /* _WIN32 && !EFIX64 && !EFI32 */
+}
+#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */
diff --git a/crypto/mbedtls/src/rsa.c b/crypto/mbedtls/src/rsa.c
index 88c1cf1..0a533d4 100644
--- a/crypto/mbedtls/src/rsa.c
+++ b/crypto/mbedtls/src/rsa.c
@@ -502,6 +502,7 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
 {
     int ret;
     mbedtls_mpi H, G, L;
+    int prime_quality = 0;
 
     if( f_rng == NULL || nbits < 128 || exponent < 3 )
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
@@ -509,6 +510,14 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
     if( nbits % 2 )
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
 
+    /*
+     * If the modulus is 1024 bit long or shorter, then the security strength of
+     * the RSA algorithm is less than or equal to 80 bits and therefore an error
+     * rate of 2^-80 is sufficient.
+     */
+    if( nbits > 1024 )
+        prime_quality = MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR;
+
     mbedtls_mpi_init( &H );
     mbedtls_mpi_init( &G );
     mbedtls_mpi_init( &L );
@@ -523,11 +532,11 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
 
     do
     {
-        MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0,
-                                                f_rng, p_rng ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1,
+                                                prime_quality, f_rng, p_rng ) );
 
-        MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0,
-                                                f_rng, p_rng ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1,
+                                                prime_quality, f_rng, p_rng ) );
 
         /* make sure the difference between p and q is not too small (FIPS 186-4 §B.3.3 step 5.4) */
         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &H, &ctx->P, &ctx->Q ) );
@@ -1378,6 +1387,97 @@ cleanup:
 #endif /* MBEDTLS_PKCS1_V21 */
 
 #if defined(MBEDTLS_PKCS1_V15)
+/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches.
+ *
+ * \param value     The value to analyze.
+ * \return          Zero if \p value is zero, otherwise all-bits-one.
+ */
+static unsigned all_or_nothing_int( unsigned value )
+{
+    /* MSVC has a warning about unary minus on unsigned, but this is
+     * well-defined and precisely what we want to do here */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+    return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) );
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+}
+
+/** Check whether a size is out of bounds, without branches.
+ *
+ * This is equivalent to `size > max`, but is likely to be compiled to
+ * to code using bitwise operation rather than a branch.
+ *
+ * \param size      Size to check.
+ * \param max       Maximum desired value for \p size.
+ * \return          \c 0 if `size <= max`.
+ * \return          \c 1 if `size > max`.
+ */
+static unsigned size_greater_than( size_t size, size_t max )
+{
+    /* Return the sign bit (1 for negative) of (max - size). */
+    return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) );
+}
+
+/** Choose between two integer values, without branches.
+ *
+ * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled
+ * to code using bitwise operation rather than a branch.
+ *
+ * \param cond      Condition to test.
+ * \param if1       Value to use if \p cond is nonzero.
+ * \param if0       Value to use if \p cond is zero.
+ * \return          \c if1 if \p cond is nonzero, otherwise \c if0.
+ */
+static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 )
+{
+    unsigned mask = all_or_nothing_int( cond );
+    return( ( mask & if1 ) | (~mask & if0 ) );
+}
+
+/** Shift some data towards the left inside a buffer without leaking
+ * the length of the data through side channels.
+ *
+ * `mem_move_to_left(start, total, offset)` is functionally equivalent to
+ * ```
+ * memmove(start, start + offset, total - offset);
+ * memset(start + offset, 0, total - offset);
+ * ```
+ * but it strives to use a memory access pattern (and thus total timing)
+ * that does not depend on \p offset. This timing independence comes at
+ * the expense of performance.
+ *
+ * \param start     Pointer to the start of the buffer.
+ * \param total     Total size of the buffer.
+ * \param offset    Offset from which to copy \p total - \p offset bytes.
+ */
+static void mem_move_to_left( void *start,
+                              size_t total,
+                              size_t offset )
+{
+    volatile unsigned char *buf = start;
+    size_t i, n;
+    if( total == 0 )
+        return;
+    for( i = 0; i < total; i++ )
+    {
+        unsigned no_op = size_greater_than( total - offset, i );
+        /* The first `total - offset` passes are a no-op. The last
+         * `offset` passes shift the data one byte to the left and
+         * zero out the last byte. */
+        for( n = 0; n < total - 1; n++ )
+        {
+            unsigned char current = buf[n];
+            unsigned char next = buf[n+1];
+            buf[n] = if_int( no_op, current, next );
+        }
+        buf[total-1] = if_int( no_op, buf[total-1], 0 );
+    }
+}
+
 /*
  * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
  */
@@ -1387,18 +1487,34 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
                                  int mode, size_t *olen,
                                  const unsigned char *input,
                                  unsigned char *output,
-                                 size_t output_max_len)
+                                 size_t output_max_len )
 {
     int ret;
-    size_t ilen, pad_count = 0, i;
-    unsigned char *p, bad, pad_done = 0;
+    size_t ilen = ctx->len;
+    size_t i;
+    size_t plaintext_max_size = ( output_max_len > ilen - 11 ?
+                                  ilen - 11 :
+                                  output_max_len );
     unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+    /* The following variables take sensitive values: their value must
+     * not leak into the observable behavior of the function other than
+     * the designated outputs (output, olen, return value). Otherwise
+     * this would open the execution of the function to
+     * side-channel-based variants of the Bleichenbacher padding oracle
+     * attack. Potential side channels include overall timing, memory
+     * access patterns (especially visible to an adversary who has access
+     * to a shared memory cache), and branches (especially visible to
+     * an adversary who has access to a shared code cache or to a shared
+     * branch predictor). */
+    size_t pad_count = 0;
+    unsigned bad = 0;
+    unsigned char pad_done = 0;
+    size_t plaintext_size = 0;
+    unsigned output_too_large;
 
     if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
 
-    ilen = ctx->len;
-
     if( ilen < 16 || ilen > sizeof( buf ) )
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
 
@@ -1409,63 +1525,109 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
     if( ret != 0 )
         goto cleanup;
 
-    p = buf;
-    bad = 0;
+    /* Check and get padding length in constant time and constant
+     * memory trace. The first byte must be 0. */
+    bad |= buf[0];
 
-    /*
-     * Check and get padding len in "constant-time"
-     */
-    bad |= *p++; /* First byte must be 0 */
-
-    /* This test does not depend on secret data */
     if( mode == MBEDTLS_RSA_PRIVATE )
     {
-        bad |= *p++ ^ MBEDTLS_RSA_CRYPT;
+        /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
+         * where PS must be at least 8 nonzero bytes. */
+        bad |= buf[1] ^ MBEDTLS_RSA_CRYPT;
 
-        /* Get padding len, but always read till end of buffer
-         * (minus one, for the 00 byte) */
-        for( i = 0; i < ilen - 3; i++ )
+        /* Read the whole buffer. Set pad_done to nonzero if we find
+         * the 0x00 byte and remember the padding length in pad_count. */
+        for( i = 2; i < ilen; i++ )
         {
-            pad_done  |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1;
+            pad_done  |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1;
             pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
         }
-
-        p += pad_count;
-        bad |= *p++; /* Must be zero */
     }
     else
     {
-        bad |= *p++ ^ MBEDTLS_RSA_SIGN;
+        /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00
+         * where PS must be at least 8 bytes with the value 0xFF. */
+        bad |= buf[1] ^ MBEDTLS_RSA_SIGN;
 
-        /* Get padding len, but always read till end of buffer
-         * (minus one, for the 00 byte) */
-        for( i = 0; i < ilen - 3; i++ )
+        /* Read the whole buffer. Set pad_done to nonzero if we find
+         * the 0x00 byte and remember the padding length in pad_count.
+         * If there's a non-0xff byte in the padding, the padding is bad. */
+        for( i = 2; i < ilen; i++ )
         {
-            pad_done |= ( p[i] != 0xFF );
-            pad_count += ( pad_done == 0 );
+            pad_done |= if_int( buf[i], 0, 1 );
+            pad_count += if_int( pad_done, 0, 1 );
+            bad |= if_int( pad_done, 0, buf[i] ^ 0xFF );
         }
-
-        p += pad_count;
-        bad |= *p++; /* Must be zero */
     }
 
-    bad |= ( pad_count < 8 );
-
-    if( bad )
-    {
-        ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
-        goto cleanup;
-    }
-
-    if( ilen - ( p - buf ) > output_max_len )
-    {
-        ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
-        goto cleanup;
-    }
-
-    *olen = ilen - (p - buf);
-    memcpy( output, p, *olen );
-    ret = 0;
+    /* If pad_done is still zero, there's no data, only unfinished padding. */
+    bad |= if_int( pad_done, 0, 1 );
+
+    /* There must be at least 8 bytes of padding. */
+    bad |= size_greater_than( 8, pad_count );
+
+    /* If the padding is valid, set plaintext_size to the number of
+     * remaining bytes after stripping the padding. If the padding
+     * is invalid, avoid leaking this fact through the size of the
+     * output: use the maximum message size that fits in the output
+     * buffer. Do it without branches to avoid leaking the padding
+     * validity through timing. RSA keys are small enough that all the
+     * size_t values involved fit in unsigned int. */
+    plaintext_size = if_int( bad,
+                             (unsigned) plaintext_max_size,
+                             (unsigned) ( ilen - pad_count - 3 ) );
+
+    /* Set output_too_large to 0 if the plaintext fits in the output
+     * buffer and to 1 otherwise. */
+    output_too_large = size_greater_than( plaintext_size,
+                                          plaintext_max_size );
+
+    /* Set ret without branches to avoid timing attacks. Return:
+     * - INVALID_PADDING if the padding is bad (bad != 0).
+     * - OUTPUT_TOO_LARGE if the padding is good but the decrypted
+     *   plaintext does not fit in the output buffer.
+     * - 0 if the padding is correct. */
+    ret = - (int) if_int( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING,
+                  if_int( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
+                          0 ) );
+
+    /* If the padding is bad or the plaintext is too large, zero the
+     * data that we're about to copy to the output buffer.
+     * We need to copy the same amount of data
+     * from the same buffer whether the padding is good or not to
+     * avoid leaking the padding validity through overall timing or
+     * through memory or cache access patterns. */
+    bad = all_or_nothing_int( bad | output_too_large );
+    for( i = 11; i < ilen; i++ )
+        buf[i] &= ~bad;
+
+    /* If the plaintext is too large, truncate it to the buffer size.
+     * Copy anyway to avoid revealing the length through timing, because
+     * revealing the length is as bad as revealing the padding validity
+     * for a Bleichenbacher attack. */
+    plaintext_size = if_int( output_too_large,
+                             (unsigned) plaintext_max_size,
+                             (unsigned) plaintext_size );
+
+    /* Move the plaintext to the leftmost position where it can start in
+     * the working buffer, i.e. make it start plaintext_max_size from
+     * the end of the buffer. Do this with a memory access trace that
+     * does not depend on the plaintext size. After this move, the
+     * starting location of the plaintext is no longer sensitive
+     * information. */
+    mem_move_to_left( buf + ilen - plaintext_max_size,
+                      plaintext_max_size,
+                      plaintext_max_size - plaintext_size );
+
+    /* Finally copy the decrypted plaintext plus trailing zeros
+     * into the output buffer. */
+    memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size );
+
+    /* Report the amount of data we copied to the output buffer. In case
+     * of errors (bad padding or output too large), the value of *olen
+     * when this function returns is not specified. Making it equivalent
+     * to the good case limits the risks of leaking the padding validity. */
+    *olen = plaintext_size;
 
 cleanup:
     mbedtls_platform_zeroize( buf, sizeof( buf ) );
@@ -1521,7 +1683,7 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
     size_t olen;
     unsigned char *p = sig;
     unsigned char salt[MBEDTLS_MD_MAX_SIZE];
-    unsigned int slen, hlen, offset = 0;
+    size_t slen, min_slen, hlen, offset = 0;
     int ret;
     size_t msb;
     const mbedtls_md_info_t *md_info;
@@ -1550,10 +1712,20 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
 
     hlen = mbedtls_md_get_size( md_info );
-    slen = hlen;
 
-    if( olen < hlen + slen + 2 )
+    /* Calculate the largest possible salt length. Normally this is the hash
+     * length, which is the maximum length the salt can have. If there is not
+     * enough room, use the maximum salt length that fits. The constraint is
+     * that the hash length plus the salt length plus 2 bytes must be at most
+     * the key length. This complies with FIPS 186-4 §5.5 (e) and RFC 8017
+     * (PKCS#1 v2.2) §9.1.1 step 3. */
+    min_slen = hlen - 2;
+    if( olen < hlen + min_slen + 2 )
         return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+    else if( olen >= hlen + hlen + 2 )
+        slen = hlen;
+    else
+        slen = olen - hlen - 2;
 
     memset( sig, 0, olen );
 
@@ -1563,7 +1735,7 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
 
     /* Note: EMSA-PSS encoding is over the length of N - 1 bits */
     msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
-    p += olen - hlen * 2 - 2;
+    p += olen - hlen - slen - 2;
     *p++ = 0x01;
     memcpy( p, salt, slen );
     p += slen;
diff --git a/crypto/mbedtls/src/rsa_internal.c b/crypto/mbedtls/src/rsa_internal.c
index 507009f..9a42d47 100644
--- a/crypto/mbedtls/src/rsa_internal.c
+++ b/crypto/mbedtls/src/rsa_internal.c
@@ -351,15 +351,20 @@ int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P,
      */
 
 #if defined(MBEDTLS_GENPRIME)
+    /*
+     * When generating keys, the strongest security we support aims for an error
+     * rate of at most 2^-100 and we are aiming for the same certainty here as
+     * well.
+     */
     if( f_rng != NULL && P != NULL &&
-        ( ret = mbedtls_mpi_is_prime( P, f_rng, p_rng ) ) != 0 )
+        ( ret = mbedtls_mpi_is_prime_ext( P, 50, f_rng, p_rng ) ) != 0 )
     {
         ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
         goto cleanup;
     }
 
     if( f_rng != NULL && Q != NULL &&
-        ( ret = mbedtls_mpi_is_prime( Q, f_rng, p_rng ) ) != 0 )
+        ( ret = mbedtls_mpi_is_prime_ext( Q, 50, f_rng, p_rng ) ) != 0 )
     {
         ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
         goto cleanup;
diff --git a/crypto/mbedtls/src/ssl_cli.c b/crypto/mbedtls/src/ssl_cli.c
index 8385720..ff576f3 100644
--- a/crypto/mbedtls/src/ssl_cli.c
+++ b/crypto/mbedtls/src/ssl_cli.c
@@ -1763,6 +1763,14 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) );
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA &&
+        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    {
+        ssl->handshake->ecrs_enabled = 1;
+    }
+#endif
+
     if( comp != MBEDTLS_SSL_COMPRESS_NULL
 #if defined(MBEDTLS_ZLIB_SUPPORT)
         && comp != MBEDTLS_SSL_COMPRESS_DEFLATE
@@ -2068,6 +2076,10 @@ static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl,
                                   (const unsigned char **) p, end ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_params" ), ret );
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+        if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+            ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
+#endif
         return( ret );
     }
 
@@ -2097,7 +2109,7 @@ static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl,
      *
      * opaque psk_identity_hint<0..2^16-1>;
      */
-    if( (*p) > end - 2 )
+    if( end - (*p) < 2 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message "
                                     "(psk_identity_hint length)" ) );
@@ -2106,7 +2118,7 @@ static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl,
     len = (*p)[0] << 8 | (*p)[1];
     *p += 2;
 
-    if( (*p) > end - len )
+    if( end - (*p) < (int) len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message "
                                     "(psk_identity_hint length)" ) );
@@ -2349,6 +2361,14 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled &&
+        ssl->handshake->ecrs_state == ssl_ecrs_ske_start_processing )
+    {
+        goto start_processing;
+    }
+#endif
+
     if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
@@ -2386,6 +2406,12 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled )
+        ssl->handshake->ecrs_state = ssl_ecrs_ske_start_processing;
+
+start_processing:
+#endif
     p   = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
     end = ssl->in_msg + ssl->in_hslen;
     MBEDTLS_SSL_DEBUG_BUF( 3,   "server key exchange", p, end - p );
@@ -2478,6 +2504,7 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
         mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
         unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
         size_t params_len = p - params;
+        void *rs_ctx = NULL;
 
         /*
          * Handle the digitally-signed structure
@@ -2600,12 +2627,25 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
             return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
         }
 
-        if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk,
-                               md_alg, hash, hashlen, p, sig_len ) ) != 0 )
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+        if( ssl->handshake->ecrs_enabled )
+            rs_ctx = &ssl->handshake->ecrs_ctx.pk;
+#endif
+
+        if( ( ret = mbedtls_pk_verify_restartable(
+                        &ssl->session_negotiate->peer_cert->pk,
+                        md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+            if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
+#endif
+                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                                MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+            if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+                ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
+#endif
             return( ret );
         }
     }
@@ -2903,6 +2943,16 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
          */
         i = 4;
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+        if( ssl->handshake->ecrs_enabled )
+        {
+            if( ssl->handshake->ecrs_state == ssl_ecrs_cke_ecdh_calc_secret )
+                goto ecdh_calc_secret;
+
+            mbedtls_ecdh_enable_restart( &ssl->handshake->ecdh_ctx );
+        }
+#endif
+
         ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx,
                                 &n,
                                 &ssl->out_msg[i], 1000,
@@ -2910,11 +2960,26 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret );
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+            if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+                ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
+#endif
             return( ret );
         }
 
         MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q );
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+        if( ssl->handshake->ecrs_enabled )
+        {
+            ssl->handshake->ecrs_n = n;
+            ssl->handshake->ecrs_state = ssl_ecrs_cke_ecdh_calc_secret;
+        }
+
+ecdh_calc_secret:
+        if( ssl->handshake->ecrs_enabled )
+            n = ssl->handshake->ecrs_n;
+#endif
         if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx,
                                       &ssl->handshake->pmslen,
                                        ssl->handshake->premaster,
@@ -2922,6 +2987,10 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
                                        ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+            if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+                ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
+#endif
             return( ret );
         }
 
@@ -3140,9 +3209,18 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
     unsigned char *hash_start = hash;
     mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
     unsigned int hashlen;
+    void *rs_ctx = NULL;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) );
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled &&
+        ssl->handshake->ecrs_state == ssl_ecrs_crt_vrfy_sign )
+    {
+        goto sign;
+    }
+#endif
+
     if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret );
@@ -3174,8 +3252,15 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
     }
 
     /*
-     * Make an RSA signature of the handshake digests
+     * Make a signature of the handshake digests
      */
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled )
+        ssl->handshake->ecrs_state = ssl_ecrs_crt_vrfy_sign;
+
+sign:
+#endif
+
     ssl->handshake->calc_verify( ssl, hash );
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
@@ -3252,11 +3337,21 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
         return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
 
-    if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash_start, hashlen,
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled )
+        rs_ctx = &ssl->handshake->ecrs_ctx.pk;
+#endif
+
+    if( ( ret = mbedtls_pk_sign_restartable( mbedtls_ssl_own_key( ssl ),
+                         md_alg, hash_start, hashlen,
                          ssl->out_msg + 6 + offset, &n,
-                         ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                         ssl->conf->f_rng, ssl->conf->p_rng, rs_ctx ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret );
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+        if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+            ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
+#endif
         return( ret );
     }
 
diff --git a/crypto/mbedtls/src/ssl_ticket.c b/crypto/mbedtls/src/ssl_ticket.c
index a2b3048..985b7cd 100644
--- a/crypto/mbedtls/src/ssl_ticket.c
+++ b/crypto/mbedtls/src/ssl_ticket.c
@@ -97,7 +97,7 @@ static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
         uint32_t current_time = (uint32_t) mbedtls_time( NULL );
         uint32_t key_time = ctx->keys[ctx->active].generation_time;
 
-        if( current_time > key_time &&
+        if( current_time >= key_time &&
             current_time - key_time < ctx->ticket_lifetime )
         {
             return( 0 );
diff --git a/crypto/mbedtls/src/ssl_tls.c b/crypto/mbedtls/src/ssl_tls.c
index 8bd74db..82e6525 100644
--- a/crypto/mbedtls/src/ssl_tls.c
+++ b/crypto/mbedtls/src/ssl_tls.c
@@ -151,7 +151,7 @@ static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl
 {
     int ret;
     size_t remaining, expansion;
-    size_t max_len = MBEDTLS_SSL_MAX_CONTENT_LEN;
+    size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
     const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl );
@@ -212,7 +212,10 @@ static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl )
      * delivered) of any compliant IPv4 (and IPv6) network, and should work
      * on most non-IP stacks too. */
     if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min )
+    {
         ssl->handshake->mtu = 508;
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "mtu autoreduction to %d bytes", ssl->handshake->mtu ) );
+    }
 
     new_timeout = 2 * ssl->handshake->retransmit_timeout;
 
@@ -2304,13 +2307,13 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
             correct = 0;
         }
         auth_done++;
-
-        /*
-         * Finally check the correct flag
-         */
-        if( correct == 0 )
-            return( MBEDTLS_ERR_SSL_INVALID_MAC );
     }
+
+    /*
+     * Finally check the correct flag
+     */
+    if( correct == 0 )
+        return( MBEDTLS_ERR_SSL_INVALID_MAC );
 #endif /* SSL_SOME_MODES_USE_MAC */
 
     /* Make extra sure authentication was performed, exactly once */
@@ -5429,60 +5432,16 @@ write_msg:
     return( ret );
 }
 
-int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
+/*
+ * Once the certificate message is read, parse it into a cert chain and
+ * perform basic checks, but leave actual verification to the caller
+ */
+static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
 {
-    int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+    int ret;
     size_t i, n;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
-    int authmode = ssl->conf->authmode;
     uint8_t alert;
 
-    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
-
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
-    }
-
-#if defined(MBEDTLS_SSL_SRV_C)
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
-    }
-
-#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-    if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET )
-        authmode = ssl->handshake->sni_authmode;
-#endif
-
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
-        authmode == MBEDTLS_SSL_VERIFY_NONE )
-    {
-        ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
-    }
-#endif
-
-    if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
-    {
-        /* mbedtls_ssl_read_record may have sent an alert already. We
-           let it decide whether to alert. */
-        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
-        return( ret );
-    }
-
-    ssl->state++;
-
 #if defined(MBEDTLS_SSL_SRV_C)
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
     /*
@@ -5502,10 +5461,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
                one. The client should know what's going on, so we
                don't send an alert. */
             ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
-            if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
-                return( 0 );
-            else
-                return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
+            return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
         }
     }
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
@@ -5526,10 +5482,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
                one. The client should know what's going on, so we
                don't send an alert. */
             ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
-            if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
-                return( 0 );
-            else
-                return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
+            return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
         }
     }
 #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
@@ -5679,6 +5632,94 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
     }
 #endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
 
+    return( 0 );
+}
+
+int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
+{
+    int ret;
+    const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
+          ssl->transform_negotiate->ciphersuite_info;
+#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+    const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET
+                       ? ssl->handshake->sni_authmode
+                       : ssl->conf->authmode;
+#else
+    const int authmode = ssl->conf->authmode;
+#endif
+    void *rs_ctx = NULL;
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
+
+    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
+        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
+        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
+        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+#if defined(MBEDTLS_SSL_SRV_C)
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
+        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
+        ssl->state++;
+        return( 0 );
+    }
+
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
+        authmode == MBEDTLS_SSL_VERIFY_NONE )
+    {
+        ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
+
+        ssl->state++;
+        return( 0 );
+    }
+#endif
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled &&
+        ssl->handshake->ecrs_state == ssl_ecrs_crt_verify )
+    {
+        goto crt_verify;
+    }
+#endif
+
+    if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
+    {
+        /* mbedtls_ssl_read_record may have sent an alert already. We
+           let it decide whether to alert. */
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
+        return( ret );
+    }
+
+    if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 )
+    {
+#if defined(MBEDTLS_SSL_SRV_C)
+        if( ret == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE &&
+            authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
+        {
+            ret = 0;
+        }
+#endif
+
+        ssl->state++;
+        return( ret );
+    }
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ssl->handshake->ecrs_enabled)
+        ssl->handshake->ecrs_state = ssl_ecrs_crt_verify;
+
+crt_verify:
+    if( ssl->handshake->ecrs_enabled)
+        rs_ctx = &ssl->handshake->ecrs_ctx;
+#endif
+
     if( authmode != MBEDTLS_SSL_VERIFY_NONE )
     {
         mbedtls_x509_crt *ca_chain;
@@ -5700,19 +5741,24 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
         /*
          * Main check: verify certificate
          */
-        ret = mbedtls_x509_crt_verify_with_profile(
+        ret = mbedtls_x509_crt_verify_restartable(
                                 ssl->session_negotiate->peer_cert,
                                 ca_chain, ca_crl,
                                 ssl->conf->cert_profile,
                                 ssl->hostname,
                                &ssl->session_negotiate->verify_result,
-                                ssl->conf->f_vrfy, ssl->conf->p_vrfy );
+                                ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
 
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
         }
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+        if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+            return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
+#endif
+
         /*
          * Secondary checks: always done, but change 'ret' only if it was 0
          */
@@ -5765,6 +5811,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
 
         if( ret != 0 )
         {
+            uint8_t alert;
+
             /* The certificate may have been rejected for several reasons.
                Pick one and send the corresponding alert. Which alert to send
                may be a subject of debate in some cases. */
@@ -5807,6 +5855,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
 #endif /* MBEDTLS_DEBUG_C */
     }
 
+    ssl->state++;
+
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
 
     return( ret );
@@ -6584,6 +6634,10 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake )
 #endif
 #endif
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    mbedtls_x509_crt_restart_init( &handshake->ecrs_ctx );
+#endif
+
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
     handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET;
 #endif
@@ -7905,6 +7959,12 @@ size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl )
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl )
 {
+    /* Return unlimited mtu for client hello messages to avoid fragmentation. */
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
+        ( ssl->state == MBEDTLS_SSL_CLIENT_HELLO ||
+          ssl->state == MBEDTLS_SSL_SERVER_HELLO ) )
+        return ( 0 );
+
     if( ssl->handshake == NULL || ssl->handshake->mtu == 0 )
         return( ssl->mtu );
 
@@ -8741,6 +8801,7 @@ static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
     if( hs_buf->is_valid == 1 )
     {
         hs->buffering.total_bytes_buffered -= hs_buf->data_len;
+        mbedtls_platform_zeroize( hs_buf->data, hs_buf->data_len );
         mbedtls_free( hs_buf->data );
         memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
     }
@@ -8825,6 +8886,10 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl )
     }
 #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */
 
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx );
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     mbedtls_free( handshake->verify_cookie );
     ssl_flight_free( handshake->flight );
diff --git a/crypto/mbedtls/src/threading.c b/crypto/mbedtls/src/threading.c
index 7a32e67..7c90c7c 100644
--- a/crypto/mbedtls/src/threading.c
+++ b/crypto/mbedtls/src/threading.c
@@ -19,6 +19,14 @@
  *  This file is part of mbed TLS (https://tls.mbed.org)
  */
 
+/*
+ * Ensure gmtime_r is available even with -std=c99; must be defined before
+ * config.h, which pulls in glibc's features.h. Harmless on other platforms.
+ */
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/config.h"
 #else
@@ -29,6 +37,36 @@
 
 #include "mbedtls/threading.h"
 
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+
+#if !defined(_WIN32) && (defined(unix) || \
+    defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
+    defined(__MACH__)))
+#include <unistd.h>
+#endif /* !_WIN32 && (unix || __unix || __unix__ ||
+        * (__APPLE__ && __MACH__)) */
+
+#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
+       ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
+         _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+/*
+ * This is a convenience shorthand macro to avoid checking the long
+ * preprocessor conditions above. Ideally, we could expose this macro in
+ * platform_util.h and simply use it in platform_util.c, threading.c and
+ * threading.h. However, this macro is not part of the Mbed TLS public API, so
+ * we keep it private by only defining it in this file
+ */
+
+#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
+#define THREADING_USE_GMTIME
+#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
+
+#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
+             ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
+                _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+
+#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
+
 #if defined(MBEDTLS_THREADING_PTHREAD)
 static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex )
 {
@@ -114,6 +152,9 @@ void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t *
 #if defined(MBEDTLS_FS_IO)
     mbedtls_mutex_init( &mbedtls_threading_readdir_mutex );
 #endif
+#if defined(THREADING_USE_GMTIME)
+    mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex );
+#endif
 }
 
 /*
@@ -124,6 +165,9 @@ void mbedtls_threading_free_alt( void )
 #if defined(MBEDTLS_FS_IO)
     mbedtls_mutex_free( &mbedtls_threading_readdir_mutex );
 #endif
+#if defined(THREADING_USE_GMTIME)
+    mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex );
+#endif
 }
 #endif /* MBEDTLS_THREADING_ALT */
 
@@ -136,5 +180,8 @@ void mbedtls_threading_free_alt( void )
 #if defined(MBEDTLS_FS_IO)
 mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT;
 #endif
+#if defined(THREADING_USE_GMTIME)
+mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT;
+#endif
 
 #endif /* MBEDTLS_THREADING_C */
diff --git a/crypto/mbedtls/src/timing.c b/crypto/mbedtls/src/timing.c
index 3e8139f..413d133 100644
--- a/crypto/mbedtls/src/timing.c
+++ b/crypto/mbedtls/src/timing.c
@@ -52,6 +52,7 @@
 
 #include <windows.h>
 #include <winbase.h>
+#include <process.h>
 
 struct _hr_time
 {
@@ -267,18 +268,17 @@ unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int
 /* It's OK to use a global because alarm() is supposed to be global anyway */
 static DWORD alarmMs;
 
-static DWORD WINAPI TimerProc( LPVOID TimerContext )
+static void TimerProc( void *TimerContext )
 {
-    ((void) TimerContext);
+    (void) TimerContext;
     Sleep( alarmMs );
     mbedtls_timing_alarmed = 1;
-    return( TRUE );
+    /* _endthread will be called implicitly on return
+     * That ensures execution of thread funcition's epilogue */
 }
 
 void mbedtls_set_alarm( int seconds )
 {
-    DWORD ThreadId;
-
     if( seconds == 0 )
     {
         /* No need to create a thread for this simple case.
@@ -289,7 +289,7 @@ void mbedtls_set_alarm( int seconds )
 
     mbedtls_timing_alarmed = 0;
     alarmMs = seconds * 1000;
-    CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) );
+    (void) _beginthread( TimerProc, 0, NULL );
 }
 
 #else /* _WIN32 && !EFIX64 && !EFI32 */
diff --git a/crypto/mbedtls/src/version_features.c b/crypto/mbedtls/src/version_features.c
index 777b603..f1798a7 100644
--- a/crypto/mbedtls/src/version_features.c
+++ b/crypto/mbedtls/src/version_features.c
@@ -339,6 +339,9 @@ static const char *features[] = {
 #if defined(MBEDTLS_ECP_NIST_OPTIM)
     "MBEDTLS_ECP_NIST_OPTIM",
 #endif /* MBEDTLS_ECP_NIST_OPTIM */
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    "MBEDTLS_ECP_RESTARTABLE",
+#endif /* MBEDTLS_ECP_RESTARTABLE */
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
     "MBEDTLS_ECDSA_DETERMINISTIC",
 #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
diff --git a/crypto/mbedtls/src/x509.c b/crypto/mbedtls/src/x509.c
index 2e6795f..52b5b64 100644
--- a/crypto/mbedtls/src/x509.c
+++ b/crypto/mbedtls/src/x509.c
@@ -29,10 +29,6 @@
  *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
  */
 
-/* Ensure gmtime_r is available even with -std=c99; must be included before
- * config.h, which pulls in glibc's features.h. Harmless on other platforms. */
-#define _POSIX_C_SOURCE 200112L
-
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/config.h"
 #else
@@ -67,6 +63,7 @@
 #include "mbedtls/platform_time.h"
 #endif
 #if defined(MBEDTLS_HAVE_TIME_DATE)
+#include "mbedtls/platform_util.h"
 #include <time.h>
 #endif
 
@@ -901,11 +898,7 @@ static int x509_get_current_time( mbedtls_x509_time *now )
     int ret = 0;
 
     tt = mbedtls_time( NULL );
-#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
-    lt = gmtime_s( &tm_buf, &tt ) == 0 ? &tm_buf : NULL;
-#else
-    lt = gmtime_r( &tt, &tm_buf );
-#endif
+    lt = mbedtls_platform_gmtime_r( &tt, &tm_buf );
 
     if( lt == NULL )
         ret = -1;
diff --git a/crypto/mbedtls/src/x509_create.c b/crypto/mbedtls/src/x509_create.c
index df20ec8..546e8fa 100644
--- a/crypto/mbedtls/src/x509_create.c
+++ b/crypto/mbedtls/src/x509_create.c
@@ -33,48 +33,84 @@
 
 #include <string.h>
 
+/* Structure linking OIDs for X.509 DN AttributeTypes to their
+ * string representations and default string encodings used by Mbed TLS. */
 typedef struct {
-    const char *name;
-    size_t name_len;
-    const char*oid;
+   const char *name; /* String representation of AttributeType, e.g.
+                      * "CN" or "emailAddress". */
+   size_t name_len;  /* Length of 'name', without trailing 0 byte. */
+   const char *oid;  /* String representation of OID of AttributeType,
+                      * as per RFC 5280, Appendix A.1. */
+   int default_tag;  /* The default character encoding used for the
+                      * given attribute type, e.g.
+                      * MBEDTLS_ASN1_UTF8_STRING for UTF-8. */
 } x509_attr_descriptor_t;
 
 #define ADD_STRLEN( s )     s, sizeof( s ) - 1
 
+/* X.509 DN attributes from RFC 5280, Appendix A.1. */
 static const x509_attr_descriptor_t x509_attrs[] =
 {
-    { ADD_STRLEN( "CN" ),                       MBEDTLS_OID_AT_CN },
-    { ADD_STRLEN( "commonName" ),               MBEDTLS_OID_AT_CN },
-    { ADD_STRLEN( "C" ),                        MBEDTLS_OID_AT_COUNTRY },
-    { ADD_STRLEN( "countryName" ),              MBEDTLS_OID_AT_COUNTRY },
-    { ADD_STRLEN( "O" ),                        MBEDTLS_OID_AT_ORGANIZATION },
-    { ADD_STRLEN( "organizationName" ),         MBEDTLS_OID_AT_ORGANIZATION },
-    { ADD_STRLEN( "L" ),                        MBEDTLS_OID_AT_LOCALITY },
-    { ADD_STRLEN( "locality" ),                 MBEDTLS_OID_AT_LOCALITY },
-    { ADD_STRLEN( "R" ),                        MBEDTLS_OID_PKCS9_EMAIL },
-    { ADD_STRLEN( "OU" ),                       MBEDTLS_OID_AT_ORG_UNIT },
-    { ADD_STRLEN( "organizationalUnitName" ),   MBEDTLS_OID_AT_ORG_UNIT },
-    { ADD_STRLEN( "ST" ),                       MBEDTLS_OID_AT_STATE },
-    { ADD_STRLEN( "stateOrProvinceName" ),      MBEDTLS_OID_AT_STATE },
-    { ADD_STRLEN( "emailAddress" ),             MBEDTLS_OID_PKCS9_EMAIL },
-    { ADD_STRLEN( "serialNumber" ),             MBEDTLS_OID_AT_SERIAL_NUMBER },
-    { ADD_STRLEN( "postalAddress" ),            MBEDTLS_OID_AT_POSTAL_ADDRESS },
-    { ADD_STRLEN( "postalCode" ),               MBEDTLS_OID_AT_POSTAL_CODE },
-    { ADD_STRLEN( "dnQualifier" ),              MBEDTLS_OID_AT_DN_QUALIFIER },
-    { ADD_STRLEN( "title" ),                    MBEDTLS_OID_AT_TITLE },
-    { ADD_STRLEN( "surName" ),                  MBEDTLS_OID_AT_SUR_NAME },
-    { ADD_STRLEN( "SN" ),                       MBEDTLS_OID_AT_SUR_NAME },
-    { ADD_STRLEN( "givenName" ),                MBEDTLS_OID_AT_GIVEN_NAME },
-    { ADD_STRLEN( "GN" ),                       MBEDTLS_OID_AT_GIVEN_NAME },
-    { ADD_STRLEN( "initials" ),                 MBEDTLS_OID_AT_INITIALS },
-    { ADD_STRLEN( "pseudonym" ),                MBEDTLS_OID_AT_PSEUDONYM },
-    { ADD_STRLEN( "generationQualifier" ),      MBEDTLS_OID_AT_GENERATION_QUALIFIER },
-    { ADD_STRLEN( "domainComponent" ),          MBEDTLS_OID_DOMAIN_COMPONENT },
-    { ADD_STRLEN( "DC" ),                       MBEDTLS_OID_DOMAIN_COMPONENT },
-    { NULL, 0, NULL }
+    { ADD_STRLEN( "CN" ),
+      MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "commonName" ),
+      MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "C" ),
+      MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING },
+    { ADD_STRLEN( "countryName" ),
+      MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING },
+    { ADD_STRLEN( "O" ),
+      MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "organizationName" ),
+      MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "L" ),
+      MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "locality" ),
+      MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "R" ),
+      MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING },
+    { ADD_STRLEN( "OU" ),
+      MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "organizationalUnitName" ),
+      MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "ST" ),
+      MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "stateOrProvinceName" ),
+      MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "emailAddress" ),
+      MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING },
+    { ADD_STRLEN( "serialNumber" ),
+      MBEDTLS_OID_AT_SERIAL_NUMBER, MBEDTLS_ASN1_PRINTABLE_STRING },
+    { ADD_STRLEN( "postalAddress" ),
+      MBEDTLS_OID_AT_POSTAL_ADDRESS, MBEDTLS_ASN1_PRINTABLE_STRING },
+    { ADD_STRLEN( "postalCode" ),
+      MBEDTLS_OID_AT_POSTAL_CODE, MBEDTLS_ASN1_PRINTABLE_STRING },
+    { ADD_STRLEN( "dnQualifier" ),
+      MBEDTLS_OID_AT_DN_QUALIFIER, MBEDTLS_ASN1_PRINTABLE_STRING },
+    { ADD_STRLEN( "title" ),
+      MBEDTLS_OID_AT_TITLE, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "surName" ),
+      MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "SN" ),
+      MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "givenName" ),
+      MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "GN" ),
+      MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "initials" ),
+      MBEDTLS_OID_AT_INITIALS, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "pseudonym" ),
+      MBEDTLS_OID_AT_PSEUDONYM, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "generationQualifier" ),
+      MBEDTLS_OID_AT_GENERATION_QUALIFIER, MBEDTLS_ASN1_UTF8_STRING },
+    { ADD_STRLEN( "domainComponent" ),
+      MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING },
+    { ADD_STRLEN( "DC" ),
+      MBEDTLS_OID_DOMAIN_COMPONENT,   MBEDTLS_ASN1_IA5_STRING },
+    { NULL, 0, NULL, MBEDTLS_ASN1_NULL }
 };
 
-static const char *x509_at_oid_from_name( const char *name, size_t name_len )
+static const x509_attr_descriptor_t *x509_attr_descr_from_name( const char *name, size_t name_len )
 {
     const x509_attr_descriptor_t *cur;
 
@@ -83,7 +119,10 @@ static const char *x509_at_oid_from_name( const char *name, size_t name_len )
             strncmp( cur->name, name, name_len ) == 0 )
             break;
 
-    return( cur->oid );
+    if ( cur->name == NULL )
+        return( NULL );
+
+    return( cur );
 }
 
 int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name )
@@ -92,6 +131,7 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na
     const char *s = name, *c = s;
     const char *end = s + strlen( s );
     const char *oid = NULL;
+    const x509_attr_descriptor_t* attr_descr = NULL;
     int in_tag = 1;
     char data[MBEDTLS_X509_MAX_DN_NAME_SIZE];
     char *d = data;
@@ -103,12 +143,13 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na
     {
         if( in_tag && *c == '=' )
         {
-            if( ( oid = x509_at_oid_from_name( s, c - s ) ) == NULL )
+            if( ( attr_descr = x509_attr_descr_from_name( s, c - s ) ) == NULL )
             {
                 ret = MBEDTLS_ERR_X509_UNKNOWN_OID;
                 goto exit;
             }
 
+            oid = attr_descr->oid;
             s = c + 1;
             in_tag = 0;
             d = data;
@@ -127,13 +168,19 @@ int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *na
         }
         else if( !in_tag && ( *c == ',' || c == end ) )
         {
-            if( mbedtls_asn1_store_named_data( head, oid, strlen( oid ),
-                                       (unsigned char *) data,
-                                       d - data ) == NULL )
+            mbedtls_asn1_named_data* cur =
+                mbedtls_asn1_store_named_data( head, oid, strlen( oid ),
+                                               (unsigned char *) data,
+                                               d - data );
+
+            if(cur == NULL )
             {
                 return( MBEDTLS_ERR_X509_ALLOC_FAILED );
             }
 
+            // set tagType
+            cur->val.tag = attr_descr->default_tag;
+
             while( c < end && *(c + 1) == ' ' )
                 c++;
 
@@ -192,46 +239,40 @@ int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid,
  *
  *  AttributeValue ::= ANY DEFINED BY AttributeType
  */
-static int x509_write_name( unsigned char **p, unsigned char *start,
-                            const char *oid, size_t oid_len,
-                            const unsigned char *name, size_t name_len )
+static int x509_write_name( unsigned char **p, unsigned char *start, mbedtls_asn1_named_data* cur_name)
 {
     int ret;
     size_t len = 0;
-
-    // Write PrintableString for all except MBEDTLS_OID_PKCS9_EMAIL
-    //
-    if( MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_EMAIL ) == oid_len &&
-        memcmp( oid, MBEDTLS_OID_PKCS9_EMAIL, oid_len ) == 0 )
-    {
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_ia5_string( p, start,
-                                                  (const char *) name,
-                                                  name_len ) );
-    }
-    else
-    {
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_printable_string( p, start,
-                                                        (const char *) name,
-                                                        name_len ) );
-    }
-
+    const char *oid             = (const char*)cur_name->oid.p;
+    size_t oid_len              = cur_name->oid.len;
+    const unsigned char *name   = cur_name->val.p;
+    size_t name_len             = cur_name->val.len;
+
+    // Write correct string tag and value
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tagged_string( p, start,
+                                                       cur_name->val.tag,
+                                                       (const char *) name,
+                                                       name_len ) );
     // Write OID
     //
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid,
+                                                       oid_len ) );
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED |
-                                                 MBEDTLS_ASN1_SEQUENCE ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
+                                                    MBEDTLS_ASN1_CONSTRUCTED |
+                                                    MBEDTLS_ASN1_SEQUENCE ) );
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED |
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
+                                                 MBEDTLS_ASN1_CONSTRUCTED |
                                                  MBEDTLS_ASN1_SET ) );
 
     return( (int) len );
 }
 
 int mbedtls_x509_write_names( unsigned char **p, unsigned char *start,
-                      mbedtls_asn1_named_data *first )
+                              mbedtls_asn1_named_data *first )
 {
     int ret;
     size_t len = 0;
@@ -239,9 +280,7 @@ int mbedtls_x509_write_names( unsigned char **p, unsigned char *start,
 
     while( cur != NULL )
     {
-        MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p,
-                                            cur->oid.len,
-                                            cur->val.p, cur->val.len ) );
+        MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, cur ) );
         cur = cur->next;
     }
 
diff --git a/crypto/mbedtls/src/x509_crt.c b/crypto/mbedtls/src/x509_crt.c
index a390f81..3e505e2 100644
--- a/crypto/mbedtls/src/x509_crt.c
+++ b/crypto/mbedtls/src/x509_crt.c
@@ -43,7 +43,6 @@
 #include "mbedtls/oid.h"
 #include "mbedtls/platform_util.h"
 
-#include <stdio.h>
 #include <string.h>
 
 #if defined(MBEDTLS_PEM_PARSE_C)
@@ -53,6 +52,7 @@
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
+#include <stdio.h>
 #include <stdlib.h>
 #define mbedtls_free       free
 #define mbedtls_calloc    calloc
@@ -228,6 +228,153 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile,
 }
 
 /*
+ * Like memcmp, but case-insensitive and always returns -1 if different
+ */
+static int x509_memcasecmp( const void *s1, const void *s2, size_t len )
+{
+    size_t i;
+    unsigned char diff;
+    const unsigned char *n1 = s1, *n2 = s2;
+
+    for( i = 0; i < len; i++ )
+    {
+        diff = n1[i] ^ n2[i];
+
+        if( diff == 0 )
+            continue;
+
+        if( diff == 32 &&
+            ( ( n1[i] >= 'a' && n1[i] <= 'z' ) ||
+              ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) )
+        {
+            continue;
+        }
+
+        return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Return 0 if name matches wildcard, -1 otherwise
+ */
+static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name )
+{
+    size_t i;
+    size_t cn_idx = 0, cn_len = strlen( cn );
+
+    /* We can't have a match if there is no wildcard to match */
+    if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
+        return( -1 );
+
+    for( i = 0; i < cn_len; ++i )
+    {
+        if( cn[i] == '.' )
+        {
+            cn_idx = i;
+            break;
+        }
+    }
+
+    if( cn_idx == 0 )
+        return( -1 );
+
+    if( cn_len - cn_idx == name->len - 1 &&
+        x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
+    {
+        return( 0 );
+    }
+
+    return( -1 );
+}
+
+/*
+ * Compare two X.509 strings, case-insensitive, and allowing for some encoding
+ * variations (but not all).
+ *
+ * Return 0 if equal, -1 otherwise.
+ */
+static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b )
+{
+    if( a->tag == b->tag &&
+        a->len == b->len &&
+        memcmp( a->p, b->p, b->len ) == 0 )
+    {
+        return( 0 );
+    }
+
+    if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
+        ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
+        a->len == b->len &&
+        x509_memcasecmp( a->p, b->p, b->len ) == 0 )
+    {
+        return( 0 );
+    }
+
+    return( -1 );
+}
+
+/*
+ * Compare two X.509 Names (aka rdnSequence).
+ *
+ * See RFC 5280 section 7.1, though we don't implement the whole algorithm:
+ * we sometimes return unequal when the full algorithm would return equal,
+ * but never the other way. (In particular, we don't do Unicode normalisation
+ * or space folding.)
+ *
+ * Return 0 if equal, -1 otherwise.
+ */
+static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b )
+{
+    /* Avoid recursion, it might not be optimised by the compiler */
+    while( a != NULL || b != NULL )
+    {
+        if( a == NULL || b == NULL )
+            return( -1 );
+
+        /* type */
+        if( a->oid.tag != b->oid.tag ||
+            a->oid.len != b->oid.len ||
+            memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 )
+        {
+            return( -1 );
+        }
+
+        /* value */
+        if( x509_string_cmp( &a->val, &b->val ) != 0 )
+            return( -1 );
+
+        /* structure of the list of sets */
+        if( a->next_merged != b->next_merged )
+            return( -1 );
+
+        a = a->next;
+        b = b->next;
+    }
+
+    /* a == NULL == b */
+    return( 0 );
+}
+
+/*
+ * Reset (init or clear) a verify_chain
+ */
+static void x509_crt_verify_chain_reset(
+    mbedtls_x509_crt_verify_chain *ver_chain )
+{
+    size_t i;
+
+    for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ )
+    {
+        ver_chain->items[i].crt = NULL;
+        ver_chain->items[i].flags = -1;
+    }
+
+    ver_chain->len = 0;
+}
+
+/*
  *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
  */
 static int x509_get_version( unsigned char **p,
@@ -1667,9 +1814,7 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
     while( crl_list != NULL )
     {
         if( crl_list->version == 0 ||
-            crl_list->issuer_raw.len != ca->subject_raw.len ||
-            memcmp( crl_list->issuer_raw.p, ca->subject_raw.p,
-                    crl_list->issuer_raw.len ) != 0 )
+            x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 )
         {
             crl_list = crl_list->next;
             continue;
@@ -1679,7 +1824,8 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
          * Check if the CA is configured to sign CRLs
          */
 #if defined(MBEDTLS_X509_CHECK_KEY_USAGE)
-        if( mbedtls_x509_crt_check_key_usage( ca, MBEDTLS_X509_KU_CRL_SIGN ) != 0 )
+        if( mbedtls_x509_crt_check_key_usage( ca,
+                                              MBEDTLS_X509_KU_CRL_SIGN ) != 0 )
         {
             flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED;
             break;
@@ -1740,140 +1886,11 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
 #endif /* MBEDTLS_X509_CRL_PARSE_C */
 
 /*
- * Like memcmp, but case-insensitive and always returns -1 if different
- */
-static int x509_memcasecmp( const void *s1, const void *s2, size_t len )
-{
-    size_t i;
-    unsigned char diff;
-    const unsigned char *n1 = s1, *n2 = s2;
-
-    for( i = 0; i < len; i++ )
-    {
-        diff = n1[i] ^ n2[i];
-
-        if( diff == 0 )
-            continue;
-
-        if( diff == 32 &&
-            ( ( n1[i] >= 'a' && n1[i] <= 'z' ) ||
-              ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) )
-        {
-            continue;
-        }
-
-        return( -1 );
-    }
-
-    return( 0 );
-}
-
-/*
- * Return 0 if name matches wildcard, -1 otherwise
- */
-static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name )
-{
-    size_t i;
-    size_t cn_idx = 0, cn_len = strlen( cn );
-
-    /* We can't have a match if there is no wildcard to match */
-    if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
-        return( -1 );
-
-    for( i = 0; i < cn_len; ++i )
-    {
-        if( cn[i] == '.' )
-        {
-            cn_idx = i;
-            break;
-        }
-    }
-
-    if( cn_idx == 0 )
-        return( -1 );
-
-    if( cn_len - cn_idx == name->len - 1 &&
-        x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
-    {
-        return( 0 );
-    }
-
-    return( -1 );
-}
-
-/*
- * Compare two X.509 strings, case-insensitive, and allowing for some encoding
- * variations (but not all).
- *
- * Return 0 if equal, -1 otherwise.
- */
-static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b )
-{
-    if( a->tag == b->tag &&
-        a->len == b->len &&
-        memcmp( a->p, b->p, b->len ) == 0 )
-    {
-        return( 0 );
-    }
-
-    if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
-        ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) &&
-        a->len == b->len &&
-        x509_memcasecmp( a->p, b->p, b->len ) == 0 )
-    {
-        return( 0 );
-    }
-
-    return( -1 );
-}
-
-/*
- * Compare two X.509 Names (aka rdnSequence).
- *
- * See RFC 5280 section 7.1, though we don't implement the whole algorithm:
- * we sometimes return unequal when the full algorithm would return equal,
- * but never the other way. (In particular, we don't do Unicode normalisation
- * or space folding.)
- *
- * Return 0 if equal, -1 otherwise.
- */
-static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b )
-{
-    /* Avoid recursion, it might not be optimised by the compiler */
-    while( a != NULL || b != NULL )
-    {
-        if( a == NULL || b == NULL )
-            return( -1 );
-
-        /* type */
-        if( a->oid.tag != b->oid.tag ||
-            a->oid.len != b->oid.len ||
-            memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 )
-        {
-            return( -1 );
-        }
-
-        /* value */
-        if( x509_string_cmp( &a->val, &b->val ) != 0 )
-            return( -1 );
-
-        /* structure of the list of sets */
-        if( a->next_merged != b->next_merged )
-            return( -1 );
-
-        a = a->next;
-        b = b->next;
-    }
-
-    /* a == NULL == b */
-    return( 0 );
-}
-
-/*
  * Check the signature of a certificate by its parent
  */
 static int x509_crt_check_signature( const mbedtls_x509_crt *child,
-                                     mbedtls_x509_crt *parent )
+                                     mbedtls_x509_crt *parent,
+                                     mbedtls_x509_crt_restart_ctx *rs_ctx )
 {
     const mbedtls_md_info_t *md_info;
     unsigned char hash[MBEDTLS_MD_MAX_SIZE];
@@ -1885,14 +1902,24 @@ static int x509_crt_check_signature( const mbedtls_x509_crt *child,
         return( -1 );
     }
 
-    if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk,
-                child->sig_md, hash, mbedtls_md_get_size( md_info ),
-                child->sig.p, child->sig.len ) != 0 )
-    {
+    /* Skip expensive computation on obvious mismatch */
+    if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) )
         return( -1 );
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA )
+    {
+        return( mbedtls_pk_verify_restartable( &parent->pk,
+                    child->sig_md, hash, mbedtls_md_get_size( md_info ),
+                    child->sig.p, child->sig.len, &rs_ctx->pk ) );
     }
+#else
+    (void) rs_ctx;
+#endif
 
-    return( 0 );
+    return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk,
+                child->sig_md, hash, mbedtls_md_get_size( md_info ),
+                child->sig.p, child->sig.len ) );
 }
 
 /*
@@ -1939,6 +1966,7 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child,
  *  1. subject name matches child's issuer
  *  2. if necessary, the CA bit is set and key usage allows signing certs
  *  3. for trusted roots, the signature is correct
+ *     (for intermediates, the signature is checked and the result reported)
  *  4. pathlen constraints are satisfied
  *
  * If there's a suitable candidate which is also time-valid, return the first
@@ -1961,23 +1989,54 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child,
  * Arguments:
  *  - [in] child: certificate for which we're looking for a parent
  *  - [in] candidates: chained list of potential parents
+ *  - [out] r_parent: parent found (or NULL)
+ *  - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0
  *  - [in] top: 1 if candidates consists of trusted roots, ie we're at the top
  *         of the chain, 0 otherwise
  *  - [in] path_cnt: number of intermediates seen so far
  *  - [in] self_cnt: number of self-signed intermediates seen so far
  *         (will never be greater than path_cnt)
+ *  - [in-out] rs_ctx: context for restarting operations
  *
  * Return value:
- *  - the first suitable parent found (see above regarding time-validity)
- *  - NULL if no suitable parent was found
+ *  - 0 on success
+ *  - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
  */
-static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
-                                                  mbedtls_x509_crt *candidates,
-                                                  int top,
-                                                  size_t path_cnt,
-                                                  size_t self_cnt )
+static int x509_crt_find_parent_in(
+                        mbedtls_x509_crt *child,
+                        mbedtls_x509_crt *candidates,
+                        mbedtls_x509_crt **r_parent,
+                        int *r_signature_is_good,
+                        int top,
+                        unsigned path_cnt,
+                        unsigned self_cnt,
+                        mbedtls_x509_crt_restart_ctx *rs_ctx )
 {
-    mbedtls_x509_crt *parent, *badtime_parent = NULL;
+    int ret;
+    mbedtls_x509_crt *parent, *fallback_parent;
+    int signature_is_good, fallback_signature_is_good;
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /* did we have something in progress? */
+    if( rs_ctx != NULL && rs_ctx->parent != NULL )
+    {
+        /* restore saved state */
+        parent = rs_ctx->parent;
+        fallback_parent = rs_ctx->fallback_parent;
+        fallback_signature_is_good = rs_ctx->fallback_signature_is_good;
+
+        /* clear saved state */
+        rs_ctx->parent = NULL;
+        rs_ctx->fallback_parent = NULL;
+        rs_ctx->fallback_signature_is_good = 0;
+
+        /* resume where we left */
+        goto check_signature;
+    }
+#endif
+
+    fallback_parent = NULL;
+    fallback_signature_is_good = 0;
 
     for( parent = candidates; parent != NULL; parent = parent->next )
     {
@@ -1993,17 +2052,38 @@ static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
         }
 
         /* Signature */
-        if( top && x509_crt_check_signature( child, parent ) != 0 )
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+check_signature:
+#endif
+        ret = x509_crt_check_signature( child, parent, rs_ctx );
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+        if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
         {
-            continue;
+            /* save state */
+            rs_ctx->parent = parent;
+            rs_ctx->fallback_parent = fallback_parent;
+            rs_ctx->fallback_signature_is_good = fallback_signature_is_good;
+
+            return( ret );
         }
+#else
+        (void) ret;
+#endif
+
+        signature_is_good = ret == 0;
+        if( top && ! signature_is_good )
+            continue;
 
         /* optional time check */
         if( mbedtls_x509_time_is_past( &parent->valid_to ) ||
             mbedtls_x509_time_is_future( &parent->valid_from ) )
         {
-            if( badtime_parent == NULL )
-                badtime_parent = parent;
+            if( fallback_parent == NULL )
+            {
+                fallback_parent = parent;
+                fallback_signature_is_good = signature_is_good;
+            }
 
             continue;
         }
@@ -2011,10 +2091,18 @@ static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
         break;
     }
 
-    if( parent == NULL )
-        parent = badtime_parent;
+    if( parent != NULL )
+    {
+        *r_parent = parent;
+        *r_signature_is_good = signature_is_good;
+    }
+    else
+    {
+        *r_parent = fallback_parent;
+        *r_signature_is_good = fallback_signature_is_good;
+    }
 
-    return( parent );
+    return( 0 );
 }
 
 /*
@@ -2026,34 +2114,78 @@ static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
  * Arguments:
  *  - [in] child: certificate for which we're looking for a parent, followed
  *         by a chain of possible intermediates
- *  - [in] trust_ca: locally trusted CAs
- *  - [out] 1 if parent was found in trust_ca, 0 if found in provided chain
- *  - [in] path_cnt: number of intermediates seen so far
- *  - [in] self_cnt: number of self-signed intermediates seen so far
+ *  - [in] trust_ca: list of locally trusted certificates
+ *  - [out] parent: parent found (or NULL)
+ *  - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0
+ *  - [out] signature_is_good: 1 if child signature by parent is valid, or 0
+ *  - [in] path_cnt: number of links in the chain so far (EE -> ... -> child)
+ *  - [in] self_cnt: number of self-signed certs in the chain so far
  *         (will always be no greater than path_cnt)
+ *  - [in-out] rs_ctx: context for restarting operations
  *
  * Return value:
- *  - the first suitable parent found (see find_parent_in() for "suitable")
- *  - NULL if no suitable parent was found
+ *  - 0 on success
+ *  - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
  */
-static mbedtls_x509_crt *x509_crt_find_parent( mbedtls_x509_crt *child,
-                                               mbedtls_x509_crt *trust_ca,
-                                               int *parent_is_trusted,
-                                               size_t path_cnt,
-                                               size_t self_cnt )
+static int x509_crt_find_parent(
+                        mbedtls_x509_crt *child,
+                        mbedtls_x509_crt *trust_ca,
+                        mbedtls_x509_crt **parent,
+                        int *parent_is_trusted,
+                        int *signature_is_good,
+                        unsigned path_cnt,
+                        unsigned self_cnt,
+                        mbedtls_x509_crt_restart_ctx *rs_ctx )
 {
-    mbedtls_x509_crt *parent;
+    int ret;
+    mbedtls_x509_crt *search_list;
 
-    /* Look for a parent in trusted CAs */
     *parent_is_trusted = 1;
-    parent = x509_crt_find_parent_in( child, trust_ca, 1, path_cnt, self_cnt );
 
-    if( parent != NULL )
-        return( parent );
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /* restore then clear saved state if we have some stored */
+    if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 )
+    {
+        *parent_is_trusted = rs_ctx->parent_is_trusted;
+        rs_ctx->parent_is_trusted = -1;
+    }
+#endif
+
+    while( 1 ) {
+        search_list = *parent_is_trusted ? trust_ca : child->next;
+
+        ret = x509_crt_find_parent_in( child, search_list,
+                                       parent, signature_is_good,
+                                       *parent_is_trusted,
+                                       path_cnt, self_cnt, rs_ctx );
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+        if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+        {
+            /* save state */
+            rs_ctx->parent_is_trusted = *parent_is_trusted;
+            return( ret );
+        }
+#else
+        (void) ret;
+#endif
+
+        /* stop here if found or already in second iteration */
+        if( *parent != NULL || *parent_is_trusted == 0 )
+            break;
+
+        /* prepare second iteration */
+        *parent_is_trusted = 0;
+    }
+
+    /* extra precaution against mistakes in the caller */
+    if( parent == NULL )
+    {
+        *parent_is_trusted = 0;
+        *signature_is_good = 0;
+    }
 
-    /* Look for a parent upwards the chain */
-    *parent_is_trusted = 0;
-    return( x509_crt_find_parent_in( child, child->next, 0, path_cnt, self_cnt ) );
+    return( 0 );
 }
 
 /*
@@ -2102,11 +2234,24 @@ static int x509_crt_check_ee_locally_trusted(
  * - EE, Ci1, ..., Ciq cannot be continued with a trusted root
  *   -> return that chain with NOT_TRUSTED set on Ciq
  *
+ * Tests for (aspects of) this function should include at least:
+ * - trusted EE
+ * - EE -> trusted root
+ * - EE -> intermedate CA -> trusted root
+ * - if relevant: EE untrusted
+ * - if relevant: EE -> intermediate, untrusted
+ * with the aspect under test checked at each relevant level (EE, int, root).
+ * For some aspects longer chains are required, but usually length 2 is
+ * enough (but length 1 is not in general).
+ *
  * Arguments:
  *  - [in] crt: the cert list EE, C1, ..., Cn
  *  - [in] trust_ca: the trusted list R1, ..., Rp
  *  - [in] ca_crl, profile: as in verify_with_profile()
- *  - [out] ver_chain, chain_len: the built and verified chain
+ *  - [out] ver_chain: the built and verified chain
+ *      Only valid when return value is 0, may contain garbage otherwise!
+ *      Restart note: need not be the same when calling again to resume.
+ *  - [in-out] rs_ctx: context for restarting operations
  *
  * Return value:
  *  - non-zero if the chain could not be fully built and examined
@@ -2118,24 +2263,50 @@ static int x509_crt_verify_chain(
                 mbedtls_x509_crt *trust_ca,
                 mbedtls_x509_crl *ca_crl,
                 const mbedtls_x509_crt_profile *profile,
-                x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE],
-                size_t *chain_len )
+                mbedtls_x509_crt_verify_chain *ver_chain,
+                mbedtls_x509_crt_restart_ctx *rs_ctx )
 {
+    /* Don't initialize any of those variables here, so that the compiler can
+     * catch potential issues with jumping ahead when restarting */
+    int ret;
     uint32_t *flags;
+    mbedtls_x509_crt_verify_chain_item *cur;
     mbedtls_x509_crt *child;
     mbedtls_x509_crt *parent;
-    int parent_is_trusted = 0;
-    int child_is_trusted = 0;
-    size_t self_cnt = 0;
+    int parent_is_trusted;
+    int child_is_trusted;
+    int signature_is_good;
+    unsigned self_cnt;
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    /* resume if we had an operation in progress */
+    if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent )
+    {
+        /* restore saved state */
+        *ver_chain = rs_ctx->ver_chain; /* struct copy */
+        self_cnt = rs_ctx->self_cnt;
+
+        /* restore derived state */
+        cur = &ver_chain->items[ver_chain->len - 1];
+        child = cur->crt;
+        flags = &cur->flags;
+
+        goto find_parent;
+    }
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
 
     child = crt;
-    *chain_len = 0;
+    self_cnt = 0;
+    parent_is_trusted = 0;
+    child_is_trusted = 0;
 
     while( 1 ) {
         /* Add certificate to the verification chain */
-        ver_chain[*chain_len].crt = child;
-        flags = &ver_chain[*chain_len].flags;
-        ++*chain_len;
+        cur = &ver_chain->items[ver_chain->len];
+        cur->crt = child;
+        cur->flags = 0;
+        ver_chain->len++;
+        flags = &cur->flags;
 
         /* Check time-validity (all certificates) */
         if( mbedtls_x509_time_is_past( &child->valid_to ) )
@@ -2156,15 +2327,33 @@ static int x509_crt_verify_chain(
             *flags |= MBEDTLS_X509_BADCERT_BAD_PK;
 
         /* Special case: EE certs that are locally trusted */
-        if( *chain_len == 1 &&
+        if( ver_chain->len == 1 &&
             x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 )
         {
             return( 0 );
         }
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+find_parent:
+#endif
         /* Look for a parent in trusted CAs or up the chain */
-        parent = x509_crt_find_parent( child, trust_ca, &parent_is_trusted,
-                                       *chain_len - 1, self_cnt );
+        ret = x509_crt_find_parent( child, trust_ca, &parent,
+                                       &parent_is_trusted, &signature_is_good,
+                                       ver_chain->len - 1, self_cnt, rs_ctx );
+
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+        if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+        {
+            /* save state */
+            rs_ctx->in_progress = x509_crt_rs_find_parent;
+            rs_ctx->self_cnt = self_cnt;
+            rs_ctx->ver_chain = *ver_chain; /* struct copy */
+
+            return( ret );
+        }
+#else
+        (void) ret;
+#endif
 
         /* No parent? We're done here */
         if( parent == NULL )
@@ -2176,7 +2365,7 @@ static int x509_crt_verify_chain(
         /* Count intermediate self-issued (not necessarily self-signed) certs.
          * These can occur with some strategies for key rollover, see [SIRO],
          * and should be excluded from max_pathlen checks. */
-        if( *chain_len != 1 &&
+        if( ver_chain->len != 1 &&
             x509_name_cmp( &child->issuer, &child->subject ) == 0 )
         {
             self_cnt++;
@@ -2185,14 +2374,14 @@ static int x509_crt_verify_chain(
         /* path_cnt is 0 for the first intermediate CA,
          * and if parent is trusted it's not an intermediate CA */
         if( ! parent_is_trusted &&
-            *chain_len > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
+            ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
         {
             /* return immediately to avoid overflow the chain array */
             return( MBEDTLS_ERR_X509_FATAL_ERROR );
         }
 
-        /* if parent is trusted, the signature was checked by find_parent() */
-        if( ! parent_is_trusted && x509_crt_check_signature( child, parent ) != 0 )
+        /* signature was checked while searching parent */
+        if( ! signature_is_good )
             *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
 
         /* check size of signing key */
@@ -2210,6 +2399,7 @@ static int x509_crt_verify_chain(
         child = parent;
         parent = NULL;
         child_is_trusted = parent_is_trusted;
+        signature_is_good = 0;
     }
 }
 
@@ -2278,21 +2468,22 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt,
  */
 static int x509_crt_merge_flags_with_cb(
            uint32_t *flags,
-           x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE],
-           size_t chain_len,
+           const mbedtls_x509_crt_verify_chain *ver_chain,
            int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
            void *p_vrfy )
 {
     int ret;
-    size_t i;
+    unsigned i;
     uint32_t cur_flags;
+    const mbedtls_x509_crt_verify_chain_item *cur;
 
-    for( i = chain_len; i != 0; --i )
+    for( i = ver_chain->len; i != 0; --i )
     {
-        cur_flags = ver_chain[i-1].flags;
+        cur = &ver_chain->items[i-1];
+        cur_flags = cur->flags;
 
         if( NULL != f_vrfy )
-            if( ( ret = f_vrfy( p_vrfy, ver_chain[i-1].crt, (int) i-1, &cur_flags ) ) != 0 )
+            if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 )
                 return( ret );
 
         *flags |= cur_flags;
@@ -2302,7 +2493,7 @@ static int x509_crt_merge_flags_with_cb(
 }
 
 /*
- * Verify the certificate validity
+ * Verify the certificate validity (default profile, not restartable)
  */
 int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
                      mbedtls_x509_crt *trust_ca,
@@ -2311,12 +2502,28 @@ int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
                      int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
                      void *p_vrfy )
 {
-    return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl,
-                &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) );
+    return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl,
+                &mbedtls_x509_crt_profile_default, cn, flags,
+                f_vrfy, p_vrfy, NULL ) );
 }
 
 /*
- * Verify the certificate validity, with profile
+ * Verify the certificate validity (user-chosen profile, not restartable)
+ */
+int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
+                     mbedtls_x509_crt *trust_ca,
+                     mbedtls_x509_crl *ca_crl,
+                     const mbedtls_x509_crt_profile *profile,
+                     const char *cn, uint32_t *flags,
+                     int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
+                     void *p_vrfy )
+{
+    return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl,
+                profile, cn, flags, f_vrfy, p_vrfy, NULL ) );
+}
+
+/*
+ * Verify the certificate validity, with profile, restartable version
  *
  * This function:
  *  - checks the requested CN (if any)
@@ -2325,23 +2532,23 @@ int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
  *  - builds and verifies the chain
  *  - then calls the callback and merges the flags
  */
-int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
+int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt,
                      mbedtls_x509_crt *trust_ca,
                      mbedtls_x509_crl *ca_crl,
                      const mbedtls_x509_crt_profile *profile,
                      const char *cn, uint32_t *flags,
                      int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
-                     void *p_vrfy )
+                     void *p_vrfy,
+                     mbedtls_x509_crt_restart_ctx *rs_ctx )
 {
     int ret;
     mbedtls_pk_type_t pk_type;
-    x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE];
-    size_t chain_len;
-    uint32_t *ee_flags = &ver_chain[0].flags;
+    mbedtls_x509_crt_verify_chain ver_chain;
+    uint32_t ee_flags;
 
     *flags = 0;
-    memset( ver_chain, 0, sizeof( ver_chain ) );
-    chain_len = 0;
+    ee_flags = 0;
+    x509_crt_verify_chain_reset( &ver_chain );
 
     if( profile == NULL )
     {
@@ -2351,28 +2558,36 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
 
     /* check name if requested */
     if( cn != NULL )
-        x509_crt_verify_name( crt, cn, ee_flags );
+        x509_crt_verify_name( crt, cn, &ee_flags );
 
     /* Check the type and size of the key */
     pk_type = mbedtls_pk_get_type( &crt->pk );
 
     if( x509_profile_check_pk_alg( profile, pk_type ) != 0 )
-        *ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
+        ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
 
     if( x509_profile_check_key( profile, &crt->pk ) != 0 )
-        *ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
+        ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
 
     /* Check the chain */
     ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile,
-                                 ver_chain, &chain_len );
+                                 &ver_chain, rs_ctx );
+
     if( ret != 0 )
         goto exit;
 
+    /* Merge end-entity flags */
+    ver_chain.items[0].flags |= ee_flags;
+
     /* Build final flags, calling callback on the way if any */
-    ret = x509_crt_merge_flags_with_cb( flags,
-                                        ver_chain, chain_len, f_vrfy, p_vrfy );
+    ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy );
 
 exit:
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
+        mbedtls_x509_crt_restart_free( rs_ctx );
+#endif
+
     /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
      * the SSL module for authmode optional, but non-zero return from the
      * callback means a fatal error so it shouldn't be ignored */
@@ -2483,4 +2698,36 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
     while( cert_cur != NULL );
 }
 
+#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+/*
+ * Initialize a restart context
+ */
+void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx )
+{
+    mbedtls_pk_restart_init( &ctx->pk );
+
+    ctx->parent = NULL;
+    ctx->fallback_parent = NULL;
+    ctx->fallback_signature_is_good = 0;
+
+    ctx->parent_is_trusted = -1;
+
+    ctx->in_progress = x509_crt_rs_none;
+    ctx->self_cnt = 0;
+    x509_crt_verify_chain_reset( &ctx->ver_chain );
+}
+
+/*
+ * Free the components of a restart context
+ */
+void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_pk_restart_free( &ctx->pk );
+    mbedtls_x509_crt_restart_init( ctx );
+}
+#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
 #endif /* MBEDTLS_X509_CRT_PARSE_C */