Merge pull request #5134 from xffbai/add-hostname-ext

TLS1.3 Add hostname extension
diff --git a/ChangeLog.d/fix-needed-shared-libraries-linux.txt b/ChangeLog.d/fix-needed-shared-libraries-linux.txt
new file mode 100644
index 0000000..74ad3bc
--- /dev/null
+++ b/ChangeLog.d/fix-needed-shared-libraries-linux.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix issue in Makefile on Linux with SHARED=1, that caused shared libraries
+     not to list other shared libraries they need.
diff --git a/ChangeLog.d/psa_crypto_api_macros.txt b/ChangeLog.d/psa_crypto_api_macros.txt
new file mode 100644
index 0000000..ff53e33
--- /dev/null
+++ b/ChangeLog.d/psa_crypto_api_macros.txt
@@ -0,0 +1,11 @@
+Features
+   * Add missing PSA macros declared by PSA Crypto API 1.0.0:
+     PSA_ALG_IS_SIGN_HASH, PSA_ALG_NONE, PSA_HASH_BLOCK_LENGTH, PSA_KEY_ID_NULL.
+
+Bugfix
+   * The existing predicate macro name PSA_ALG_IS_HASH_AND_SIGN is now reserved
+     for algorithm values that fully encode the hashing step, as per the PSA
+     Crypto API specification. This excludes PSA_ALG_RSA_PKCS1V15_SIGN_RAW and
+     PSA_ALG_ECDSA_ANY. The new predicate macro PSA_ALG_IS_SIGN_HASH covers
+     all algorithms that can be used with psa_{sign,verify}_hash(), including
+     these two.
diff --git a/README.md b/README.md
index e6924cb..c8d9450 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@
 
 The main systems used for development are CMake and GNU Make. Those systems are always complete and up-to-date. The others should reflect all changes present in the CMake and Make build system, although features may not be ported there automatically.
 
-The Make and CMake build systems create three libraries: libmbedcrypto, libmbedx509, and libmbedtls. Note that libmbedtls depends on libmbedx509 and libmbedcrypto, and libmbedx509 depends on libmbedcrypto. As a result, some linkers will expect flags to be in a specific order, for example the GNU linker wants `-lmbedtls -lmbedx509 -lmbedcrypto`. Also, when loading shared libraries using dlopen(), you'll need to load libmbedcrypto first, then libmbedx509, before you can load libmbedtls.
+The Make and CMake build systems create three libraries: libmbedcrypto, libmbedx509, and libmbedtls. Note that libmbedtls depends on libmbedx509 and libmbedcrypto, and libmbedx509 depends on libmbedcrypto. As a result, some linkers will expect flags to be in a specific order, for example the GNU linker wants `-lmbedtls -lmbedx509 -lmbedcrypto`.
 
 ### Tool versions
 
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 5d9854a..ee4b54c 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -2990,7 +2990,9 @@
  * \param key                   Identifier of the key to use for the operation.
  *                              It must be an asymmetric key pair. The key must
  *                              allow the usage #PSA_KEY_USAGE_SIGN_HASH.
- * \param alg                   A signature algorithm that is compatible with
+ * \param alg                   A signature algorithm (PSA_ALG_XXX
+ *                              value such that #PSA_ALG_IS_SIGN_HASH(\p alg)
+ *                              is true), that is compatible with
  *                              the type of \p key.
  * \param[in] hash              The hash or message to sign.
  * \param hash_length           Size of the \p hash buffer in bytes.
@@ -3043,7 +3045,9 @@
  *                          must be a public key or an asymmetric key pair. The
  *                          key must allow the usage
  *                          #PSA_KEY_USAGE_VERIFY_HASH.
- * \param alg               A signature algorithm that is compatible with
+ * \param alg               A signature algorithm (PSA_ALG_XXX
+ *                          value such that #PSA_ALG_IS_SIGN_HASH(\p alg)
+ *                          is true), that is compatible with
  *                          the type of \p key.
  * \param[in] hash          The hash or message whose signature is to be
  *                          verified.
diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h
index 4c67f10..5f230e0 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -79,6 +79,38 @@
         PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_512 ? 64 :       \
         0)
 
+/** The input block size of a hash algorithm, in bytes.
+ *
+ * Hash algorithms process their input data in blocks. Hash operations will
+ * retain any partial blocks until they have enough input to fill the block or
+ * until the operation is finished.
+ * This affects the output from psa_hash_suspend().
+ *
+ * \param alg   A hash algorithm (\c PSA_ALG_XXX value such that
+ *              PSA_ALG_IS_HASH(\p alg) is true).
+ *
+ * \return      The block size in bytes for the specified hash algorithm.
+ *              If the hash algorithm is not recognized, return 0.
+ *              An implementation can return either 0 or the correct size for a
+ *              hash algorithm that it recognizes, but does not support.
+ */
+#define PSA_HASH_BLOCK_LENGTH(alg)                                  \
+    (                                                               \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD5 ? 64 :            \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_RIPEMD160 ? 64 :      \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_1 ? 64 :          \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_224 ? 64 :        \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_256 ? 64 :        \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_384 ? 128 :       \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512 ? 128 :       \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512_224 ? 128 :   \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512_256 ? 128 :   \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_224 ? 144 :      \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_256 ? 136 :      \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_384 ? 104 :      \
+        PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_512 ? 72 :       \
+        0)
+
 /** \def PSA_HASH_MAX_SIZE
  *
  * Maximum size of a hash.
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index 621b872..f0d76fb 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -847,6 +847,9 @@
     (PSA_ALG_IS_KEY_DERIVATION(alg) &&              \
      (alg) & PSA_ALG_KEY_DERIVATION_STRETCHING_FLAG)
 
+/** An invalid algorithm identifier value. */
+#define PSA_ALG_NONE                            ((psa_algorithm_t)0)
+
 #define PSA_ALG_HASH_MASK                       ((psa_algorithm_t)0x000000ff)
 /** MD5 */
 #define PSA_ALG_MD5                             ((psa_algorithm_t)0x02000003)
@@ -1589,20 +1592,24 @@
  * file. */
 #define PSA_ALG_IS_VENDOR_HASH_AND_SIGN(alg) 0
 
-/** Whether the specified algorithm is a hash-and-sign algorithm.
+/** Whether the specified algorithm is a signature algorithm that can be used
+ * with psa_sign_hash() and psa_verify_hash().
  *
- * Hash-and-sign algorithms are asymmetric (public-key) signature algorithms
- * structured in two parts: first the calculation of a hash in a way that
- * does not depend on the key, then the calculation of a signature from the
- * hash value and the key.
+ * This encompasses all strict hash-and-sign algorithms categorized by
+ * PSA_ALG_IS_HASH_AND_SIGN(), as well as algorithms that follow the
+ * paradigm more loosely:
+ * - #PSA_ALG_RSA_PKCS1V15_SIGN_RAW (expects its input to be an encoded hash)
+ * - #PSA_ALG_ECDSA_ANY (doesn't specify what kind of hash the input is)
  *
- * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ * \param alg An algorithm identifier (value of type psa_algorithm_t).
  *
- * \return 1 if \p alg is a hash-and-sign algorithm, 0 otherwise.
- *         This macro may return either 0 or 1 if \p alg is not a supported
- *         algorithm identifier.
+ * \return 1 if alg is a signature algorithm that can be used to sign a
+ *         hash. 0 if alg is a signature algorithm that can only be used
+ *         to sign a message. 0 if alg is not a signature algorithm.
+ *         This macro can return either 0 or 1 if alg is not a
+ *         supported algorithm identifier.
  */
