Merge pull request #1522 from ronald-cron-arm/mbedtls-3.6-release-sync-merge

Merge of 'mbedtls-restricted/mbedtls-3.6-release-sync' into 'mbedtls-restricted/mbedtls-3.6-restricted'
This commit is contained in:
Gilles Peskine
2026-03-23 14:29:17 +01:00
committed by GitHub
27 changed files with 815 additions and 974 deletions

View File

@@ -0,0 +1,5 @@
Bugfix
* Support re-assembly of fragmented DTLS 1.2 ClientHello in Mbed TLS server.
* Support re-assembly of fragmented TLS 1.2 ClientHello in Mbed TLS server
even if TLS 1.3 support is disabled. This removes the main limitation on
support for re-assembly of fragmented handshake messages in TLS 1.2.

View File

@@ -0,0 +1,7 @@
Bugfix
* Some functions in PK were using large buffers (around 2KB in the default
configuration) on the stack, which was a problem in environments with a
small stack. Those buffers are now allocated on the heap, except in
configurations where ECC is the only supported key type in PK, making PK
still independent of the heap in such configurations (if the ECC driver
itself is not using the heap). Fixes #476.

View File

@@ -0,0 +1,5 @@
Changes
* Harden mbedtls_ssl_get_verify_result() against misuse.
If the handshake has not yet been attempted, return -1u to indicate
that the result is not available. Previously the result of verification
was zero-initialized so the function would return 0 (indicating success).

View File