-#define PSA_ALG_IS_HASH_AND_SIGN(alg)                                   \
+#define PSA_ALG_IS_SIGN_HASH(alg)                                       \
     (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||    \
      PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_HASH_EDDSA(alg) ||             \
      PSA_ALG_IS_VENDOR_HASH_AND_SIGN(alg))
@@ -1619,7 +1626,37 @@
  *         supported algorithm identifier.
  */
 #define PSA_ALG_IS_SIGN_MESSAGE(alg)                                    \
-    (PSA_ALG_IS_HASH_AND_SIGN(alg) || (alg) == PSA_ALG_PURE_EDDSA )
+    (PSA_ALG_IS_SIGN_HASH(alg) || (alg) == PSA_ALG_PURE_EDDSA )
+
+/** Whether the specified algorithm is a hash-and-sign algorithm.
+ *
+ * Hash-and-sign algorithms are asymmetric (public-key) signature algorithms
+ * structured in two parts: first the calculation of a hash in a way that
+ * does not depend on the key, then the calculation of a signature from the
+ * hash value and the key. Hash-and-sign algorithms encode the hash
+ * used for the hashing step, and you can call #PSA_ALG_SIGN_GET_HASH
+ * to extract this algorithm.
+ *
+ * Thus, for a hash-and-sign algorithm,
+ * `psa_sign_message(key, alg, input, ...)` is equivalent to
+ * ```
+ * psa_hash_compute(PSA_ALG_SIGN_GET_HASH(alg), input, ..., hash, ...);
+ * psa_sign_hash(key, alg, hash, ..., signature, ...);
+ * ```
+ * Most usefully, separating the hash from the signature allows the hash
+ * to be calculated in multiple steps with psa_hash_setup(), psa_hash_update()
+ * and psa_hash_finish(). Likewise psa_verify_message() is equivalent to
+ * calculating the hash and then calling psa_verify_hash().
+ *
+ * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ *
+ * \return 1 if \p alg is a hash-and-sign algorithm, 0 otherwise.
+ *         This macro may return either 0 or 1 if \p alg is not a supported
+ *         algorithm identifier.
+ */
+#define PSA_ALG_IS_HASH_AND_SIGN(alg)                                   \
+    (PSA_ALG_IS_SIGN_HASH(alg) &&                                       \
+     ((alg) & PSA_ALG_HASH_MASK) != 0)
 
 /** Get the hash used by a hash-and-sign signature algorithm.
  *
@@ -1641,7 +1678,6 @@
  */
 #define PSA_ALG_SIGN_GET_HASH(alg)                                     \
     (PSA_ALG_IS_HASH_AND_SIGN(alg) ?                                   \
-     ((alg) & PSA_ALG_HASH_MASK) == 0 ? /*"raw" algorithm*/ 0 :        \
      ((alg) & PSA_ALG_HASH_MASK) | PSA_ALG_CATEGORY_HASH :             \
      0)
 
@@ -2132,6 +2168,9 @@
 
 #define PSA_KEY_LOCATION_VENDOR_FLAG            ((psa_key_location_t)0x800000)
 
+/** The null key identifier.
+ */
+#define PSA_KEY_ID_NULL                         ((psa_key_id_t)0)
 /** The minimum value for a key identifier chosen by the application.
  */
 #define PSA_KEY_ID_USER_MIN                     ((psa_key_id_t)0x00000001)
diff --git a/library/Makefile b/library/Makefile
index 13cd7db..01e85cf 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -199,7 +199,7 @@
 
 libmbedtls.$(SOEXT_TLS): $(OBJS_TLS) libmbedx509.so
 	echo "  LD    $@"
-	$(CC) -shared -Wl,-soname,$@ -L. -lmbedcrypto -lmbedx509 $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_TLS)
+	$(CC) -shared -Wl,-soname,$@ -o $@ $(OBJS_TLS) -L. -lmbedx509 -lmbedcrypto $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 libmbedtls.so: libmbedtls.$(SOEXT_TLS)
 	echo "  LN    $@ -> $<"
@@ -207,11 +207,11 @@
 
 libmbedtls.dylib: $(OBJS_TLS) libmbedx509.dylib
 	echo "  LD    $@"
-	$(CC) -dynamiclib -L. -lmbedcrypto -lmbedx509 $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_TLS)
+	$(CC) -dynamiclib -o $@ $(OBJS_TLS) -L. -lmbedx509 -lmbedcrypto $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 libmbedtls.dll: $(OBJS_TLS) libmbedx509.dll
 	echo "  LD    $@"
-	$(CC) -shared -Wl,-soname,$@ -Wl,--out-implib,$@.a -o $@ $(OBJS_TLS) -lws2_32 -lwinmm -lgdi32 -L. -lmbedcrypto -lmbedx509 -static-libgcc $(LOCAL_LDFLAGS) $(LDFLAGS)
+	$(CC) -shared -Wl,-soname,$@ -Wl,--out-implib,$@.a -o $@ $(OBJS_TLS) -lws2_32 -lwinmm -lgdi32 -L. -lmbedx509 -lmbedcrypto -static-libgcc $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 # x509
 libmbedx509.a: $(OBJS_X509)
@@ -226,7 +226,7 @@
 
 libmbedx509.$(SOEXT_X509): $(OBJS_X509) libmbedcrypto.so
 	echo "  LD    $@"
-	$(CC) -shared -Wl,-soname,$@ -L. -lmbedcrypto $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_X509)
+	$(CC) -shared -Wl,-soname,$@ -o $@ $(OBJS_X509) -L. -lmbedcrypto $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 libmbedx509.so: libmbedx509.$(SOEXT_X509)
 	echo "  LN    $@ -> $<"
@@ -234,7 +234,7 @@
 
 libmbedx509.dylib: $(OBJS_X509) libmbedcrypto.dylib
 	echo "  LD    $@"
-	$(CC) -dynamiclib -L. -lmbedcrypto  $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_X509)
+	$(CC) -dynamiclib -o $@ $(OBJS_X509) -L. -lmbedcrypto  $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 libmbedx509.dll: $(OBJS_X509) libmbedcrypto.dll
 	echo "  LD    $@"
@@ -253,7 +253,7 @@
 
 libmbedcrypto.$(SOEXT_CRYPTO): $(OBJS_CRYPTO)
 	echo "  LD    $@"
-	$(CC) -shared -Wl,-soname,$@ $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_CRYPTO)
+	$(CC) -shared -Wl,-soname,$@ -o $@ $(OBJS_CRYPTO) $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 libmbedcrypto.so: libmbedcrypto.$(SOEXT_CRYPTO)
 	echo "  LN    $@ -> $<"
@@ -261,7 +261,7 @@
 
 libmbedcrypto.dylib: $(OBJS_CRYPTO)
 	echo "  LD    $@"
-	$(CC) -dynamiclib $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_CRYPTO)
+	$(CC) -dynamiclib -o $@ $(OBJS_CRYPTO) $(LOCAL_LDFLAGS) $(LDFLAGS)
 
 libmbedcrypto.dll: $(OBJS_CRYPTO)
 	echo "  LD    $@"
diff --git a/library/base64_invasive.h b/library/base64_invasive.h
index 9e26471..ed5f7cb 100644
--- a/library/base64_invasive.h
+++ b/library/base64_invasive.h
@@ -52,4 +52,4 @@
 signed char mbedtls_base64_dec_value( unsigned char c );
 #endif /* MBEDTLS_TEST_HOOKS */
 
-#endif /* MBEDTLS_SSL_INVASIVE_H */
+#endif /* MBEDTLS_BASE64_INVASIVE_H */
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 3670071..c4bcddc 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -623,8 +623,8 @@
         return( alg1 );
     /* If the policies are from the same hash-and-sign family, check
      * if one is a wildcard. If so the other has the specific algorithm. */
-    if( PSA_ALG_IS_HASH_AND_SIGN( alg1 ) &&
-        PSA_ALG_IS_HASH_AND_SIGN( alg2 ) &&
+    if( PSA_ALG_IS_SIGN_HASH( alg1 ) &&
+        PSA_ALG_IS_SIGN_HASH( alg2 ) &&
         ( alg1 & ~PSA_ALG_HASH_MASK ) == ( alg2 & ~PSA_ALG_HASH_MASK ) )
     {
         if( PSA_ALG_SIGN_GET_HASH( alg1 ) == PSA_ALG_ANY_HASH )
@@ -726,7 +726,7 @@
     /* If policy_alg is a hash-and-sign with a wildcard for the hash,
      * and requested_alg is the same hash-and-sign family with any hash,
      * then requested_alg is compliant with policy_alg. */
-    if( PSA_ALG_IS_HASH_AND_SIGN( requested_alg ) &&
+    if( PSA_ALG_IS_SIGN_HASH( requested_alg ) &&
         PSA_ALG_SIGN_GET_HASH( policy_alg ) == PSA_ALG_ANY_HASH )
     {
         return( ( policy_alg & ~PSA_ALG_HASH_MASK ) ==
@@ -2644,7 +2644,7 @@
         if( ! PSA_ALG_IS_SIGN_MESSAGE( alg ) )
             return( PSA_ERROR_INVALID_ARGUMENT );
 
-        if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
+        if ( PSA_ALG_IS_SIGN_HASH( alg ) )
         {
             if( ! PSA_ALG_IS_HASH( PSA_ALG_SIGN_GET_HASH( alg ) ) )
                 return( PSA_ERROR_INVALID_ARGUMENT );
@@ -2652,7 +2652,7 @@
     }
     else
     {
-        if( ! PSA_ALG_IS_HASH_AND_SIGN( alg ) )
+        if( ! PSA_ALG_IS_SIGN_HASH( alg ) )
             return( PSA_ERROR_INVALID_ARGUMENT );
     }
 
@@ -2802,7 +2802,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
-    if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
+    if ( PSA_ALG_IS_SIGN_HASH( alg ) )
     {
         size_t hash_length;
         uint8_t hash[PSA_HASH_MAX_SIZE];
@@ -2849,7 +2849,7 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
-    if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
+    if ( PSA_ALG_IS_SIGN_HASH( alg ) )
     {
         size_t hash_length;
         uint8_t hash[PSA_HASH_MAX_SIZE];
diff --git a/library/psa_crypto_mac.c b/library/psa_crypto_mac.c
index 2c079d4..7e0a832 100644
--- a/library/psa_crypto_mac.c
+++ b/library/psa_crypto_mac.c
@@ -42,29 +42,6 @@
 #endif
 
 #if defined(BUILTIN_ALG_HMAC)
-static size_t psa_get_hash_block_size( psa_algorithm_t alg )
-{
-    switch( alg )
-    {
-        case PSA_ALG_MD5:
-            return( 64 );
-        case PSA_ALG_RIPEMD160:
-            return( 64 );
-        case PSA_ALG_SHA_1:
-            return( 64 );
-        case PSA_ALG_SHA_224:
-            return( 64 );
-        case PSA_ALG_SHA_256:
-            return( 64 );
-        case PSA_ALG_SHA_384:
-            return( 128 );
-        case PSA_ALG_SHA_512:
-            return( 128 );
-        default:
-            return( 0 );
-    }
-}
-
 static psa_status_t psa_hmac_abort_internal(
     mbedtls_psa_hmac_operation_t *hmac )
 {
@@ -81,7 +58,7 @@
     uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
     size_t i;
     size_t hash_size = PSA_HASH_LENGTH( hash_alg );
-    size_t block_size = psa_get_hash_block_size( hash_alg );
+    size_t block_size = PSA_HASH_BLOCK_LENGTH( hash_alg );
     psa_status_t status;
 
     hmac->alg = hash_alg;
@@ -153,7 +130,7 @@
     uint8_t tmp[MBEDTLS_MD_MAX_SIZE];
     psa_algorithm_t hash_alg = hmac->alg;
     size_t hash_size = 0;
-    size_t block_size = psa_get_hash_block_size( hash_alg );
+    size_t block_size = PSA_HASH_BLOCK_LENGTH( hash_alg );
     psa_status_t status;
 
     status = psa_hash_finish( &hmac->hash_ctx, tmp, sizeof( tmp ), &hash_size );
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index 87347bf..23d5970 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -1646,6 +1646,11 @@
 int mbedtls_ssl_tls13_process_certificate( mbedtls_ssl_context *ssl );
 
 /*
+ * Generic handler of Certificate Verify
+ */
+int mbedtls_ssl_tls13_process_certificate_verify( mbedtls_ssl_context *ssl );
+
+/*
  * Write TLS 1.3 handshake message tail
  */
 int mbedtls_ssl_tls13_finish_handshake_msg( mbedtls_ssl_context *ssl,
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index 5abb18c..e36e28d 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -1590,7 +1590,12 @@
  */
 static int ssl_tls1_3_process_certificate_verify( mbedtls_ssl_context *ssl )
 {
-    MBEDTLS_SSL_DEBUG_MSG( 1, ( "%s hasn't been implemented", __func__ ) );
+    int ret;
+
+    ret = mbedtls_ssl_tls13_process_certificate_verify( ssl );
+    if( ret != 0 )
+        return( ret );
+
     mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_FINISHED );
     return( 0 );
 }
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index c8601ce..75b11c9 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -23,14 +23,15 @@
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
 
+#include <string.h>
+
 #include "mbedtls/error.h"
 #include "mbedtls/debug.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/platform.h"
 
 #include "ssl_misc.h"
-#include <mbedtls/debug.h>
-#include <mbedtls/oid.h>
-#include <mbedtls/platform.h>
-
+#include "ssl_tls13_keys.h"
 
 int mbedtls_ssl_tls1_3_fetch_handshake_msg( mbedtls_ssl_context *ssl,
                                             unsigned hs_type,
@@ -217,8 +218,300 @@
     return( 0 );
 }
 
+/*
+ * STATE HANDLING: Read CertificateVerify
+ */
+/* Macro to express the maximum length of the verify structure.
+ *
+ * The structure is computed per TLS 1.3 specification as:
+ *   - 64 bytes of octet 32,
+ *   - 33 bytes for the context string
+ *        (which is either "TLS 1.3, client CertificateVerify"
+ *         or "TLS 1.3, server CertificateVerify"),
+ *   - 1 byte for the octet 0x0, which serves as a separator,
+ *   - 32 or 48 bytes for the Transcript-Hash(Handshake Context, Certificate)
+ *     (depending on the size of the transcript_hash)
+ *
+ * This results in a total size of
+ * - 130 bytes for a SHA256-based transcript hash, or
+ *   (64 + 33 + 1 + 32 bytes)
+ * - 146 bytes for a SHA384-based transcript hash.
+ *   (64 + 33 + 1 + 48 bytes)
+ *
+ */
+#define SSL_VERIFY_STRUCT_MAX_SIZE  ( 64 +                          \
+                                      33 +                          \
+                                       1 +                          \
+                                      MBEDTLS_TLS1_3_MD_MAX_SIZE    \
+                                    )
+
+/*
+ * The ssl_tls13_create_verify_structure() creates the verify structure.
+ * As input, it requires the transcript hash.
+ *
+ * The caller has to ensure that the buffer has size at least
+ * SSL_VERIFY_STRUCT_MAX_SIZE bytes.
+ */
+static void ssl_tls13_create_verify_structure( const unsigned char *transcript_hash,
+                                               size_t transcript_hash_len,
+                                               unsigned char *verify_buffer,
+                                               size_t *verify_buffer_len,
+                                               int from )
+{
+    size_t idx;
+
+    /* RFC 8446, Section 4.4.3:
+     *
+     * The digital signature [in the CertificateVerify message] is then
+     * computed over the concatenation of:
+     * -  A string that consists of octet 32 (0x20) repeated 64 times
+     * -  The context string
+     * -  A single 0 byte which serves as the separator
+     * -  The content to be signed
+     */
+    memset( verify_buffer, 0x20, 64 );
+    idx = 64;
+
+    if( from == MBEDTLS_SSL_IS_CLIENT )
+    {
+        memcpy( verify_buffer + idx, MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( client_cv ) );
+        idx += MBEDTLS_SSL_TLS1_3_LBL_LEN( client_cv );
+    }
+    else
+    { /* from == MBEDTLS_SSL_IS_SERVER */
+        memcpy( verify_buffer + idx, MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( server_cv ) );
+        idx += MBEDTLS_SSL_TLS1_3_LBL_LEN( server_cv );
+    }
+
+    verify_buffer[idx++] = 0x0;
+
+    memcpy( verify_buffer + idx, transcript_hash, transcript_hash_len );
+    idx += transcript_hash_len;
+
+    *verify_buffer_len = idx;
+}
+
+static int ssl_tls13_sig_alg_is_offered( const mbedtls_ssl_context *ssl,
+                                         uint16_t sig_alg )
+{
+    const uint16_t *tls13_sig_alg = ssl->conf->tls13_sig_algs;
+
+    for( ; *tls13_sig_alg != MBEDTLS_TLS13_SIG_NONE ; tls13_sig_alg++ )
+    {
+        if( *tls13_sig_alg == sig_alg )
+            return( 1 );
+    }
+    return( 0 );
+}
+
+static int ssl_tls13_parse_certificate_verify( mbedtls_ssl_context *ssl,
+                                               const unsigned char *buf,
+                                               const unsigned char *end,
+                                               const unsigned char *verify_buffer,
+                                               size_t verify_buffer_len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    const unsigned char *p = buf;
+    uint16_t algorithm;
+    size_t signature_len;
+    mbedtls_pk_type_t sig_alg;
+    mbedtls_md_type_t md_alg;
+    unsigned char verify_hash[MBEDTLS_MD_MAX_SIZE];
+    size_t verify_hash_len;
+
+    /*
+     * struct {
+     *     SignatureScheme algorithm;
+     *     opaque signature<0..2^16-1>;
+     * } CertificateVerify;
+     */
+    MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, 2 );
+    algorithm = MBEDTLS_GET_UINT16_BE( p, 0 );
+    p += 2;
+
+    /* RFC 8446 section 4.4.3
+     *
+     * If the CertificateVerify message is sent by a server, the signature algorithm
+     * MUST be one offered in the client's "signature_algorithms" extension unless
+     * no valid certificate chain can be produced without unsupported algorithms
+     *
+     * RFC 8446 section 4.4.2.2
+     *
+     * If the client cannot construct an acceptable chain using the provided
+     * certificates and decides to abort the handshake, then it MUST abort the handshake
+     * with an appropriate certificate-related alert (by default, "unsupported_certificate").
+     *
+     * Check if algorithm is an offered signature algorithm.
+     */
+    if( ! ssl_tls13_sig_alg_is_offered( ssl, algorithm ) )
+    {
+        /* algorithm not in offered signature algorithms list */
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "Received signature algorithm(%04x) is not "
+                                    "offered.",
+                                    ( unsigned int ) algorithm ) );
+        goto error;
+    }
+
+    /* We currently only support ECDSA-based signatures */
+    switch( algorithm )
+    {
+        case MBEDTLS_TLS13_SIG_ECDSA_SECP256R1_SHA256:
+            md_alg = MBEDTLS_MD_SHA256;
+            sig_alg = MBEDTLS_PK_ECDSA;
+            break;
+        case MBEDTLS_TLS13_SIG_ECDSA_SECP384R1_SHA384:
+            md_alg = MBEDTLS_MD_SHA384;
+            sig_alg = MBEDTLS_PK_ECDSA;
+            break;
+        case MBEDTLS_TLS13_SIG_ECDSA_SECP521R1_SHA512:
+            md_alg = MBEDTLS_MD_SHA512;
+            sig_alg = MBEDTLS_PK_ECDSA;
+            break;
+        default:
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "Certificate Verify: Unknown signature algorithm." ) );
+            goto error;
+    }
+
+    MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate Verify: Signature algorithm ( %04x )",
+                                ( unsigned int ) algorithm ) );
+
+    /*
+     * Check the certificate's key type matches the signature alg
+     */
+    if( !mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, sig_alg ) )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "signature algorithm doesn't match cert key" ) );
+        goto error;
+    }
+
+    MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, 2 );
+    signature_len = MBEDTLS_GET_UINT16_BE( p, 0 );
+    p += 2;
+    MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, signature_len );
+
+    /* Hash verify buffer with indicated hash function */
+    switch( md_alg )
+    {
+#if defined(MBEDTLS_SHA256_C)
+        case MBEDTLS_MD_SHA256:
+            verify_hash_len = 32;
+            ret = mbedtls_sha256( verify_buffer, verify_buffer_len, verify_hash, 0 );
+            break;
+#endif /* MBEDTLS_SHA256_C */
+
+#if defined(MBEDTLS_SHA384_C)
+        case MBEDTLS_MD_SHA384:
+            verify_hash_len = 48;
+            ret = mbedtls_sha512( verify_buffer, verify_buffer_len, verify_hash, 1 );
+            break;
+#endif /* MBEDTLS_SHA384_C */
+
+#if defined(MBEDTLS_SHA512_C)
+        case MBEDTLS_MD_SHA512:
+            verify_hash_len = 64;
+            ret = mbedtls_sha512( verify_buffer, verify_buffer_len, verify_hash, 0 );
+            break;
+#endif /* MBEDTLS_SHA512_C */
+
+        default:
+            ret = MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
+            break;
+    }
+
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "hash computation error", ret );
+        goto error;
+    }
+
+    MBEDTLS_SSL_DEBUG_BUF( 3, "verify hash", verify_hash, verify_hash_len );
+
+    if( ( ret = mbedtls_pk_verify_ext( sig_alg, NULL,
+                                       &ssl->session_negotiate->peer_cert->pk,
+                                       md_alg, verify_hash, verify_hash_len,
+                                       p, signature_len ) ) == 0 )
+    {
+        return( 0 );
+    }
+    MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify_ext", ret );
+
+error:
+    /* RFC 8446 section 4.4.3
+     *
+     * If the verification fails, the receiver MUST terminate the handshake
+     * with a "decrypt_error" alert.
+    */
+    MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR,
+                                  MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
+    return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
+
+}
 #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */
 