@@ -218,8 +218,11 @@ typedef struct mbedtls_pk_info_t mbedtls_pk_info_t;
* \brief Public key container
*/
typedef struct mbedtls_pk_context {
const mbedtls_pk_info_t *MBEDTLS_PRIVATE(pk_info); /**< Public key information */
void *MBEDTLS_PRIVATE(pk_ctx); /**< Underlying public key context */
/** Method table */
const mbedtls_pk_info_t *MBEDTLS_PRIVATE(pk_info);
/** Underlying type-specific key context */
void *MBEDTLS_PRIVATE(pk_ctx);
/* The following field is used to store the ID of a private key in the
* following cases:
* - opaque key when MBEDTLS_USE_PSA_CRYPTO is defined
@@ -838,7 +841,7 @@ int mbedtls_pk_verify_ext(mbedtls_pk_type_t type, const void *options,
* length up to the hash length), depending on the padding mode
* in the underlying RSA context. For a pk object constructed
* by parsing, this is PKCS#1 v1.5 by default. Use
* mbedtls_pk_verify_ext() to explicitly select a different
* mbedtls_pk_sign_ext() to explicitly select a different
* algorithm.
*
* \return 0 on success, or a specific error code.

View File

@@ -5084,13 +5084,6 @@ int mbedtls_ssl_get_session(const mbedtls_ssl_context *ssl,
* supported with some limitations (those limitations do
* not apply to DTLS, where defragmentation is fully
* supported):
* - On an Mbed TLS server that only accepts TLS 1.2,
* the initial ClientHello message must not be fragmented.
* A TLS 1.2 ClientHello may be fragmented if the server
* also accepts TLS 1.3 connections (meaning
* that #MBEDTLS_SSL_PROTO_TLS1_3 enabled, and the
* accepted versions have not been restricted with
* mbedtls_ssl_conf_max_tls_version() or the like).
* - The first fragment of a handshake message must be
* at least 4 bytes long.
* - Non-handshake records must not be interleaved between

View File

@@ -39,9 +39,9 @@ extern "C" {
#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE 1
#if PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
#if PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
#undef MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE
#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE
#endif
/* This covers ciphers, AEADs and CMAC. */

View File

@@ -912,15 +912,11 @@
* If the parameters are not valid, the return value is unspecified.
*/
#define PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits) \
(PSA_KEY_TYPE_IS_UNSTRUCTURED(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \
PSA_KEY_TYPE_IS_DH(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \
(key_type) == PSA_KEY_TYPE_RSA_KEY_PAIR ? PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits) : \
((key_type) == PSA_KEY_TYPE_RSA_KEY_PAIR ? PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits) : \
(key_type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY ? PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \
(key_type) == PSA_KEY_TYPE_DSA_KEY_PAIR ? PSA_KEY_EXPORT_DSA_KEY_PAIR_MAX_SIZE(key_bits) : \
(key_type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY ? PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \
PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) ? PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(key_bits) : \
PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \
0u)
PSA_BITS_TO_BYTES(key_bits)) /*unstructured; FFDH public or private*/
/** Sufficient output buffer size for psa_export_public_key().
*
@@ -1038,10 +1034,16 @@
PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS)
#endif
#define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \
/* This is the name that was standardized in PSA Crypto v1.3 */
#define PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE \
((PSA_EXPORT_KEY_PAIR_MAX_SIZE > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) ? \
PSA_EXPORT_KEY_PAIR_MAX_SIZE : PSA_EXPORT_PUBLIC_KEY_MAX_SIZE)
/* This is our old custom name from before it was in the spec,
* keep it around in case users were relying on it. */
#define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \
PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE
/** Sufficient output buffer size for psa_raw_key_agreement().
*
* This macro returns a compile-time constant if its arguments are

View File

@@ -35,6 +35,31 @@
#include <limits.h>
#include <stdint.h>
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
#include "mbedtls/platform.h" // for calloc/free
#endif
#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
#define MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN \
PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
#define MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN \
PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)
#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN 0
#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && \
MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
#undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN
#endif
#if (defined(MBEDTLS_RSA_C) || \
(defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))) && \
MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
#undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN
#endif
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
/*
* Initialise a mbedtls_pk_context
*/
@@ -586,19 +611,44 @@ int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk,
#if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_USE_PSA_CRYPTO)
static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id,
psa_key_type_t old_type, size_t old_bits,
const psa_key_attributes_t *attributes,
mbedtls_svc_key_id_t *new_key_id)
{
unsigned char key_buffer[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
unsigned char *key_buffer = NULL;
size_t key_buffer_size = 0;
#else
unsigned char key_buffer[PK_EXPORT_KEY_STACK_BUFFER_SIZE];
const size_t key_buffer_size = sizeof(key_buffer);
#endif
size_t key_length = 0;
/* We are exporting from a PK object, so we know key type is valid for PK */
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
key_buffer_size = PSA_EXPORT_KEY_OUTPUT_SIZE(old_type, old_bits);
key_buffer = mbedtls_calloc(1, key_buffer_size);
if (key_buffer == NULL) {
return MBEDTLS_ERR_PK_ALLOC_FAILED;
}
#else
(void) old_type;
(void) old_bits;
#endif
psa_status_t status = psa_export_key(old_key_id,
key_buffer, sizeof(key_buffer),
key_buffer, key_buffer_size,
&key_length);
if (status != PSA_SUCCESS) {
return status;
goto cleanup;
}
status = psa_import_key(attributes, key_buffer, key_length, new_key_id);
mbedtls_platform_zeroize(key_buffer, key_length);
cleanup:
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
mbedtls_free(key_buffer);
#endif
return status;
}
@@ -628,11 +678,13 @@ static int copy_into_psa(mbedtls_svc_key_id_t old_key_id,
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
psa_key_type_t old_type = psa_get_key_type(&old_attributes);
size_t old_bits = psa_get_key_bits(&old_attributes);
psa_reset_key_attributes(&old_attributes);
if (old_type != psa_get_key_type(attributes)) {
return MBEDTLS_ERR_PK_TYPE_MISMATCH;
}
status = export_import_into_psa(old_key_id, attributes, new_key_id);
status = export_import_into_psa(old_key_id, old_type, old_bits,
attributes, new_key_id);
}
return PSA_PK_TO_MBEDTLS_ERR(status);
}
@@ -649,20 +701,25 @@ static int import_pair_into_psa(const mbedtls_pk_context *pk,
if (psa_get_key_type(attributes) != PSA_KEY_TYPE_RSA_KEY_PAIR) {
return MBEDTLS_ERR_PK_TYPE_MISMATCH;
}
unsigned char key_buffer[
PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
unsigned char *const key_end = key_buffer + sizeof(key_buffer);
size_t key_bits = psa_get_key_bits(attributes);
size_t key_buffer_size = PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits);
unsigned char *key_buffer = mbedtls_calloc(1, key_buffer_size);
if (key_buffer == NULL) {
return MBEDTLS_ERR_PK_ALLOC_FAILED;
}
unsigned char *const key_end = key_buffer + key_buffer_size;
unsigned char *key_data = key_end;
int ret = mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk),
key_buffer, &key_data);
if (ret < 0) {
return ret;
goto cleanup_rsa;
}
size_t key_length = key_end - key_data;
ret = PSA_PK_TO_MBEDTLS_ERR(psa_import_key(attributes,
key_data, key_length,
key_id));
mbedtls_platform_zeroize(key_data, key_length);
cleanup_rsa:
mbedtls_zeroize_and_free(key_buffer, key_buffer_size);
return ret;
}
#endif /* MBEDTLS_RSA_C */
@@ -741,7 +798,7 @@ static int import_public_into_psa(const mbedtls_pk_context *pk,
#if defined(MBEDTLS_RSA_C) || \
(defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)) || \
defined(MBEDTLS_USE_PSA_CRYPTO)
unsigned char key_buffer[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
unsigned char key_buffer[MBEDTLS_PK_MAX_PUBKEY_RAW_LEN];
#endif
unsigned char *key_data = NULL;
size_t key_length = 0;
@@ -857,6 +914,21 @@ int mbedtls_pk_import_into_psa(const mbedtls_pk_context *pk,
}
}
static int is_valid_for_pk(psa_key_type_t key_type)
{
#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
if (PSA_KEY_TYPE_IS_ECC(key_type)) {
return 1;
}
#endif
#if defined(MBEDTLS_RSA_C)
if (PSA_KEY_TYPE_IS_RSA(key_type)) {
return 1;
}
#endif
return 0;
}
static int copy_from_psa(mbedtls_svc_key_id_t key_id,
mbedtls_pk_context *pk,
int public_only)
@@ -865,8 +937,13 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id,
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
psa_key_type_t key_type;
size_t key_bits;
/* Use a buffer size large enough to contain either a key pair or public key. */
unsigned char exp_key[PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE];
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
unsigned char *exp_key = NULL;
size_t exp_key_size = 0;
#else
unsigned char exp_key[PK_EXPORT_KEY_STACK_BUFFER_SIZE];
const size_t exp_key_size = sizeof(exp_key);
#endif
size_t exp_key_len;
int ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
@@ -879,10 +956,28 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id,
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
key_type = psa_get_key_type(&key_attr);
if (!is_valid_for_pk(key_type)) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
if (public_only) {
status = psa_export_public_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(key_type);
}
key_bits = psa_get_key_bits(&key_attr);
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
exp_key_size = PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits);
exp_key = mbedtls_calloc(1, exp_key_size);
if (exp_key == NULL) {
return MBEDTLS_ERR_PK_ALLOC_FAILED;
}
#endif
if (public_only) {
status = psa_export_public_key(key_id, exp_key, exp_key_size, &exp_key_len);
} else {
status = psa_export_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
status = psa_export_key(key_id, exp_key, exp_key_size, &exp_key_len);
}
if (status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -964,12 +1059,16 @@ static int copy_from_psa(mbedtls_svc_key_id_t key_id,
#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
{
(void) key_bits;
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
goto exit;
}
exit:
mbedtls_platform_zeroize(exp_key, exp_key_size);
#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
mbedtls_free(exp_key);
#endif
psa_reset_key_attributes(&key_attr);
mbedtls_platform_zeroize(exp_key, sizeof(exp_key));
return ret;
}
@@ -1146,7 +1245,7 @@ int mbedtls_pk_verify_ext(mbedtls_pk_type_t type, const void *options,
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if (pss_opts->mgf1_hash_id == md_alg) {
unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
unsigned char *p;
int key_len;
size_t signature_length;

View File

@@ -44,6 +44,40 @@
#define PEM_BEGIN_ENCRYPTED_PRIVATE_KEY_PKCS8 "-----BEGIN ENCRYPTED PRIVATE KEY-----"
#define PEM_END_ENCRYPTED_PRIVATE_KEY_PKCS8 "-----END ENCRYPTED PRIVATE KEY-----"
/*
* We're trying to statisfy two kinds of users:
* - those who don't want to use the heap;
* - those who can't afford large stack buffers.
*
* The current compromise is that if ECC is the only key type supported in PK,
* then we export keys on the stack, and otherwise we use the heap.
*
* RSA can either be used directly or indirectly via opaque keys if enabled.
* (RSA_ALT is not relevant here as we can't export from such contexts.)
*/
#if !defined(MBEDTLS_RSA_C) && \
!(defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))
#define PK_EXPORT_KEYS_ON_THE_STACK
#endif
#if defined(PK_EXPORT_KEYS_ON_THE_STACK)
/* We know for ECC, pubkey are longer than privkeys, but double check.
* Also, take the maximum size of legacy and PSA, as PSA might be disabled. */
#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE
#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
#endif
#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_ECP_MAX_BYTES
#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE
#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_ECP_MAX_BYTES
#endif
#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_ECP_MAX_PT_LEN
#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE
#define PK_EXPORT_KEY_STACK_BUFFER_SIZE MBEDTLS_ECP_MAX_PT_LEN
#endif
#endif
#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)
/**
* Public function mbedtls_pk_ec() can be used to get direct access to the

View File

@@ -72,7 +72,7 @@ static int rsa_verify_wrap(mbedtls_pk_context *pk, mbedtls_md_type_t md_alg,
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
psa_status_t status;
int key_len;
unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
unsigned char *p = buf + sizeof(buf);
psa_algorithm_t psa_alg_md;
size_t rsa_len = mbedtls_rsa_get_len(rsa);
@@ -288,9 +288,6 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
psa_algorithm_t psa_md_alg, decrypt_alg;
psa_status_t status;
int key_len;
unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES];
unsigned char *p = buf + sizeof(buf);
((void) f_rng);
((void) p_rng);
@@ -298,6 +295,13 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
}
const size_t key_bits = mbedtls_pk_get_bitlen(pk);
/* mbedtls_rsa_write_key() uses the same format as PSA export, which
* actually calls it under the hood, so we can use the PSA size macro. */
const size_t buf_size = PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits);
unsigned char *buf = mbedtls_calloc(1, buf_size);
unsigned char *p = buf + buf_size;
key_len = mbedtls_rsa_write_key(rsa, buf, &p);
if (key_len <= 0) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
@@ -314,7 +318,7 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
psa_set_key_algorithm(&attributes, decrypt_alg);
status = psa_import_key(&attributes,
buf + sizeof(buf) - key_len, key_len,
buf + buf_size - key_len, key_len,
&key_id);
if (status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -333,7 +337,7 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
ret = 0;
cleanup:
mbedtls_platform_zeroize(buf, sizeof(buf));
mbedtls_zeroize_and_free(buf, buf_size);
status = psa_destroy_key(key_id);
if (ret == 0 && status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -371,7 +375,7 @@ static int rsa_encrypt_wrap(mbedtls_pk_context *pk,
psa_algorithm_t psa_md_alg, psa_encrypt_alg;
psa_status_t status;
int key_len;
unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
unsigned char *p = buf + sizeof(buf);
((void) f_rng);
@@ -1336,7 +1340,6 @@ static int rsa_alt_check_pair(mbedtls_pk_context *pub, mbedtls_pk_context *prv,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
unsigned char hash[32];
size_t sig_len = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -1345,21 +1348,29 @@ static int rsa_alt_check_pair(mbedtls_pk_context *pub, mbedtls_pk_context *prv,
return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
}
size_t sig_size = (rsa_get_bitlen(pub) + 7) / 8;
unsigned char *sig = mbedtls_calloc(1, sig_size);
if (sig == NULL) {
return MBEDTLS_ERR_PK_ALLOC_FAILED;
}
memset(hash, 0x2a, sizeof(hash));
if ((ret = rsa_alt_sign_wrap(prv, MBEDTLS_MD_NONE,
hash, sizeof(hash),
sig, sizeof(sig), &sig_len,
sig, sig_size, &sig_len,
f_rng, p_rng)) != 0) {
return ret;
goto cleanup;
}
if (rsa_verify_wrap(pub, MBEDTLS_MD_NONE,
hash, sizeof(hash), sig, sig_len) != 0) {
return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
}
return 0;
cleanup:
mbedtls_zeroize_and_free(sig, sig_size);
return ret;
}
#endif /* MBEDTLS_RSA_C */

View File

@@ -45,10 +45,10 @@
/* Helpers for properly sizing buffers aimed at holding public keys or
* key-pairs based on build symbols. */
#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
#define PK_MAX_EC_PUBLIC_KEY_SIZE PSA_EXPORT_PUBLIC_KEY_MAX_SIZE
#define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
#define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
#elif defined(MBEDTLS_USE_PSA_CRYPTO)
#define PK_MAX_EC_PUBLIC_KEY_SIZE PSA_EXPORT_PUBLIC_KEY_MAX_SIZE
#define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
#define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
#else
#define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_ECP_MAX_PT_LEN

View File

@@ -3261,6 +3261,49 @@ int mbedtls_ssl_prepare_handshake_record(mbedtls_ssl_context *ssl)
return MBEDTLS_ERR_SSL_INVALID_RECORD;
}
if (ssl->in_msg[0] == MBEDTLS_SSL_HS_CLIENT_HELLO &&
ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) {
if (ssl->state == MBEDTLS_SSL_CLIENT_HELLO
#if defined(MBEDTLS_SSL_RENEGOTIATION)
&& ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE
#endif
) {
/*
* When establishing the connection, the client may go through
* a series of ClientHello and HelloVerifyRequest requests and
* responses. The server intentionally does not keep trace of
* these initial round trips: minimum allocated ressources as
* long as the reachability of the client has not been
* confirmed. When receiving the "first ClientHello" from
* server perspective, we may thus need to adapt the next
* expected `message_seq` for the incoming and outgoing
* handshake messages.
*/
ssl->handshake->in_msg_seq = recv_msg_seq;
ssl->handshake->out_msg_seq = recv_msg_seq;
/* Epoch should be 0 for initial handshakes */
if (ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
}
memcpy(&ssl->cur_out_ctr[2], ssl->in_ctr + 2,
sizeof(ssl->cur_out_ctr) - 2);
} else if (mbedtls_ssl_is_handshake_over(ssl) == 1) {
/* In case of a post-handshake ClientHello that initiates a
* renegotiation check that the handshake message sequence
* number is zero.
*/
if (recv_msg_seq != 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message_seq: "
"%u (expected 0)",
recv_msg_seq));
return MBEDTLS_ERR_SSL_DECODE_ERROR;
}
}
}
if (ssl->handshake != NULL &&
((mbedtls_ssl_is_handshake_over(ssl) == 0 &&
recv_msg_seq != ssl->handshake->in_msg_seq) ||
@@ -5137,14 +5180,9 @@ static int ssl_get_next_record(mbedtls_ssl_context *ssl)
/* The record content type may change during decryption,
* so re-read it. */
ssl->in_msgtype = rec.type;
/* Also update the input buffer, because unfortunately
* the server-side ssl_parse_client_hello() reparses the
* record header when receiving a ClientHello initiating
* a renegotiation. */
ssl->in_hdr[0] = rec.type;
ssl->in_msg = rec.buf + rec.data_offset;
ssl->in_msglen = rec.data_len;
MBEDTLS_PUT_UINT16_BE(rec.data_len, ssl->in_len, 0);
return 0;
}
@@ -5830,6 +5868,11 @@ static int ssl_tls12_handle_hs_message_post_handshake(mbedtls_ssl_context *ssl)
ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING;
}
#endif
/* Keep the ClientHello message for ssl_parse_client_hello() */
if (ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) {
ssl->keep_current_message = 1;
}
ret = mbedtls_ssl_start_renegotiation(ssl);
if (ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO &&
ret != 0) {

View File

@@ -1056,6 +1056,8 @@ void mbedtls_ssl_transform_init(mbedtls_ssl_transform *transform)
void mbedtls_ssl_session_init(mbedtls_ssl_session *session)
{
memset(session, 0, sizeof(mbedtls_ssl_session));
/* Set verify_result to -1u to indicate 'result not available'. */
session->verify_result = 0xFFFFFFFF;
}
MBEDTLS_CHECK_RETURN_CRITICAL
@@ -3286,13 +3288,6 @@ size_t mbedtls_ssl_get_output_max_frag_len(const mbedtls_ssl_context *ssl)
#if defined(MBEDTLS_SSL_PROTO_DTLS)
size_t mbedtls_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;
}
@@ -5011,6 +5006,9 @@ void mbedtls_ssl_session_free(mbedtls_ssl_session *session)
#endif
mbedtls_platform_zeroize(session, sizeof(mbedtls_ssl_session));
/* Set verify_result to -1u to indicate 'result not available'. */
session->verify_result = 0xFFFFFFFF;
}
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
@@ -7937,6 +7935,7 @@ static int ssl_parse_certificate_coordinate(mbedtls_ssl_context *ssl,
ssl->handshake->ciphersuite_info;
if (!mbedtls_ssl_ciphersuite_uses_srv_cert(ciphersuite_info)) {
ssl->session_negotiate->verify_result = 0;
return SSL_CERTIFICATE_SKIP;
}
@@ -9881,6 +9880,7 @@ int mbedtls_ssl_verify_certificate(mbedtls_ssl_context *ssl,
void *rs_ctx)
{
if (authmode == MBEDTLS_SSL_VERIFY_NONE) {
ssl->session_negotiate->verify_result = 0;
return 0;
}

View File

@@ -912,131 +912,35 @@ static int ssl_parse_client_hello(mbedtls_ssl_context *ssl)
MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse client hello"));
int renegotiating;
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
read_record_header:
#endif
/*
* If renegotiating, then the input was read with mbedtls_ssl_read_record(),
* otherwise read it ourselves manually in order to support SSLv2
* ClientHello, which doesn't use the same record layer format.
* Otherwise in a scenario of TLS 1.3/TLS 1.2 version negotiation, the
* ClientHello has been already fully fetched by the TLS 1.3 code and the
* flag ssl->keep_current_message is raised.
* Fetch the expected ClientHello handshake message. Do not ask
* mbedtls_ssl_read_record() to update the handshake digest, because the
* ClientHello may already have been read in ssl_tls13_process_client_hello()
* or as a post-handshake message (renegotiation). In those cases we need
* to update the digest ourselves, and it is simpler to do so
* unconditionally than to track whether it is needed.
*/
renegotiating = 0;
#if defined(MBEDTLS_SSL_RENEGOTIATION)
renegotiating = (ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE);
#endif
if (!renegotiating && !ssl->keep_current_message) {
if ((ret = mbedtls_ssl_fetch_input(ssl, 5)) != 0) {
/* No alert on a read error. */
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_fetch_input", ret);
return ret;
}
if ((ret = mbedtls_ssl_read_record(ssl, 0)) != 0) {
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record ", ret);
return ret;
}
buf = ssl->in_hdr;
MBEDTLS_SSL_DEBUG_BUF(4, "record header", buf, mbedtls_ssl_in_hdr_len(ssl));
/*
* TLS Client Hello
* Update the handshake checksum.
*
* Record layer:
* 0 . 0 message type
* 1 . 2 protocol version
* 3 . 11 DTLS: epoch + record sequence number
* 3 . 4 message length
* Note that the checksum must be updated before parsing the extensions
* because ssl_parse_session_ticket_ext() may decrypt the ticket in place
* and therefore modify the ClientHello message. This occurs when using
* the Mbed TLS ssl_ticket.c implementation.
*/
MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, message type: %d",
buf[0]));
if (buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
}
MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, message len.: %d",
MBEDTLS_GET_UINT16_BE(ssl->in_len, 0)));
MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, protocol version: [%d:%d]",
buf[1], buf[2]));
/* For DTLS if this is the initial handshake, remember the client sequence
* number to use it in our next message (RFC 6347 4.2.1) */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM
#if defined(MBEDTLS_SSL_RENEGOTIATION)
&& ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE
#endif
) {
/* Epoch should be 0 for initial handshakes */
if (ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
}
memcpy(&ssl->cur_out_ctr[2], ssl->in_ctr + 2,
sizeof(ssl->cur_out_ctr) - 2);
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
if (mbedtls_ssl_dtls_replay_check(ssl) != 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("replayed record, discarding"));
ssl->next_record_offset = 0;
ssl->in_left = 0;
goto read_record_header;
}
/* No MAC to check yet, so we can update right now */
mbedtls_ssl_dtls_replay_update(ssl);
#endif
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
msg_len = MBEDTLS_GET_UINT16_BE(ssl->in_len, 0);
#if defined(MBEDTLS_SSL_RENEGOTIATION)
if (ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE) {
/* Set by mbedtls_ssl_read_record() */
msg_len = ssl->in_hslen;
} else
#endif
{
if (ssl->keep_current_message) {
ssl->keep_current_message = 0;
} else {
if (msg_len > MBEDTLS_SSL_IN_CONTENT_LEN) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
}
if ((ret = mbedtls_ssl_fetch_input(ssl,
mbedtls_ssl_in_hdr_len(ssl) + msg_len)) != 0) {
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_fetch_input", ret);
return ret;
}
/* Done reading this record, get ready for the next one */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
ssl->next_record_offset = msg_len + mbedtls_ssl_in_hdr_len(ssl);
} else
#endif
ssl->in_left = 0;
}
ret = mbedtls_ssl_update_handshake_status(ssl);
if (0 != ret) {
MBEDTLS_SSL_DEBUG_RET(1, ("mbedtls_ssl_update_handshake_status"), ret);
return ret;
}
buf = ssl->in_msg;
MBEDTLS_SSL_DEBUG_BUF(4, "record contents", buf, msg_len);
ret = ssl->handshake->update_checksum(ssl, buf, msg_len);
if (0 != ret) {
MBEDTLS_SSL_DEBUG_RET(1, ("update_checksum"), ret);
return ret;
}
msg_len = ssl->in_hslen;
/*
* Handshake layer:
@@ -1046,64 +950,12 @@ read_record_header:
* 6 . 8 DTLS only: fragment offset
* 9 . 11 DTLS only: fragment length
*/
if (msg_len < mbedtls_ssl_hs_hdr_len(ssl)) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
return MBEDTLS_ERR_SSL_DECODE_ERROR;
}
MBEDTLS_SSL_DEBUG_MSG(3, ("client hello v3, handshake type: %d", buf[0]));
if (buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO) {
if ((ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE) ||
(buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO)) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
/*
* Copy the client's handshake message_seq on initial handshakes,
* check sequence number on renego.
*/
#if defined(MBEDTLS_SSL_RENEGOTIATION)
if (ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS) {
/* This couldn't be done in ssl_prepare_handshake_record() */
unsigned int cli_msg_seq = (unsigned int) MBEDTLS_GET_UINT16_BE(ssl->in_msg, 4);
if (cli_msg_seq != ssl->handshake->in_msg_seq) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message_seq: "
"%u (expected %u)", cli_msg_seq,
ssl->handshake->in_msg_seq));
return MBEDTLS_ERR_SSL_DECODE_ERROR;
}
ssl->handshake->in_msg_seq++;
} else
#endif
{
unsigned int cli_msg_seq = (unsigned int) MBEDTLS_GET_UINT16_BE(ssl->in_msg, 4);
ssl->handshake->out_msg_seq = cli_msg_seq;
ssl->handshake->in_msg_seq = cli_msg_seq + 1;
}
{
/*
* For now we don't support fragmentation, so make sure
* fragment_offset == 0 and fragment_length == length
*/
size_t fragment_offset, fragment_length, length;
fragment_offset = MBEDTLS_GET_UINT24_BE(ssl->in_msg, 6);
fragment_length = MBEDTLS_GET_UINT24_BE(ssl->in_msg, 9);
length = MBEDTLS_GET_UINT24_BE(ssl->in_msg, 1);
MBEDTLS_SSL_DEBUG_MSG(
4, ("fragment_offset=%u fragment_length=%u length=%u",
(unsigned) fragment_offset, (unsigned) fragment_length,
(unsigned) length));
if (fragment_offset != 0 || length != fragment_length) {
MBEDTLS_SSL_DEBUG_MSG(1, ("ClientHello fragmentation not supported"));
return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
}
}
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
buf += mbedtls_ssl_hs_hdr_len(ssl);
msg_len -= mbedtls_ssl_hs_hdr_len(ssl);
@@ -1433,7 +1285,11 @@ read_record_header:
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
case MBEDTLS_TLS_EXT_SESSION_TICKET:
MBEDTLS_SSL_DEBUG_MSG(3, ("found session ticket extension"));
/*
* If the Mbed TLS ssl_ticket.c implementation is used, the
* ticket is decrypted in place. This modifies the ClientHello
* message in the input buffer.
*/
ret = ssl_parse_session_ticket_ext(ssl, ext + 4, ext_size);
if (ret != 0) {
return ret;

View File

@@ -2270,6 +2270,9 @@ static int ssl_tls13_process_encrypted_extensions(mbedtls_ssl_context *ssl)
#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED)
if (mbedtls_ssl_tls13_key_exchange_mode_with_psk(ssl)) {
mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_SERVER_FINISHED);
/* Since we're not using a certificate, set verify_result to success */
ssl->session_negotiate->verify_result = 0;
} else {
mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST);
}