+int mbedtls_ssl_tls13_process_certificate_verify( mbedtls_ssl_context *ssl )
+{
+
+#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED)
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char verify_buffer[SSL_VERIFY_STRUCT_MAX_SIZE];
+    size_t verify_buffer_len;
+    unsigned char transcript[MBEDTLS_TLS1_3_MD_MAX_SIZE];
+    size_t transcript_len;
+    unsigned char *buf;
+    size_t buf_len;
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
+
+    MBEDTLS_SSL_PROC_CHK(
+        mbedtls_ssl_tls1_3_fetch_handshake_msg( ssl,
+                MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, &buf, &buf_len ) );
+
+    /* Need to calculate the hash of the transcript first
+     * before reading the message since otherwise it gets
+     * included in the transcript
+     */
+    ret = mbedtls_ssl_get_handshake_transcript( ssl,
+                            ssl->handshake->ciphersuite_info->mac,
+                            transcript, sizeof( transcript ),
+                            &transcript_len );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_PEND_FATAL_ALERT(
+            MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR,
+            MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+        return( ret );
+    }
+
+    MBEDTLS_SSL_DEBUG_BUF( 3, "handshake hash", transcript, transcript_len );
+
+    /* Create verify structure */
+    ssl_tls13_create_verify_structure( transcript,
+                                       transcript_len,
+                                       verify_buffer,
+                                       &verify_buffer_len,
+                                       ( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) ?
+                                         MBEDTLS_SSL_IS_SERVER :
+                                         MBEDTLS_SSL_IS_CLIENT );
+
+    /* Process the message contents */
+    MBEDTLS_SSL_PROC_CHK( ssl_tls13_parse_certificate_verify( ssl, buf,
+                            buf + buf_len, verify_buffer, verify_buffer_len ) );
+
+    mbedtls_ssl_tls1_3_add_hs_msg_to_checksum( ssl,
+                        MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, buf, buf_len );
+
+cleanup:
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) );
+    MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_process_certificate_verify", ret );
+    return( ret );
+#else
+    ((void) ssl);
+    MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+    return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */
+}
+
 /*
  *
  * STATE HANDLING: Incoming Certificate, client-side only currently.
diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h
index 384f433..165b58a 100644
--- a/library/ssl_tls13_keys.h
+++ b/library/ssl_tls13_keys.h
@@ -22,25 +22,27 @@
 /* This requires MBEDTLS_SSL_TLS1_3_LABEL( idx, name, string ) to be defined at
  * the point of use. See e.g. the definition of mbedtls_ssl_tls1_3_labels_union
  * below. */
-#define MBEDTLS_SSL_TLS1_3_LABEL_LIST                               \
-    MBEDTLS_SSL_TLS1_3_LABEL( finished    , "finished"     ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( resumption  , "resumption"   ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( traffic_upd , "traffic upd"  ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( exporter    , "exporter"     ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( key         , "key"          ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( iv          , "iv"           ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( c_hs_traffic, "c hs traffic" ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( c_ap_traffic, "c ap traffic" ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( c_e_traffic , "c e traffic"  ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( s_hs_traffic, "s hs traffic" ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( s_ap_traffic, "s ap traffic" ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( s_e_traffic , "s e traffic"  ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( e_exp_master, "e exp master" ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( res_master  , "res master"   ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( exp_master  , "exp master"   ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( ext_binder  , "ext binder"   ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( res_binder  , "res binder"   ) \
-    MBEDTLS_SSL_TLS1_3_LABEL( derived     , "derived"      )
+#define MBEDTLS_SSL_TLS1_3_LABEL_LIST                                             \
+    MBEDTLS_SSL_TLS1_3_LABEL( finished    , "finished"                          ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( resumption  , "resumption"                        ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( traffic_upd , "traffic upd"                       ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( exporter    , "exporter"                          ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( key         , "key"                               ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( iv          , "iv"                                ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( c_hs_traffic, "c hs traffic"                      ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( c_ap_traffic, "c ap traffic"                      ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( c_e_traffic , "c e traffic"                       ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( s_hs_traffic, "s hs traffic"                      ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( s_ap_traffic, "s ap traffic"                      ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( s_e_traffic , "s e traffic"                       ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( e_exp_master, "e exp master"                      ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( res_master  , "res master"                        ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( exp_master  , "exp master"                        ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( ext_binder  , "ext binder"                        ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( res_binder  , "res binder"                        ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( derived     , "derived"                           ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( client_cv   , "TLS 1.3, client CertificateVerify" ) \
+    MBEDTLS_SSL_TLS1_3_LABEL( server_cv   , "TLS 1.3, server CertificateVerify" )
 
 #define MBEDTLS_SSL_TLS1_3_LABEL( name, string )       \
     const unsigned char name    [ sizeof(string) - 1 ];
@@ -57,9 +59,12 @@
 
 extern const struct mbedtls_ssl_tls1_3_labels_struct mbedtls_ssl_tls1_3_labels;
 
+#define MBEDTLS_SSL_TLS1_3_LBL_LEN( LABEL )  \
+    sizeof(mbedtls_ssl_tls1_3_labels.LABEL)
+
 #define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( LABEL )  \
     mbedtls_ssl_tls1_3_labels.LABEL,              \
-    sizeof(mbedtls_ssl_tls1_3_labels.LABEL)
+    MBEDTLS_SSL_TLS1_3_LBL_LEN( LABEL )
 
 #define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN  \
     sizeof( union mbedtls_ssl_tls1_3_labels_union )
diff --git a/scripts/code_size_compare.py b/scripts/code_size_compare.py
new file mode 100755
index 0000000..85393d0
--- /dev/null
+++ b/scripts/code_size_compare.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python3
+
+"""
+Purpose
+
+This script is for comparing the size of the library files from two
+different Git revisions within an Mbed TLS repository.
+The results of the comparison is formatted as csv and stored at a
+configurable location.
+Note: must be run from Mbed TLS root.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import os
+import subprocess
+import sys
+
+class CodeSizeComparison:
+    """Compare code size between two Git revisions."""
+
+    def __init__(self, old_revision, new_revision, result_dir):
+        """
+        old_revision: revision to compare against
+        new_revision:
+        result_dir: directory for comparision result
+        """
+        self.repo_path = "."
+        self.result_dir = os.path.abspath(result_dir)
+        os.makedirs(self.result_dir, exist_ok=True)
+
+        self.csv_dir = os.path.abspath("code_size_records/")
+        os.makedirs(self.csv_dir, exist_ok=True)
+
+        self.old_rev = old_revision
+        self.new_rev = new_revision
+        self.git_command = "git"
+        self.make_command = "make"
+
+    @staticmethod
+    def check_repo_path():
+        if not all(os.path.isdir(d) for d in ["include", "library", "tests"]):
+            raise Exception("Must be run from Mbed TLS root")
+
+    @staticmethod
+    def validate_revision(revision):
+        result = subprocess.check_output(["git", "rev-parse", "--verify",
+                                          revision + "^{commit}"], shell=False)
+        return result
+
+    def _create_git_worktree(self, revision):
+        """Make a separate worktree for revision.
+        Do not modify the current worktree."""
+
+        if revision == "current":
+            print("Using current work directory.")
+            git_worktree_path = self.repo_path
+        else:
+            print("Creating git worktree for", revision)
+            git_worktree_path = os.path.join(self.repo_path, "temp-" + revision)
+            subprocess.check_output(
+                [self.git_command, "worktree", "add", "--detach",
+                 git_worktree_path, revision], cwd=self.repo_path,
+                stderr=subprocess.STDOUT
+            )
+        return git_worktree_path
+
+    def _build_libraries(self, git_worktree_path):
+        """Build libraries in the specified worktree."""
+
+        my_environment = os.environ.copy()
+        subprocess.check_output(
+            [self.make_command, "-j", "lib"], env=my_environment,
+            cwd=git_worktree_path, stderr=subprocess.STDOUT,
+        )
+
+    def _gen_code_size_csv(self, revision, git_worktree_path):
+        """Generate code size csv file."""
+
+        csv_fname = revision + ".csv"
+        if revision == "current":
+            print("Measuring code size in current work directory.")
+        else:
+            print("Measuring code size for", revision)
+        result = subprocess.check_output(
+            ["size library/*.o"], cwd=git_worktree_path, shell=True
+        )
+        size_text = result.decode()
+        csv_file = open(os.path.join(self.csv_dir, csv_fname), "w")
+        for line in size_text.splitlines()[1:]:
+            data = line.split()
+            csv_file.write("{}, {}\n".format(data[5], data[3]))
+
+    def _remove_worktree(self, git_worktree_path):
+        """Remove temporary worktree."""
+        if git_worktree_path != self.repo_path:
+            print("Removing temporary worktree", git_worktree_path)
+            subprocess.check_output(
+                [self.git_command, "worktree", "remove", "--force",
+                 git_worktree_path], cwd=self.repo_path,
+                stderr=subprocess.STDOUT
+            )
+
+    def _get_code_size_for_rev(self, revision):
+        """Generate code size csv file for the specified git revision."""
+
+        # Check if the corresponding record exists
+        csv_fname = revision + ".csv"
+        if (revision != "current") and \
+           os.path.exists(os.path.join(self.csv_dir, csv_fname)):
+            print("Code size csv file for", revision, "already exists.")
+        else:
+            git_worktree_path = self._create_git_worktree(revision)
+            self._build_libraries(git_worktree_path)
+            self._gen_code_size_csv(revision, git_worktree_path)
+            self._remove_worktree(git_worktree_path)
+
+    def compare_code_size(self):
+        """Generate results of the size changes between two revisions,
+        old and new. Measured code size results of these two revisions
+        must be available."""
+
+        old_file = open(os.path.join(self.csv_dir, self.old_rev + ".csv"), "r")
+        new_file = open(os.path.join(self.csv_dir, self.new_rev + ".csv"), "r")
+        res_file = open(os.path.join(self.result_dir, "compare-" + self.old_rev
+                                     + "-" + self.new_rev + ".csv"), "w")
+
+        res_file.write("file_name, this_size, old_size, change, change %\n")
+        print("Generating comparision results.")
+
+        old_ds = {}
+        for line in old_file.readlines()[1:]:
+            cols = line.split(", ")
+            fname = cols[0]
+            size = int(cols[1])
+            if size != 0:
+                old_ds[fname] = size
+
+        new_ds = {}
+        for line in new_file.readlines()[1:]:
+            cols = line.split(", ")
+            fname = cols[0]
+            size = int(cols[1])
+            new_ds[fname] = size
+
+        for fname in new_ds:
+            this_size = new_ds[fname]
+            if fname in old_ds:
+                old_size = old_ds[fname]
+                change = this_size - old_size
+                change_pct = change / old_size
+                res_file.write("{}, {}, {}, {}, {:.2%}\n".format(fname, \
+                               this_size, old_size, change, float(change_pct)))
+            else:
+                res_file.write("{}, {}\n".format(fname, this_size))
+        return 0
+
+    def get_comparision_results(self):
+        """Compare size of library/*.o between self.old_rev and self.new_rev,
+        and generate the result file."""
+        self.check_repo_path()
+        self._get_code_size_for_rev(self.old_rev)
+        self._get_code_size_for_rev(self.new_rev)
+        return self.compare_code_size()
+
+def main():
+    parser = argparse.ArgumentParser(
+        description=(
+            """This script is for comparing the size of the library files
+            from two different Git revisions within an Mbed TLS repository.
+            The results of the comparison is formatted as csv, and stored at
+            a configurable location.
+            Note: must be run from Mbed TLS root."""
+        )
+    )
+    parser.add_argument(
+        "-r", "--result-dir", type=str, default="comparison",
+        help="directory where comparison result is stored, \
+              default is comparison",
+    )
+    parser.add_argument(
+        "-o", "--old-rev", type=str, help="old revision for comparison.",
+        required=True,
+    )
+    parser.add_argument(
+        "-n", "--new-rev", type=str, default=None,
+        help="new revision for comparison, default is the current work \
+              directory, including uncommited changes."
+    )
+    comp_args = parser.parse_args()
+
+    if os.path.isfile(comp_args.result_dir):
+        print("Error: {} is not a directory".format(comp_args.result_dir))
+        parser.exit()
+
+    validate_res = CodeSizeComparison.validate_revision(comp_args.old_rev)
+    old_revision = validate_res.decode().replace("\n", "")
+
+    if comp_args.new_rev is not None:
+        validate_res = CodeSizeComparison.validate_revision(comp_args.new_rev)
+        new_revision = validate_res.decode().replace("\n", "")
+    else:
+        new_revision = "current"
+
+    result_dir = comp_args.result_dir
+    size_compare = CodeSizeComparison(old_revision, new_revision, result_dir)
+    return_code = size_compare.get_comparision_results()
+    sys.exit(return_code)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c
index 923d2c1..91bac67 100644
--- a/tests/src/psa_exercise_key.c
+++ b/tests/src/psa_exercise_key.c
@@ -306,7 +306,7 @@
         psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH( alg );
 
         /* If the policy allows signing with any hash, just pick one. */
-        if( PSA_ALG_IS_HASH_AND_SIGN( alg ) && hash_alg == PSA_ALG_ANY_HASH )
+        if( PSA_ALG_IS_SIGN_HASH( alg ) && hash_alg == PSA_ALG_ANY_HASH )
         {
     #if defined(KNOWN_SUPPORTED_HASH_ALG)
             hash_alg = KNOWN_SUPPORTED_HASH_ALG;
@@ -925,7 +925,7 @@
 {
     if( PSA_ALG_IS_MAC( alg ) || PSA_ALG_IS_SIGN( alg ) )
     {
-        if( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
+        if( PSA_ALG_IS_SIGN_HASH( alg ) )
         {
             if( PSA_ALG_SIGN_GET_HASH( alg ) )
                 return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ?
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 9930210..0e78356 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -8831,8 +8831,11 @@
             -c "server hello, chosen ciphersuite: ( 1301 ) - TLS1-3-AES-128-GCM-SHA256" \
             -c "ECDH curve: x25519"         \
             -c "=> ssl_tls1_3_process_server_hello" \
+            -c "<= parse encrypted extensions"      \
             -c "Certificate verification flags clear" \
-            -c "<= parse encrypted extensions"
+            -c "=> parse certificate verify"          \
+            -c "<= parse certificate verify"          \
+            -c "mbedtls_ssl_tls13_process_certificate_verify() returned 0"
 
 requires_gnutls_tls1_3
 requires_gnutls_next_no_ticket
@@ -8861,8 +8864,11 @@
             -c "server hello, chosen ciphersuite: ( 1301 ) - TLS1-3-AES-128-GCM-SHA256" \
             -c "ECDH curve: x25519"         \
             -c "=> ssl_tls1_3_process_server_hello" \
+            -c "<= parse encrypted extensions"      \
             -c "Certificate verification flags clear" \
-            -c "<= parse encrypted extensions"
+            -c "=> parse certificate verify"          \
+            -c "<= parse certificate verify"          \
+            -c "mbedtls_ssl_tls13_process_certificate_verify() returned 0"
 
 # Test heap memory usage after handshake
 requires_config_enabled MBEDTLS_MEMORY_DEBUG
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 591c296..01a0698 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -1422,7 +1422,7 @@
     else
         TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED );
 
-    if( PSA_ALG_IS_HASH_AND_SIGN( exercise_alg ) &&
+    if( PSA_ALG_IS_SIGN_HASH( exercise_alg ) &&
         PSA_ALG_IS_HASH( PSA_ALG_SIGN_GET_HASH( exercise_alg ) ) )
     {
         status = psa_sign_message( key, exercise_alg,
diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data
index ad806c7..83763c5 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.data
+++ b/tests/suites/test_suite_psa_crypto_metadata.data
@@ -196,31 +196,31 @@
 
 Asymmetric signature: RSA PKCS#1 v1.5 raw
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
-asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_SIGN_HASH
 
 Asymmetric signature: RSA PKCS#1 v1.5 SHA-256
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_ALG_SHA_256
-asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN( PSA_ALG_SHA_256 ):ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN( PSA_ALG_SHA_256 ):ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: RSA PSS SHA-256
 depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256
-asymmetric_signature_algorithm:PSA_ALG_RSA_PSS( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_STANDARD_SALT | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_RSA_PSS( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_STANDARD_SALT | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: RSA PSS-any-salt SHA-256
 depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256
-asymmetric_signature_algorithm:PSA_ALG_RSA_PSS_ANY_SALT( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_ANY_SALT | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_RSA_PSS_ANY_SALT( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_ANY_SALT | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: randomized ECDSA (no hashing)
 depends_on:PSA_WANT_ALG_ECDSA
-asymmetric_signature_algorithm:PSA_ALG_ECDSA_ANY:ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_ECDSA_ANY:ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_SIGN_HASH
 
 Asymmetric signature: SHA-256 + randomized ECDSA
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256
-asymmetric_signature_algorithm:PSA_ALG_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: SHA-256 + deterministic ECDSA using SHA-256
 depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256
-asymmetric_signature_algorithm:PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_DETERMINISTIC_ECDSA | ALG_ECDSA_IS_DETERMINISTIC | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_DETERMINISTIC_ECDSA | ALG_ECDSA_IS_DETERMINISTIC | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: pure EdDSA
 depends_on:PSA_WANT_ALG_EDDSA
@@ -228,11 +228,11 @@
 
 Asymmetric signature: Ed25519ph
 depends_on:PSA_WANT_ALG_EDDSA
-asymmetric_signature_algorithm:PSA_ALG_ED25519PH:ALG_IS_HASH_EDDSA | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_ED25519PH:ALG_IS_HASH_EDDSA | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: Ed448ph
 depends_on:PSA_WANT_ALG_EDDSA
-asymmetric_signature_algorithm:PSA_ALG_ED448PH:ALG_IS_HASH_EDDSA | ALG_IS_HASH_AND_SIGN
+asymmetric_signature_algorithm:PSA_ALG_ED448PH:ALG_IS_HASH_EDDSA | ALG_IS_SIGN_HASH | ALG_IS_HASH_AND_SIGN
 
 Asymmetric signature: RSA PKCS#1 v1.5 with wildcard hash
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN
diff --git a/tests/suites/test_suite_psa_crypto_metadata.function b/tests/suites/test_suite_psa_crypto_metadata.function
index ab9b2f8..092780c 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.function
+++ b/tests/suites/test_suite_psa_crypto_metadata.function
@@ -33,16 +33,18 @@
 #define ALG_IS_DETERMINISTIC_ECDSA      ( 1u << 14 )
 #define ALG_IS_RANDOMIZED_ECDSA         ( 1u << 15 )
 #define ALG_IS_HASH_EDDSA               ( 1u << 16 )
-#define ALG_IS_HASH_AND_SIGN            ( 1u << 17 )
-#define ALG_IS_RSA_OAEP                 ( 1u << 18 )
-#define ALG_IS_HKDF                     ( 1u << 19 )
-#define ALG_IS_FFDH                     ( 1u << 20 )
-#define ALG_IS_ECDH                     ( 1u << 21 )
-#define ALG_IS_WILDCARD                 ( 1u << 22 )
-#define ALG_IS_RAW_KEY_AGREEMENT        ( 1u << 23 )
-#define ALG_IS_AEAD_ON_BLOCK_CIPHER     ( 1u << 24 )
-#define ALG_IS_TLS12_PRF                ( 1u << 25 )
-#define ALG_IS_TLS12_PSK_TO_MS          ( 1u << 26 )
+#define ALG_IS_SIGN_HASH                ( 1u << 17 )
+#define ALG_IS_HASH_AND_SIGN            ( 1u << 18 )
+#define ALG_IS_RSA_OAEP                 ( 1u << 19 )
+#define ALG_IS_HKDF                     ( 1u << 20 )
+#define ALG_IS_FFDH                     ( 1u << 21 )
+#define ALG_IS_ECDH                     ( 1u << 22 )
+#define ALG_IS_WILDCARD                 ( 1u << 23 )
+#define ALG_IS_RAW_KEY_AGREEMENT        ( 1u << 24 )
+#define ALG_IS_AEAD_ON_BLOCK_CIPHER     ( 1u << 25 )
+#define ALG_IS_TLS12_PRF                ( 1u << 26 )
+#define ALG_IS_TLS12_PSK_TO_MS          ( 1u << 27 )
+#define ALG_FLAG_MASK_PLUS_ONE          ( 1u << 28 ) /* must be last! */
 
 /* Flags for key type classification macros. There is a flag for every
  * key type classification macro PSA_KEY_TYPE_IS_xxx except for some that
@@ -51,26 +53,43 @@
 #define KEY_TYPE_IS_VENDOR_DEFINED      ( 1u << 0 )
 #define KEY_TYPE_IS_UNSTRUCTURED        ( 1u << 1 )
 #define KEY_TYPE_IS_PUBLIC_KEY          ( 1u << 2 )
-#define KEY_TYPE_IS_KEY_PAIR             ( 1u << 3 )
+#define KEY_TYPE_IS_KEY_PAIR            ( 1u << 3 )
 #define KEY_TYPE_IS_RSA                 ( 1u << 4 )
 #define KEY_TYPE_IS_DSA                 ( 1u << 5 )
 #define KEY_TYPE_IS_ECC                 ( 1u << 6 )
 #define KEY_TYPE_IS_DH                  ( 1u << 7 )
+#define KEY_TYPE_FLAG_MASK_PLUS_ONE     ( 1u << 8 ) /* must be last! */
 
 /* Flags for lifetime classification macros. There is a flag for every
  * lifetime classification macro PSA_KEY_LIFETIME_IS_xxx. The name of the
  * flag is the name of the classification macro without the PSA_ prefix. */
 #define KEY_LIFETIME_IS_VOLATILE        ( 1u << 0 )
 #define KEY_LIFETIME_IS_READ_ONLY       ( 1u << 1 )
+#define KEY_LIFETIME_FLAG_MASK_PLUS_ONE ( 1u << 2 ) /* must be last! */
 
-#define TEST_CLASSIFICATION_MACRO( flag, alg, flags ) \
-    do                                                \
-    {                                                 \
-        if( ( flags ) & ( flag ) )                    \
-            TEST_ASSERT( PSA_##flag( alg ) );         \
-        else                                          \
-            TEST_ASSERT( ! PSA_##flag( alg ) );       \
-    }                                                 \
+/* Check that in the value of flags, the bit flag (which should be a macro
+ * expanding to a number of the form 1 << k) is set if and only if
+ * PSA_##flag(alg) is true.
+ *
+ * Only perform this check if cond is true. Typically cond is 1, but it can
+ * be different if the value of the flag bit is only specified under specific
+ * conditions.
+ *
+ * Unconditionally mask flag into the ambient variable
+ * classification_flags_tested.
+ */
+#define TEST_CLASSIFICATION_MACRO( cond, flag, alg, flags )     \
+    do                                                          \
+    {                                                           \
+        if( cond )                                              \
+        {                                                       \
+            if( ( flags ) & ( flag ) )                          \
+                TEST_ASSERT( PSA_##flag( alg ) );               \
+            else                                                \
+                TEST_ASSERT( ! PSA_##flag( alg ) );             \
+        }                                                       \
+        classification_flags_tested |= ( flag );                \
+    }                                                           \
     while( 0 )
 
 /* Check the parity of value.
@@ -97,44 +116,55 @@
 
 void algorithm_classification( psa_algorithm_t alg, unsigned flags )
 {
-    TEST_CLASSIFICATION_MACRO( ALG_IS_VENDOR_DEFINED, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_HMAC, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_BLOCK_CIPHER_MAC, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_STREAM_CIPHER, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_PKCS1V15_SIGN, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_PSS, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_DSA, alg, flags );
-    if ( PSA_ALG_IS_DSA( alg ) )
-        TEST_CLASSIFICATION_MACRO( ALG_DSA_IS_DETERMINISTIC, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_DETERMINISTIC_DSA, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_RANDOMIZED_DSA, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_ECDSA, alg, flags );
-    if ( PSA_ALG_IS_ECDSA( alg ) )
-        TEST_CLASSIFICATION_MACRO( ALG_ECDSA_IS_DETERMINISTIC, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_DETERMINISTIC_ECDSA, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_RANDOMIZED_ECDSA, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_HASH_EDDSA, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_HASH_AND_SIGN, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_OAEP, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_HKDF, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_WILDCARD, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_ECDH, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_FFDH, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_RAW_KEY_AGREEMENT, alg, flags );
-    TEST_CLASSIFICATION_MACRO( ALG_IS_AEAD_ON_BLOCK_CIPHER, alg, flags );
+    unsigned classification_flags_tested = 0;
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_VENDOR_DEFINED, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_HMAC, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_BLOCK_CIPHER_MAC, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_STREAM_CIPHER, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RSA_PKCS1V15_SIGN, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RSA_PSS, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RSA_PSS_ANY_SALT, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RSA_PSS_STANDARD_SALT, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_DSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( PSA_ALG_IS_DSA( alg ),
+                               ALG_DSA_IS_DETERMINISTIC, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_DETERMINISTIC_DSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RANDOMIZED_DSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_ECDSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( PSA_ALG_IS_ECDSA( alg ),
+                               ALG_ECDSA_IS_DETERMINISTIC, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_DETERMINISTIC_ECDSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RANDOMIZED_ECDSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_HASH_EDDSA, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_SIGN_HASH, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_HASH_AND_SIGN, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RSA_OAEP, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_HKDF, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_WILDCARD, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_ECDH, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_FFDH, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_RAW_KEY_AGREEMENT, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_AEAD_ON_BLOCK_CIPHER, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_TLS12_PRF, alg, flags );
+    TEST_CLASSIFICATION_MACRO( 1, ALG_IS_TLS12_PSK_TO_MS, alg, flags );
+    TEST_EQUAL( classification_flags_tested, ALG_FLAG_MASK_PLUS_ONE - 1 );
 exit: ;
 }
 
 void key_type_classification( psa_key_type_t type, unsigned flags )
 {
+    unsigned classification_flags_tested = 0;
+
     /* Macros tested based on the test case parameter */
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_VENDOR_DEFINED, type, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_UNSTRUCTURED, type, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_PUBLIC_KEY, type, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_KEY_PAIR, type, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_RSA, type, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_ECC, type, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_DH, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_VENDOR_DEFINED, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_UNSTRUCTURED, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_PUBLIC_KEY, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_KEY_PAIR, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_RSA, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_DSA, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_ECC, type, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_TYPE_IS_DH, type, flags );
+    TEST_EQUAL( classification_flags_tested, KEY_TYPE_FLAG_MASK_PLUS_ONE - 1 );
 
     /* Macros with derived semantics */
     TEST_EQUAL( PSA_KEY_TYPE_IS_ASYMMETRIC( type ),
@@ -353,6 +383,7 @@
     TEST_ASSERT( PSA_ALG_IS_HASH( hash_alg ) );
     TEST_EQUAL( PSA_ALG_HMAC( hash_alg ), alg );
 
+    TEST_ASSERT( block_size == PSA_HASH_BLOCK_LENGTH( alg ) );
     TEST_ASSERT( block_size <= PSA_HMAC_MAX_HASH_BLOCK_SIZE );
 
     test_mac_algorithm( alg_arg, ALG_IS_HMAC, length,
@@ -489,7 +520,9 @@
 /* BEGIN_CASE */
 void asymmetric_signature_wildcard( int alg_arg, int classification_flags )
 {
-    classification_flags |= ALG_IS_HASH_AND_SIGN | ALG_IS_WILDCARD;
+    classification_flags |= ALG_IS_WILDCARD;
+    classification_flags |= ALG_IS_SIGN_HASH;
+    classification_flags |= ALG_IS_HASH_AND_SIGN;
     test_asymmetric_signature_algorithm( alg_arg, classification_flags );
     /* Any failure of this test function comes from
      * asymmetric_signature_algorithm. Pacify -Werror=unused-label. */
@@ -693,9 +726,12 @@
     psa_key_persistence_t persistence = persistence_arg;
     psa_key_location_t location = location_arg;
     unsigned flags = classification_flags;
+    unsigned classification_flags_tested = 0;
 
-    TEST_CLASSIFICATION_MACRO( KEY_LIFETIME_IS_VOLATILE, lifetime, flags );
-    TEST_CLASSIFICATION_MACRO( KEY_LIFETIME_IS_READ_ONLY, lifetime, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_LIFETIME_IS_VOLATILE, lifetime, flags );
+    TEST_CLASSIFICATION_MACRO( 1, KEY_LIFETIME_IS_READ_ONLY, lifetime, flags );
+    TEST_EQUAL( classification_flags_tested,
+                KEY_LIFETIME_FLAG_MASK_PLUS_ONE - 1 );
 
     TEST_EQUAL( PSA_KEY_LIFETIME_GET_PERSISTENCE( lifetime ), persistence );
     TEST_EQUAL( PSA_KEY_LIFETIME_GET_LOCATION( lifetime ), location );