View File

@@ -2645,6 +2645,9 @@ static int ssl_tls13_write_encrypted_extensions(mbedtls_ssl_context *ssl)
#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED)
if (mbedtls_ssl_tls13_key_exchange_mode_with_psk(ssl)) {
mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_SERVER_FINISHED);
/* Since we're not using a certificate, set verify_result to success */
ssl->session_negotiate->verify_result = 0;
} else {
mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST);
}

View File

@@ -4235,7 +4235,55 @@ close_notify:
} while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
ret = 0;
mbedtls_printf(" done\n");
/*
* In the DTLS case, attempt to read a possible response to the close
* notification. This avoids reconnecting to the same client when we
* reset and later receive its close-notification response during
* step 3 (waiting for a client to connect).
*
* Stop waiting for the response if the connection has already ended.
*
* The waiting loop below relies on mbedtls_ssl_read() returning regularly
* in order to keep the total waiting time approximately bounded to 1s. If
* no read timeout is configured (see the read_timeout option), or if the
* configured timeout is close to or larger than 1s, the total waiting time
* may exceed 1s by a significant margin.
*/
#if defined(MBEDTLS_SSL_PROTO_DTLS) && defined(MBEDTLS_HAVE_TIME)
if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
mbedtls_ms_time_t start = mbedtls_ms_time();
for (;;) {
ret = mbedtls_ssl_read(&ssl, buf, opt.buffer_size);
/*
* mbedtls_ssl_read() returned some data or timed out, loop if we
* have not spent already too much time, quite arbitrarily 1s.
*/
if ((ret > 0) || (ret == MBEDTLS_ERR_SSL_TIMEOUT)) {
if ((mbedtls_ms_time() - start) < 1000) {
continue;
}
}
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
mbedtls_printf(" done, received client close notification.\n");
} else {
/* ret = 0, silent transport EOF or ret < 0 except
* MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY. Note that we do not
* handle specifically the non-fatal error codes like
* MBEDTLS_ERR_SSL_WANT_READ as we do not really expect them
* here.
*/
mbedtls_printf(" done\n");
}
break;
}
ret = 0;
} else
#endif /* MBEDTLS_SSL_PROTO_DTLS && MBEDTLS_HAVE_TIME */
{
mbedtls_printf(" done\n");
}
fflush(stdout);
#if defined(MBEDTLS_SSL_CACHE_C)
if (opt.cache_remove > 0) {

View File

@@ -1,699 +1,16 @@
#!/usr/bin/env python3
"""This script compares the interfaces of two versions of Mbed TLS, looking
for backward incompatibilities between two different Git revisions within
an Mbed TLS repository. It must be run from the root of a Git working tree.
### How the script works ###
For the source (API) and runtime (ABI) interface compatibility, this script
is a small wrapper around the abi-compliance-checker and abi-dumper tools,
applying them to compare the header and library files.
For the storage format, this script compares the automatically generated
storage tests and the manual read tests, and complains if there is a
reduction in coverage. A change in test data will be signaled as a
coverage reduction since the old test data is no longer present. A change in
how test data is presented will be signaled as well; this would be a false
positive.
The results of the API/ABI comparison are either formatted as HTML and stored
at a configurable location, or are given as a brief list of problems.
Returns 0 on success, 1 on non-compliance, and 2 if there is an error
while running the script.
### How to interpret non-compliance ###
This script has relatively common false positives. In many scenarios, it only
reports a pass if there is a strict textual match between the old version and
the new version, and it reports problems where there is a sufficient semantic
match but not a textual match. This section lists some common false positives.
This is not an exhaustive list: in the end what matters is whether we are
breaking a backward compatibility goal.
**API**: the goal is that if an application works with the old version of the
library, it can be recompiled against the new version and will still work.
This is normally validated by comparing the declarations in `include/*/*.h`.
A failure is a declaration that has disappeared or that now has a different
type.
* It's ok to change or remove macros and functions that are documented as
for internal use only or as experimental.
* It's ok to rename function or macro parameters as long as the semantics
has not changed.
* It's ok to change or remove structure fields that are documented as
private.
* It's ok to add fields to a structure that already had private fields
or was documented as extensible.
**ABI**: the goal is that if an application was built against the old version
of the library, the same binary will work when linked against the new version.
This is normally validated by comparing the symbols exported by `libmbed*.so`.
A failure is a symbol that is no longer exported by the same library or that
now has a different type.
* All ABI changes are acceptable if the library version is bumped
(see `scripts/bump_version.sh`).
* ABI changes that concern functions which are declared only inside the
library directory, and not in `include/*/*.h`, are acceptable only if
the function was only ever used inside the same library (libmbedcrypto,
libmbedx509, libmbedtls). As a counter example, if the old version
of libmbedtls calls mbedtls_foo() from libmbedcrypto, and the new version
of libmbedcrypto no longer has a compatible mbedtls_foo(), this does
require a version bump for libmbedcrypto.
**Storage format**: the goal is to check that persistent keys stored by the
old version can be read by the new version. This is normally validated by
comparing the `*read*` test cases in `test_suite*storage_format*.data`.
A failure is a storage read test case that is no longer present with the same
function name and parameter list.
* It's ok if the same test data is present, but its presentation has changed,
for example if a test function is renamed or has different parameters.
* It's ok if redundant tests are removed.
**Generated test coverage**: the goal is to check that automatically
generated tests have as much coverage as before. This is normally validated
by comparing the test cases that are automatically generated by a script.
A failure is a generated test case that is no longer present with the same
function name and parameter list.
* It's ok if the same test data is present, but its presentation has changed,
for example if a test function is renamed or has different parameters.
* It's ok if redundant tests are removed.
"""Bridge script
See framework/scripts/mbedtls_framework/interface_checks.py for detailed documentation.
This is a convenient place to encode any branch-specific information we might want to add
in the future.
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import glob
import os
import re
import sys
import traceback
import shutil
import subprocess
import argparse
import logging
import tempfile
import fnmatch
from types import SimpleNamespace
import xml.etree.ElementTree as ET
import framework_scripts_path # pylint: disable=unused-import
from mbedtls_framework import build_tree
class AbiChecker:
"""API and ABI checker."""
def __init__(self, old_version, new_version, configuration):
"""Instantiate the API/ABI checker.
old_version: RepoVersion containing details to compare against
new_version: RepoVersion containing details to check
configuration.report_dir: directory for output files
configuration.keep_all_reports: if false, delete old reports
configuration.brief: if true, output shorter report to stdout
configuration.check_abi: if true, compare ABIs
configuration.check_api: if true, compare APIs
configuration.check_storage: if true, compare storage format tests
configuration.skip_file: path to file containing symbols and types to skip
"""
self.repo_path = "."
self.log = None
self.verbose = configuration.verbose
self._setup_logger()
self.report_dir = os.path.abspath(configuration.report_dir)
self.keep_all_reports = configuration.keep_all_reports
self.can_remove_report_dir = not (os.path.exists(self.report_dir) or
self.keep_all_reports)
self.old_version = old_version
self.new_version = new_version
self.skip_file = configuration.skip_file
self.check_abi = configuration.check_abi
self.check_api = configuration.check_api
if self.check_abi != self.check_api:
raise Exception('Checking API without ABI or vice versa is not supported')
self.check_storage_tests = configuration.check_storage
self.brief = configuration.brief
self.git_command = "git"
self.make_command = "make"
def _setup_logger(self):
self.log = logging.getLogger()
if self.verbose:
self.log.setLevel(logging.DEBUG)
else:
self.log.setLevel(logging.INFO)
self.log.addHandler(logging.StreamHandler())
@staticmethod
def check_abi_tools_are_installed():
for command in ["abi-dumper", "abi-compliance-checker"]:
if not shutil.which(command):
raise Exception("{} not installed, aborting".format(command))
def _get_clean_worktree_for_git_revision(self, version):
"""Make a separate worktree with version.revision checked out.
Do not modify the current worktree."""
git_worktree_path = tempfile.mkdtemp()
if version.repository:
self.log.debug(
"Checking out git worktree for revision {} from {}".format(
version.revision, version.repository
)
)
fetch_output = subprocess.check_output(
[self.git_command, "fetch",
version.repository, version.revision],
cwd=self.repo_path,
stderr=subprocess.STDOUT
)
self.log.debug(fetch_output.decode("utf-8"))
worktree_rev = "FETCH_HEAD"
else:
self.log.debug("Checking out git worktree for revision {}".format(
version.revision
))
worktree_rev = version.revision
worktree_output = subprocess.check_output(
[self.git_command, "worktree", "add", "--detach",
git_worktree_path, worktree_rev],
cwd=self.repo_path,
stderr=subprocess.STDOUT
)
self.log.debug(worktree_output.decode("utf-8"))
version.commit = subprocess.check_output(
[self.git_command, "rev-parse", "HEAD"],
cwd=git_worktree_path,
stderr=subprocess.STDOUT
).decode("ascii").rstrip()
self.log.debug("Commit is {}".format(version.commit))
return git_worktree_path
def _update_git_submodules(self, git_worktree_path, version):
"""If the crypto submodule is present, initialize it.
if version.crypto_revision exists, update it to that revision,
otherwise update it to the default revision"""
submodule_output = subprocess.check_output(
[self.git_command, "submodule", "foreach", "--recursive",
f'git worktree add --detach "{git_worktree_path}/$displaypath" HEAD'],
cwd=self.repo_path,
stderr=subprocess.STDOUT
)
self.log.debug(submodule_output.decode("utf-8"))
try:
# Try to update the submodules using local commits
# (Git will sometimes insist on fetching the remote without --no-fetch
# if the submodules are shallow clones)
update_output = subprocess.check_output(
[self.git_command, "submodule", "update", "--init", '--recursive', '--no-fetch'],
cwd=git_worktree_path,
stderr=subprocess.STDOUT
)
except subprocess.CalledProcessError as err:
self.log.debug(err.stdout.decode("utf-8"))
# Checkout with --no-fetch failed, falling back to fetching from origin
update_output = subprocess.check_output(
[self.git_command, "submodule", "update", "--init", '--recursive'],
cwd=git_worktree_path,
stderr=subprocess.STDOUT
)
self.log.debug(update_output.decode("utf-8"))
if not (os.path.exists(os.path.join(git_worktree_path, "crypto"))
and version.crypto_revision):
return
if version.crypto_repository:
fetch_output = subprocess.check_output(
[self.git_command, "fetch", version.crypto_repository,
version.crypto_revision],
cwd=os.path.join(git_worktree_path, "crypto"),
stderr=subprocess.STDOUT
)
self.log.debug(fetch_output.decode("utf-8"))
crypto_rev = "FETCH_HEAD"
else:
crypto_rev = version.crypto_revision
checkout_output = subprocess.check_output(
[self.git_command, "checkout", crypto_rev],
cwd=os.path.join(git_worktree_path, "crypto"),
stderr=subprocess.STDOUT
)
self.log.debug(checkout_output.decode("utf-8"))
def _build_shared_libraries(self, git_worktree_path, version):
"""Build the shared libraries in the specified worktree."""
my_environment = os.environ.copy()
my_environment["CFLAGS"] = "-g -Og"
my_environment["SHARED"] = "1"
if os.path.exists(os.path.join(git_worktree_path, "crypto")):
my_environment["USE_CRYPTO_SUBMODULE"] = "1"
make_output = subprocess.check_output(
[self.make_command, "lib"],
env=my_environment,
cwd=git_worktree_path,
stderr=subprocess.STDOUT
)
self.log.debug(make_output.decode("utf-8"))
for root, _dirs, files in os.walk(git_worktree_path):
for file in fnmatch.filter(files, "*.so"):
version.modules[os.path.splitext(file)[0]] = (
os.path.join(root, file)
)
@staticmethod
def _pretty_revision(version):
if version.revision == version.commit:
return version.revision
else:
return "{} ({})".format(version.revision, version.commit)
def _get_abi_dumps_from_shared_libraries(self, version):
"""Generate the ABI dumps for the specified git revision.
The shared libraries must have been built and the module paths
present in version.modules."""
for mbed_module, module_path in version.modules.items():
output_path = os.path.join(
self.report_dir, "{}-{}-{}.dump".format(
mbed_module, version.revision, version.version
)
)
abi_dump_command = [
"abi-dumper",
module_path,
"-o", output_path,
"-lver", self._pretty_revision(version),
]
abi_dump_output = subprocess.check_output(
abi_dump_command,
stderr=subprocess.STDOUT
)
self.log.debug(abi_dump_output.decode("utf-8"))
version.abi_dumps[mbed_module] = output_path
@staticmethod
def _normalize_storage_test_case_data(line):
"""Eliminate cosmetic or irrelevant details in storage format test cases."""
line = re.sub(r'\s+', r'', line)
return line
def _read_storage_tests(self,
directory,
filename,
is_generated,
storage_tests):
"""Record storage tests from the given file.
Populate the storage_tests dictionary with test cases read from
filename under directory.
"""
at_paragraph_start = True
description = None
full_path = os.path.join(directory, filename)
with open(full_path) as fd:
for line_number, line in enumerate(fd, 1):
line = line.strip()
if not line:
at_paragraph_start = True
continue
if line.startswith('#'):
continue
if at_paragraph_start:
description = line.strip()
at_paragraph_start = False
continue
if line.startswith('depends_on:'):
continue
# We've reached a test case data line
test_case_data = self._normalize_storage_test_case_data(line)
if not is_generated:
# In manual test data, only look at read tests.
function_name = test_case_data.split(':', 1)[0]
if 'read' not in function_name.split('_'):
continue
metadata = SimpleNamespace(
filename=filename,
line_number=line_number,
description=description
)
storage_tests[test_case_data] = metadata
@staticmethod
def _list_generated_test_data_files(git_worktree_path):
"""List the generated test data files."""
generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
# The checked-out revision is from before generate_psa_tests.py
# was moved to the framework submodule. Use the old location.
generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
output = subprocess.check_output(
[generate_psa_tests, '--list'],
cwd=git_worktree_path,
).decode('ascii')
return [line for line in output.split('\n') if line]
def _get_storage_format_tests(self, version, git_worktree_path):
"""Record the storage format tests for the specified git version.
The storage format tests are the test suite data files whose name
contains "storage_format".
The version must be checked out at git_worktree_path.
This function creates or updates the generated data files.
"""
# Existing test data files. This may be missing some automatically
# generated files if they haven't been generated yet.
storage_data_files = set(glob.glob(
'tests/suites/test_suite_*storage_format*.data'
))
# Discover and (re)generate automatically generated data files.
to_be_generated = set()
for filename in self._list_generated_test_data_files(git_worktree_path):
if 'storage_format' in filename:
storage_data_files.add(filename)
to_be_generated.add(filename)
generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
# The checked-out revision is from before generate_psa_tests.py
# was moved to the framework submodule. Use the old location.
generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
subprocess.check_call(
[generate_psa_tests] + sorted(to_be_generated),
cwd=git_worktree_path,
)
for test_file in sorted(storage_data_files):
self._read_storage_tests(git_worktree_path,
test_file,
test_file in to_be_generated,
version.storage_tests)
def _cleanup_worktree(self, git_worktree_path):
"""Remove the specified git worktree."""
shutil.rmtree(git_worktree_path)
submodule_output = subprocess.check_output(
[self.git_command, "submodule", "foreach", "--recursive",
f'git worktree remove "{git_worktree_path}/$displaypath"'],
cwd=self.repo_path,
stderr=subprocess.STDOUT
)
self.log.debug(submodule_output.decode("utf-8"))
worktree_output = subprocess.check_output(
[self.git_command, "worktree", "remove", git_worktree_path],
cwd=self.repo_path,
stderr=subprocess.STDOUT
)
self.log.debug(worktree_output.decode("utf-8"))
def _get_abi_dump_for_ref(self, version):
"""Generate the interface information for the specified git revision."""
git_worktree_path = self._get_clean_worktree_for_git_revision(version)
self._update_git_submodules(git_worktree_path, version)
if self.check_abi:
self._build_shared_libraries(git_worktree_path, version)
self._get_abi_dumps_from_shared_libraries(version)
if self.check_storage_tests:
self._get_storage_format_tests(version, git_worktree_path)
self._cleanup_worktree(git_worktree_path)
def _remove_children_with_tag(self, parent, tag):
children = parent.getchildren()
for child in children:
if child.tag == tag:
parent.remove(child)
else:
self._remove_children_with_tag(child, tag)
def _remove_extra_detail_from_report(self, report_root):
for tag in ['test_info', 'test_results', 'problem_summary',
'added_symbols', 'affected']:
self._remove_children_with_tag(report_root, tag)
for report in report_root:
for problems in report.getchildren()[:]:
if not problems.getchildren():
report.remove(problems)
def _abi_compliance_command(self, mbed_module, output_path):
"""Build the command to run to analyze the library mbed_module.
The report will be placed in output_path."""
abi_compliance_command = [
"abi-compliance-checker",
"-l", mbed_module,
"-old", self.old_version.abi_dumps[mbed_module],
"-new", self.new_version.abi_dumps[mbed_module],
"-strict",
"-report-path", output_path,
]
if self.skip_file:
abi_compliance_command += ["-skip-symbols", self.skip_file,
"-skip-types", self.skip_file]
if self.brief:
abi_compliance_command += ["-report-format", "xml",
"-stdout"]
return abi_compliance_command
def _is_library_compatible(self, mbed_module, compatibility_report):
"""Test if the library mbed_module has remained compatible.
Append a message regarding compatibility to compatibility_report."""
output_path = os.path.join(
self.report_dir, "{}-{}-{}.html".format(
mbed_module, self.old_version.revision,
self.new_version.revision
)
)
try:
subprocess.check_output(
self._abi_compliance_command(mbed_module, output_path),
stderr=subprocess.STDOUT
)
except subprocess.CalledProcessError as err:
if err.returncode != 1:
raise err
if self.brief:
self.log.info(
"Compatibility issues found for {}".format(mbed_module)
)
report_root = ET.fromstring(err.output.decode("utf-8"))
self._remove_extra_detail_from_report(report_root)
self.log.info(ET.tostring(report_root).decode("utf-8"))
else:
self.can_remove_report_dir = False
compatibility_report.append(
"Compatibility issues found for {}, "
"for details see {}".format(mbed_module, output_path)
)
return False
compatibility_report.append(
"No compatibility issues for {}".format(mbed_module)
)
if not (self.keep_all_reports or self.brief):
os.remove(output_path)
return True
@staticmethod
def _is_storage_format_compatible(old_tests, new_tests,
compatibility_report):
"""Check whether all tests present in old_tests are also in new_tests.
Append a message regarding compatibility to compatibility_report.
"""
missing = frozenset(old_tests.keys()).difference(new_tests.keys())
for test_data in sorted(missing):
metadata = old_tests[test_data]
compatibility_report.append(
'Test case from {} line {} "{}" has disappeared: {}'.format(
metadata.filename, metadata.line_number,
metadata.description, test_data
)
)
compatibility_report.append(
'FAIL: {}/{} storage format test cases have changed or disappeared.'.format(
len(missing), len(old_tests)
) if missing else
'PASS: All {} storage format test cases are preserved.'.format(
len(old_tests)
)
)
compatibility_report.append(
'Info: number of storage format tests cases: {} -> {}.'.format(
len(old_tests), len(new_tests)
)
)
return not missing
def get_abi_compatibility_report(self):
"""Generate a report of the differences between the reference ABI
and the new ABI. ABI dumps from self.old_version and self.new_version
must be available."""
compatibility_report = ["Checking evolution from {} to {}".format(
self._pretty_revision(self.old_version),
self._pretty_revision(self.new_version)
)]
compliance_return_code = 0
if self.check_abi:
shared_modules = list(set(self.old_version.modules.keys()) &
set(self.new_version.modules.keys()))
for mbed_module in shared_modules:
if not self._is_library_compatible(mbed_module,
compatibility_report):
compliance_return_code = 1
if self.check_storage_tests:
if not self._is_storage_format_compatible(
self.old_version.storage_tests,
self.new_version.storage_tests,
compatibility_report):
compliance_return_code = 1
for version in [self.old_version, self.new_version]:
for mbed_module, mbed_module_dump in version.abi_dumps.items():
os.remove(mbed_module_dump)
if self.can_remove_report_dir:
os.rmdir(self.report_dir)
self.log.info("\n".join(compatibility_report))
return compliance_return_code
def check_for_abi_changes(self):
"""Generate a report of ABI differences
between self.old_rev and self.new_rev."""
build_tree.check_repo_path()
if self.check_api or self.check_abi:
self.check_abi_tools_are_installed()
self._get_abi_dump_for_ref(self.old_version)
self._get_abi_dump_for_ref(self.new_version)
return self.get_abi_compatibility_report()
def run_main():
try:
parser = argparse.ArgumentParser(
description=__doc__
)
parser.add_argument(
"-v", "--verbose", action="store_true",
help="set verbosity level",
)
parser.add_argument(
"-r", "--report-dir", type=str, default="reports",
help="directory where reports are stored, default is reports",
)
parser.add_argument(
"-k", "--keep-all-reports", action="store_true",
help="keep all reports, even if there are no compatibility issues",
)
parser.add_argument(
"-o", "--old-rev", type=str, help="revision for old version.",
required=True,
)
parser.add_argument(
"-or", "--old-repo", type=str, help="repository for old version."
)
parser.add_argument(
"-oc", "--old-crypto-rev", type=str,
help="revision for old crypto submodule."
)
parser.add_argument(
"-ocr", "--old-crypto-repo", type=str,
help="repository for old crypto submodule."
)
parser.add_argument(
"-n", "--new-rev", type=str, help="revision for new version",
required=True,
)
parser.add_argument(
"-nr", "--new-repo", type=str, help="repository for new version."
)
parser.add_argument(
"-nc", "--new-crypto-rev", type=str,
help="revision for new crypto version"
)
parser.add_argument(
"-ncr", "--new-crypto-repo", type=str,
help="repository for new crypto submodule."
)
parser.add_argument(
"-s", "--skip-file", type=str,
help=("path to file containing symbols and types to skip "
"(typically \"-s identifiers\" after running "
"\"tests/scripts/list-identifiers.sh --internal\")")
)
parser.add_argument(
"--check-abi",
action='store_true', default=True,
help="Perform ABI comparison (default: yes)"
)
parser.add_argument("--no-check-abi", action='store_false', dest='check_abi')
parser.add_argument(
"--check-api",
action='store_true', default=True,
help="Perform API comparison (default: yes)"
)
parser.add_argument("--no-check-api", action='store_false', dest='check_api')
parser.add_argument(
"--check-storage",
action='store_true', default=True,
help="Perform storage tests comparison (default: yes)"
)
parser.add_argument("--no-check-storage", action='store_false', dest='check_storage')
parser.add_argument(
"-b", "--brief", action="store_true",
help="output only the list of issues to stdout, instead of a full report",
)
abi_args = parser.parse_args()
if os.path.isfile(abi_args.report_dir):
print("Error: {} is not a directory".format(abi_args.report_dir))
parser.exit()
old_version = SimpleNamespace(
version="old",
repository=abi_args.old_repo,
revision=abi_args.old_rev,
commit=None,
crypto_repository=abi_args.old_crypto_repo,
crypto_revision=abi_args.old_crypto_rev,
abi_dumps={},
storage_tests={},
modules={}
)
new_version = SimpleNamespace(
version="new",
repository=abi_args.new_repo,
revision=abi_args.new_rev,
commit=None,
crypto_repository=abi_args.new_crypto_repo,
crypto_revision=abi_args.new_crypto_rev,
abi_dumps={},
storage_tests={},
modules={}
)
configuration = SimpleNamespace(
verbose=abi_args.verbose,
report_dir=abi_args.report_dir,
keep_all_reports=abi_args.keep_all_reports,
brief=abi_args.brief,
check_abi=abi_args.check_abi,
check_api=abi_args.check_api,
check_storage=abi_args.check_storage,
skip_file=abi_args.skip_file
)
abi_check = AbiChecker(old_version, new_version, configuration)
return_code = abi_check.check_for_abi_changes()
sys.exit(return_code)
except Exception: # pylint: disable=broad-except
# Print the backtrace and exit explicitly so as to exit with
# status 2, not 1.
traceback.print_exc()
sys.exit(2)
from mbedtls_framework import interface_checks
if __name__ == "__main__":
run_main()
interface_checks.run_main()

View File

@@ -6,12 +6,9 @@ Generate miscellaneous TLS test cases relating to the handshake.
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import sys
import framework_scripts_path # pylint: disable=unused-import
from mbedtls_framework import tls_handshake_tests
if __name__ == '__main__':
sys.argv[1:1] = ["--no-tls12-client-hello-defragmentation-support"]
tls_handshake_tests.main()

View File

@@ -660,6 +660,7 @@ setup_arguments()
# with OpenSSL 1.0.1h, -www, -WWW and -HTTP break DTLS handshakes
if is_dtls "$MODE"; then
O_SERVER_ARGS="$O_SERVER_ARGS"
M_SERVER_ARGS="$M_SERVER_ARGS read_timeout=1000"
else
O_SERVER_ARGS="$O_SERVER_ARGS -www"
fi

View File

@@ -43,7 +43,7 @@ class CoverageTask(outcome_analysis.CoverageTask):
'DTLS cookie: enabled, IPv6',
# Disabled due to OpenSSL bug.
# https://github.com/openssl/openssl/issues/18887
'DTLS fragmenting: 3d, openssl client, DTLS 1.2',
'DTLS fragmenting: 3d, MTU=512, openssl client, DTLS 1.2',
# We don't run ssl-opt.sh with Valgrind on the CI because
# it's extremely slow. We don't intend to change this.
'DTLS fragmenting: proxy MTU: auto-reduction (with valgrind)',

View File

@@ -385,6 +385,7 @@ component_test_tls1_2_ccm_psk_psa () {
component_test_tls1_2_ccm_psk_dtls_legacy () {
msg "build: configs/config-ccm-psk-dtls1_2.h"
cp configs/config-ccm-psk-dtls1_2.h "$CONFIG_H"
scripts/config.py set MBEDTLS_HAVE_TIME
# test-ref-configs works by overwriting mbedtls_config.h; this makes cmake
# want to re-generate generated files that depend on it, quite correctly.
# However this doesn't work as the generation script expects a specific
@@ -419,6 +420,7 @@ component_test_tls1_2_ccm_psk_dtls_psa () {
cp configs/config-ccm-psk-dtls1_2.h "$CONFIG_H"
scripts/config.py set MBEDTLS_PSA_CRYPTO_C
scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
scripts/config.py set MBEDTLS_HAVE_TIME
# test-ref-configs works by overwriting mbedtls_config.h; this makes cmake
# want to re-generate generated files that depend on it, quite correctly.
# However this doesn't work as the generation script expects a specific

View File

@@ -10942,7 +10942,7 @@ run_test "DTLS reassembly: more fragmentation (gnutls server)" \
requires_gnutls
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: more fragmentation, nbio (gnutls server)" \
"$G_SRV -u --mtu 128" \
"$G_SRV -u --mtu 109" \
"$P_CLI dtls=1 nbio=2 debug_level=2" \
0 \
-c "found fragmented DTLS handshake message" \
@@ -10954,7 +10954,7 @@ requires_gnutls
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: fragmentation, renego (gnutls server)" \
"$G_SRV -u --mtu 256" \
"$G_SRV -u --mtu 241" \
"$P_CLI debug_level=3 dtls=1 renegotiation=1 renegotiate=1" \
0 \
-c "found fragmented DTLS handshake message" \
@@ -10982,6 +10982,52 @@ run_test "DTLS reassembly: fragmentation, nbio, renego (gnutls server)" \
-C "error" \
-s "Extra-header:"
requires_gnutls
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: no fragmentation (gnutls client)" \
"$P_SRV debug_level=2 dtls=1" \
"$G_NEXT_CLI -u --mtu 2048 --insecure 127.0.0.1" \
0 \
-S "found fragmented DTLS handshake message" \
-S "error"
requires_gnutls
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: some fragmentation (gnutls client)" \
"$P_SRV debug_level=2 dtls=1 auth_mode=required" \
"$G_NEXT_CLI -u --mtu 211 --insecure 127.0.0.1 --x509certfile $DATA_FILES_PATH/server5.crt --x509keyfile $DATA_FILES_PATH/server5.key" \
0 \
-s "found fragmented DTLS handshake message" \
-s "Certificate handshake message has been buffered and reassembled" \
-S "error"
# Set the MTU to 128 bytes. The minimum size of a DTLS 1.2 record
# containing a ClientHello handshake message is 69 bytes, without any cookie,
# ciphersuite, or extension. With an MTU of 128 bytes, the ClientHello handshake
# message is therefore very likely to be fragmented, regardless of the
# GnuTLS client version. For example, the ClientHello sent by the GnuTLS 3.7.2
# client is 206 bytes in this test.
requires_gnutls
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: more fragmentation (gnutls client)" \
"$P_SRV debug_level=2 dtls=1" \
"$G_NEXT_CLI -u --mtu 103 --insecure 127.0.0.1" \
0 \
-s "ClientHello handshake message has been buffered and reassembled" \
-S "error"
requires_gnutls
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: more fragmentation, nbio (gnutls client)" \
"$P_SRV debug_level=2 dtls=1 nbio=2" \
"$G_NEXT_CLI -u --mtu 103 --insecure 127.0.0.1" \
0 \
-s "ClientHello handshake message has been buffered and reassembled" \
-S "error"
# No fragmentation and renegotiation tests with GnuTLS client as the feature
# does not work properly.
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: no fragmentation (openssl server)" \
"$O_SRV -dtls -mtu 2048" \
@@ -11005,13 +11051,45 @@ run_test "DTLS reassembly: fragmentation (openssl server)" \
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: fragmentation, nbio (openssl server)" \
"$O_SRV -dtls -mtu 256" \
"$O_SRV -dtls -mtu 273" \
"$P_CLI dtls=1 nbio=2 debug_level=2" \
0 \
-c "found fragmented DTLS handshake message" \
-c "Certificate handshake message has been buffered and reassembled" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: no fragmentation (openssl client)" \
"$P_SRV debug_level=2 dtls=1 auth_mode=required" \
"$O_NEXT_CLI -dtls -mtu 2048 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
0 \
-S "found fragmented DTLS handshake message" \
-S "error"
# Minimum possible MTU for OpenSSL server: 256 bytes.
# We expect the client Certificate handshake message to be fragmented and
# verify that this is the case. With OpenSSL 3.0.13, the ClientHello handshake
# message is 224 bytes and also fragmented. However, it may not hold across
# OpenSSL version updates. Therefore, we do not verify that the ClientHello is
# reassembled by the server.
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: some fragmentation (openssl client)" \
"$P_SRV debug_level=2 dtls=1 auth_mode=required" \
"$O_NEXT_CLI -dtls -mtu 256 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
0 \
-s "found fragmented DTLS handshake message" \
-s "Certificate handshake message has been buffered and reassembled" \
-S "error"
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS reassembly: fragmentation, nbio (openssl client)" \
"$P_SRV debug_level=2 dtls=1 auth_mode=required nbio=2" \
"$O_NEXT_CLI -dtls -mtu 269 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
0 \
-s "found fragmented DTLS handshake message" \
-s "Certificate handshake message has been buffered and reassembled" \
-S "error"
# Tests for sending fragmented handshake messages with DTLS
#
# Use client auth when we need the client to send large messages,
@@ -11253,20 +11331,20 @@ run_test "DTLS fragmenting: server (MTU)" \
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
requires_max_content_len 1038
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS fragmenting: both (MTU=1024)" \
-p "$P_PXY mtu=1024" \
run_test "DTLS fragmenting: both (MTU=1038)" \
-p "$P_PXY mtu=1038" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
hs_timeout=2500-60000 \
mtu=1024" \
mtu=1038" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
hs_timeout=2500-60000 \
mtu=1024" \
mtu=1038" \
0 \
-s "found fragmented DTLS handshake message" \
-c "found fragmented DTLS handshake message" \
@@ -11276,25 +11354,105 @@ run_test "DTLS fragmenting: both (MTU=1024)" \
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_hash_alg SHA_256
requires_max_content_len 2048
run_test "DTLS fragmenting: both (MTU=512)" \
-p "$P_PXY mtu=512" \
requires_max_content_len 509
run_test "DTLS fragmenting: both (MTU=509)" \
-p "$P_PXY mtu=509" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
hs_timeout=2500-60000 \
mtu=512" \
mtu=509" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
hs_timeout=2500-60000 \
mtu=512" \
mtu=509" \
0 \
-s "found fragmented DTLS handshake message" \
-c "found fragmented DTLS handshake message" \
-C "error"
# Depending on the ciphersuite selected to encrypt the application data, the
# maximum application data payload per record may be small with an MTU of 128.
# For example, with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384, this maximum is
# 35 bytes. We therefore reduce the size of the client request and the server
# response in this test and the two following tests.
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_max_content_len 128
run_test "DTLS fragmenting: both (MTU=128)" \
-p "$P_PXY mtu=128" \
"$P_SRV dtls=1 debug_level=5 auth_mode=required \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
response_size=8 \
hs_timeout=2500-60000 \
mtu=128" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=8 \
hs_timeout=2500-60000 \
mtu=128" \
0 \
-s "found fragmented DTLS handshake message" \
-s "fragmenting Certificate handshake message" \
-c "found fragmented DTLS handshake message" \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-c "fragmenting CertificateVerify handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_max_content_len 2048
run_test "DTLS fragmenting: both (MTU=107)" \
-p "$P_PXY mtu=107" \
"$P_SRV dtls=1 debug_level=5 auth_mode=required \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
response_size=8 \
hs_timeout=2500-60000 \
mtu=107" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=8 \
hs_timeout=2500-60000 \
mtu=107" \
0 \
-s "found fragmented DTLS handshake message" \
-s "fragmenting Certificate handshake message" \
-c "found fragmented DTLS handshake message" \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-c "fragmenting CertificateVerify handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_max_content_len 2048
run_test "DTLS fragmenting: both (MTU=133)" \
-p "$P_PXY mtu=133" \
"$P_SRV dtls=1 debug_level=5 auth_mode=required \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
response_size=8 \
hs_timeout=2500-60000 \
mtu=133" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=8 \
hs_timeout=2500-60000 \
mtu=133" \
0 \
-s "found fragmented DTLS handshake message" \
-s "fragmenting Certificate handshake message" \
-c "found fragmented DTLS handshake message" \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-c "fragmenting CertificateVerify handshake message" \
-C "error"
# Test for automatic MTU reduction on repeated resend.
# Forcing ciphersuite for this test to fit the MTU of 508 with full config.
# The ratio of max/min timeout should ideally equal 4 to accept two
@@ -11348,7 +11506,7 @@ run_test "DTLS fragmenting: proxy MTU: auto-reduction (with valgrind)" \
not_with_valgrind # spurious autoreduction due to timeout
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
requires_max_content_len 1024
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS fragmenting: proxy MTU, simple handshake (MTU=1024)" \
-p "$P_PXY mtu=1024" \
@@ -11375,7 +11533,7 @@ run_test "DTLS fragmenting: proxy MTU, simple handshake (MTU=1024)" \
not_with_valgrind # spurious autoreduction due to timeout
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
requires_max_content_len 512
run_test "DTLS fragmenting: proxy MTU, simple handshake (MTU=512)" \
-p "$P_PXY mtu=512" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11398,7 +11556,7 @@ run_test "DTLS fragmenting: proxy MTU, simple handshake (MTU=512)" \
not_with_valgrind # spurious autoreduction due to timeout
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
requires_max_content_len 1024
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS fragmenting: proxy MTU, simple handshake, nbio (MTU=1024)" \
-p "$P_PXY mtu=1024" \
@@ -11422,7 +11580,7 @@ run_test "DTLS fragmenting: proxy MTU, simple handshake, nbio (MTU=1024)" \
not_with_valgrind # spurious autoreduction due to timeout
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
requires_max_content_len 512
run_test "DTLS fragmenting: proxy MTU, simple handshake, nbio (MTU=512)" \
-p "$P_PXY mtu=512" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11455,7 +11613,7 @@ run_test "DTLS fragmenting: proxy MTU, simple handshake, nbio (MTU=512)" \
not_with_valgrind # spurious autoreduction due to timeout
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
requires_max_content_len 1450
run_test "DTLS fragmenting: proxy MTU, resumed handshake" \
-p "$P_PXY mtu=1450" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11482,7 +11640,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_hash_alg SHA_256
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
requires_max_content_len 2048
requires_max_content_len 512
run_test "DTLS fragmenting: proxy MTU, ChachaPoly renego" \
-p "$P_PXY mtu=512" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11511,7 +11669,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_hash_alg SHA_256
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
requires_max_content_len 2048
requires_max_content_len 512
run_test "DTLS fragmenting: proxy MTU, AES-GCM renego" \
-p "$P_PXY mtu=512" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11540,7 +11698,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_hash_alg SHA_256
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
requires_max_content_len 2048
requires_max_content_len 1024
run_test "DTLS fragmenting: proxy MTU, AES-CCM renego" \
-p "$P_PXY mtu=1024" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11570,7 +11728,7 @@ requires_config_enabled MBEDTLS_RSA_C
requires_hash_alg SHA_256
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC
requires_max_content_len 2048
requires_max_content_len 1024
run_test "DTLS fragmenting: proxy MTU, AES-CBC EtM renego" \
-p "$P_PXY mtu=1024" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11599,7 +11757,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_hash_alg SHA_256
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
requires_max_content_len 2048
requires_max_content_len 1024
run_test "DTLS fragmenting: proxy MTU, AES-CBC non-EtM renego" \
-p "$P_PXY mtu=1024" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11625,7 +11783,7 @@ run_test "DTLS fragmenting: proxy MTU, AES-CBC non-EtM renego" \
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 2
requires_max_content_len 2048
requires_max_content_len 512
run_test "DTLS fragmenting: proxy MTU + 3d" \
-p "$P_PXY mtu=512 drop=8 delay=8 duplicate=8" \
"$P_SRV dgram_packing=0 dtls=1 debug_level=2 auth_mode=required \
@@ -11646,7 +11804,7 @@ run_test "DTLS fragmenting: proxy MTU + 3d" \
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 2
requires_max_content_len 2048
requires_max_content_len 512
run_test "DTLS fragmenting: proxy MTU + 3d, nbio" \
-p "$P_PXY mtu=512 drop=8 delay=8 duplicate=8" \
"$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11671,16 +11829,32 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_gnutls
requires_max_content_len 2048
run_test "DTLS fragmenting: gnutls server, DTLS 1.2" \
run_test "DTLS fragmenting: MTU=501, gnutls server, DTLS 1.2" \
"$G_SRV -u" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
mtu=512 force_version=dtls12" \
mtu=501 force_version=dtls12" \
0 \
-c "fragmenting Certificate handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_gnutls
requires_max_content_len 2048
run_test "DTLS fragmenting: MTU=110, gnutls server, DTLS 1.2" \
"$G_NEXT_SRV -u" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=35 \
mtu=110 force_version=dtls12" \
0 \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-C "error"
# We use --insecure for the GnuTLS client because it expects
# the hostname / IP it connects to to be the name used in the
# certificate obtained from the server. Here, however, it
@@ -11693,11 +11867,25 @@ requires_config_enabled MBEDTLS_RSA_C
requires_gnutls
requires_not_i686
requires_max_content_len 2048
run_test "DTLS fragmenting: gnutls client, DTLS 1.2" \
run_test "DTLS fragmenting: MTU=536, gnutls client, DTLS 1.2" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
mtu=512 force_version=dtls12" \
mtu=536 force_version=dtls12" \
"$G_CLI -u --insecure 127.0.0.1" \
0 \
-s "fragmenting Certificate handshake message"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_gnutls
requires_not_i686
requires_max_content_len 2048
run_test "DTLS fragmenting: MTU=149, gnutls client, DTLS 1.2" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
mtu=149 force_version=dtls12" \
"$G_CLI -u --insecure 127.0.0.1" \
0 \
-s "fragmenting Certificate handshake message"
@@ -11705,20 +11893,39 @@ run_test "DTLS fragmenting: gnutls client, DTLS 1.2" \
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
run_test "DTLS fragmenting: openssl server, DTLS 1.2" \
run_test "DTLS fragmenting: MTU=525, openssl server, DTLS 1.2" \
"$O_SRV -dtls1_2 -verify 10" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
mtu=512 force_version=dtls12" \
mtu=525 force_version=dtls12" \
0 \
-c "fragmenting Certificate handshake message" \
-C "error"
# Depending on the ciphersuite selected to encrypt the application data, the
# maximum application data payload per record may be small with an MTU of 128.
# For example, with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384, this maximum is
# 35 bytes. We therefore reduce the size of the client request in this test.
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
run_test "DTLS fragmenting: MTU=130, openssl server, DTLS 1.2" \
"$O_NEXT_SRV -dtls1_2 -verify 10" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=8 \
mtu=130 force_version=dtls12" \
0 \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-C "error"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
run_test "DTLS fragmenting: openssl client, DTLS 1.2" \
run_test "DTLS fragmenting: MTU=512, openssl client, DTLS 1.2" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
@@ -11727,6 +11934,18 @@ run_test "DTLS fragmenting: openssl client, DTLS 1.2" \
0 \
-s "fragmenting Certificate handshake message"
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
requires_max_content_len 2048
run_test "DTLS fragmenting: MTU=131, openssl client, DTLS 1.2" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
mtu=131 force_version=dtls12" \
"$O_CLI -dtls1_2" \
0 \
-s "fragmenting Certificate handshake message"
# interop tests for DTLS fragmentating with unreliable connection
#
# again we just want to test that the we fragment in a way that
@@ -11736,28 +11955,61 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 4
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, gnutls server, DTLS 1.2" \
run_test "DTLS fragmenting: 3d, MTU=434, gnutls server, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$G_NEXT_SRV -u" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
hs_timeout=250-60000 mtu=512 force_version=dtls12" \
hs_timeout=250-60000 mtu=434 force_version=dtls12" \
0 \
-c "fragmenting Certificate handshake message" \
-C "error"
requires_gnutls_next
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 6
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, MTU=103, gnutls server, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$G_NEXT_SRV -u" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=35 \
hs_timeout=250-60000 mtu=103 force_version=dtls12" \
0 \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-C "error"
requires_gnutls_next
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 4
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, gnutls client, DTLS 1.2" \
run_test "DTLS fragmenting: 3d, MTU=614, gnutls client, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
hs_timeout=250-60000 mtu=512 force_version=dtls12" \
hs_timeout=250-60000 mtu=614 force_version=dtls12" \
"$G_NEXT_CLI -u --insecure 127.0.0.1" \
0 \
-s "fragmenting Certificate handshake message"
requires_gnutls_next
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 4
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, MTU=116, gnutls client, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
key_file=$DATA_FILES_PATH/server7.key \
hs_timeout=250-60000 mtu=116 force_version=dtls12" \
"$G_NEXT_CLI -u --insecure 127.0.0.1" \
0 \
-s "fragmenting Certificate handshake message"
@@ -11769,17 +12021,39 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 4
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, openssl server, DTLS 1.2" \
run_test "DTLS fragmenting: 3d, MTU=541, openssl server, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$O_NEXT_SRV -dtls1_2 -verify 10" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
hs_timeout=250-60000 mtu=512 force_version=dtls12" \
hs_timeout=250-60000 mtu=541 force_version=dtls12" \
0 \
-c "fragmenting Certificate handshake message" \
-C "error"
# Depending on the ciphersuite selected to encrypt the application data, the
# maximum application data payload per record may be small with an MTU of 128.
# For example, with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384, this maximum is
# 35 bytes. We therefore reduce the size of the client request in this test.
requires_openssl_next
requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 4
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, MTU=108, openssl server, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$O_NEXT_SRV -dtls1_2 -verify 10" \
"$P_CLI dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
key_file=$DATA_FILES_PATH/server8.key \
request_size=8 \
hs_timeout=250-60000 mtu=108 force_version=dtls12" \
0 \
-c "fragmenting ClientHello handshake message" \
-c "fragmenting Certificate handshake message" \
-C "error"
## the test below will time out with certain seed.
## The cause is an openssl bug (https://github.com/openssl/openssl/issues/18887)
skip_next_test
@@ -11787,7 +12061,7 @@ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
requires_config_enabled MBEDTLS_RSA_C
client_needs_more_time 4
requires_max_content_len 2048
run_test "DTLS fragmenting: 3d, openssl client, DTLS 1.2" \
run_test "DTLS fragmenting: 3d, MTU=512, openssl client, DTLS 1.2" \
-p "$P_PXY drop=8 delay=8 duplicate=8" \
"$P_SRV dtls=1 debug_level=2 \
crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
@@ -12874,7 +13148,7 @@ not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, openssl server, fragmentation" \
-p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
"$O_NEXT_SRV -dtls1_2 -mtu 256" \
"$O_NEXT_SRV -dtls1_2 -mtu 277" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000 tickets=0" \
0 \
-c "HTTP/1.0 200 OK" \
@@ -12886,12 +13160,49 @@ not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, openssl server, fragmentation, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
"$O_NEXT_SRV -dtls1_2 -mtu 256" \
"$O_NEXT_SRV -dtls1_2 -mtu 268" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000 nbio=2 tickets=0" \
0 \
-c "HTTP/1.0 200 OK" \
-c "Certificate handshake message has been buffered and reassembled"
requires_openssl_next
client_needs_more_time 6
not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, openssl client" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$P_SRV dgram_packing=0 dtls=1 hs_timeout=500-60000 tickets=0" \
"$O_NEXT_CLI -dtls1_2 -mtu 2048" \
0 \
-s "HTTP/1.0 200 OK"
requires_openssl_next
client_needs_more_time 8
not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, openssl client, fragmentation" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$P_SRV debug_level=2 dgram_packing=0 auth_mode=required dtls=1 hs_timeout=500-60000 tickets=0" \
"$O_NEXT_CLI -dtls1_2 -mtu 260 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
0 \
-s "HTTP/1.0 200 OK" \
-s "found fragmented DTLS handshake message" \
-s "Certificate handshake message has been buffered and reassembled"
requires_openssl_next
client_needs_more_time 8
not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, openssl client, fragmentation, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$P_SRV debug_level=2 dgram_packing=0 auth_mode=required dtls=1 hs_timeout=500-60000 nbio=2 tickets=0" \
"$O_NEXT_CLI -dtls1_2 -mtu 259 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
0 \
-s "HTTP/1.0 200 OK" \
-s "found fragmented DTLS handshake message" \
-s "Certificate handshake message has been buffered and reassembled"
requires_gnutls
client_needs_more_time 6
not_with_valgrind # risk of non-mbedtls peer timing out
@@ -12910,7 +13221,7 @@ not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, gnutls server, fragmentation" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$G_NEXT_SRV -u --mtu 512" \
"$G_NEXT_SRV -u --mtu 499" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000" \
0 \
-s "Extra-header:" \
@@ -12923,13 +13234,54 @@ not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$G_NEXT_SRV -u --mtu 512" \
"$G_NEXT_SRV -u --mtu 528" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000 nbio=2" \
0 \
-s "Extra-header:" \
-c "Extra-header:" \
-c "Certificate handshake message has been buffered and reassembled"
requires_gnutls
client_needs_more_time 6
not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, gnutls client" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$P_SRV dgram_packing=0 dtls=1" \
"$G_NEXT_CLI -u --mtu 2048 --insecure 127.0.0.1" \
0 \
-s "HTTP/1.0 200 OK"
# Set the MTU to 131 bytes. The ClientHello is not guaranteed to be surely
# fragmented but it is very likely. For example, the ClientHello sent by the
# GnuTLS 3.7.2 client is 206 bytes in this test. We expect ClientHello
# fragmentation to remain the case across GnuTLS version updates. Avoid using a
# smaller MTU, as the smaller the MTU, the more likely the handshake is to fail
# in this very unreliable connection emulation.
requires_gnutls
client_needs_more_time 8
not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, gnutls client, fragmentation" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$P_SRV dgram_packing=0 dtls=1 debug_level=2" \
"$G_NEXT_CLI -u --mtu 131 --insecure 127.0.0.1" \
0 \
-s "HTTP/1.0 200 OK" \
-s "ClientHello handshake message has been buffered and reassembled"
requires_gnutls
client_needs_more_time 8
not_with_valgrind # risk of non-mbedtls peer timing out
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "DTLS proxy: 3d, gnutls client, fragmentation, nbio=2" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$P_SRV dgram_packing=0 dtls=1 debug_level=2 nbio=2" \
"$G_NEXT_CLI -u --mtu 135 --insecure 127.0.0.1" \
0 \
-s "HTTP/1.0 200 OK" \
-s "ClientHello handshake message has been buffered and reassembled"
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
run_test "export keys functionality" \
"$P_SRV eap_tls=1 debug_level=3" \
@@ -14853,7 +15205,6 @@ run_test "Handshake defragmentation on server: len=256, client-initiated rene
-s "Consume: waiting for more handshake fragments 256/" \
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "Handshake defragmentation on server: len=128, client-initiated renegotiation" \
"$P_SRV debug_level=4 exchanges=2 renegotiation=1 auth_mode=required" \
@@ -14870,7 +15221,6 @@ run_test "Handshake defragmentation on server: len=128, client-initiated rene
-s "Consume: waiting for more handshake fragments 128/" \
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "Handshake defragmentation on server: len=4, client-initiated renegotiation" \
"$P_SRV debug_level=4 exchanges=2 renegotiation=1 auth_mode=required" \
@@ -14887,7 +15237,6 @@ run_test "Handshake defragmentation on server: len=4, client-initiated renego
-s "Consume: waiting for more handshake fragments 4/" \
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "Handshake defragmentation on server: len=4, client-initiated server-rejected renegotiation" \
"$P_SRV debug_level=4 exchanges=2 renegotiation=0 auth_mode=required" \

View File

@@ -12,3 +12,19 @@ pass:
Config: ECC: Montgomery curves only
depends_on:!MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED:MBEDTLS_ECP_MONTGOMERY_ENABLED
pass:
Config: PK export keys on the stack (PK is ECC-only) (USE_PSA)
depends_on:PK_EXPORT_KEYS_ON_THE_STACK:MBEDTLS_USE_PSA_CRYPTO
pass:
Config: PK export keys on the stack (PK is ECC-only) (!USE_PSA)
depends_on:PK_EXPORT_KEYS_ON_THE_STACK:!MBEDTLS_USE_PSA_CRYPTO
pass:
Config: PK export keys on the heap (PK is not ECC-only) (USE_PSA)
depends_on:!PK_EXPORT_KEYS_ON_THE_STACK:MBEDTLS_USE_PSA_CRYPTO
pass:
Config: PK export keys on the heap (PK is not ECC-only) (!USE_PSA)
depends_on:!PK_EXPORT_KEYS_ON_THE_STACK:!MBEDTLS_USE_PSA_CRYPTO
pass:

View File

@@ -1,5 +1,5 @@
/* BEGIN_HEADER */
#include "pk_internal.h"
/* END_HEADER */
/* BEGIN_CASE */

View File

@@ -3543,3 +3543,6 @@ send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:0
Negative Test: Server using sig_alg not offered by the client - ECDSA with SHA512
depends_on:MBEDTLS_CAN_HANDLE_ECDSA_TEST_KEY:MBEDTLS_CAN_HANDLE_ECDSA_CLIENT_TEST_KEY:MBEDTLS_MD_CAN_SHA512
send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER
Default verify_result before doing a handshake
verify_result_without_handshake

View File

@@ -6272,3 +6272,47 @@ exit:
PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
void verify_result_without_handshake(void)
{
/* Test the result of verification before we perform a handshake. */
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
PSA_INIT();
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT), 0);
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
mbedtls_ssl_conf_ca_chain(&conf, NULL, NULL);
mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
TEST_EQUAL(mbedtls_ssl_setup(&ssl, &conf), 0);
uint32_t verify_result = mbedtls_ssl_get_verify_result(&ssl);
TEST_EQUAL(verify_result, 0xFFFFFFFF);
/* Set the verify result manually and check that session_free resets it. */
/* Set the verify result to 0. */
ssl.session_negotiate->verify_result = 0;
mbedtls_ssl_session_free(ssl.session_negotiate);
verify_result = mbedtls_ssl_get_verify_result(&ssl);
TEST_EQUAL(verify_result, 0xFFFFFFFF);
exit:
mbedtls_ssl_config_free(&conf);
mbedtls_ssl_free(&ssl);
PSA_DONE();
}
/* END_CASE */